From 8669710c0f9909f8b3b825e3d0693b98563979fd Mon Sep 17 00:00:00 2001 From: rofl0r Date: Wed, 27 Apr 2022 16:17:04 +0000 Subject: [PATCH 1/6] build: allow empty prefix there was some concern that this will break windows' way of doing file lookups relatively from the binary, rather than via hardcoded locations, but so far each occurence adding e.g. "CA65_INC" to the pathsearch is already shielded with an #ifndef _WIN32. addressing #1726 --- doc/Makefile | 1 - libsrc/Makefile | 1 - samples/Makefile | 1 - src/Makefile | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index bb8f551ad..bfdf0cce3 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -46,7 +46,6 @@ clean: $(RM) -r ../html ../info install: - $(if $(PREFIX),,$(error variable "PREFIX" must be set)) ifeq ($(wildcard ../html),../html) $(INSTALL) -d $(DESTDIR)$(htmldir) $(INSTALL) -m0644 ../html/*.* $(DESTDIR)$(htmldir) diff --git a/libsrc/Makefile b/libsrc/Makefile index 177314bdf..2018de801 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -96,7 +96,6 @@ INSTALL = install define INSTALL_recipe -$(if $(PREFIX),,$(error variable "PREFIX" must be set)) $(INSTALL) -d $(DESTDIR)$(datadir)/$(dir) $(INSTALL) -m0644 ../$(dir)/*.* $(DESTDIR)$(datadir)/$(dir) diff --git a/samples/Makefile b/samples/Makefile index 9732cfac7..01ad6f983 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -525,7 +525,6 @@ INSTALL = install samplesdir = $(PREFIX)/share/cc65/samples install: - $(if $(PREFIX),,$(error variable "PREFIX" must be set)) $(INSTALL) -d $(DESTDIR)$(samplesdir) $(INSTALL) -d $(DESTDIR)$(samplesdir)/geos $(INSTALL) -d $(DESTDIR)$(samplesdir)/tutorial diff --git a/src/Makefile b/src/Makefile index 75b92394e..8356d0001 100644 --- a/src/Makefile +++ b/src/Makefile @@ -26,7 +26,7 @@ PROGS = ar65 \ .SUFFIXES: bindir := $(PREFIX)/bin -datadir := $(if $(PREFIX),$(PREFIX)/share/cc65,$(abspath ..)) +datadir := $(PREFIX)/share/cc65 CA65_INC = $(datadir)/asminc CC65_INC = $(datadir)/include @@ -111,7 +111,6 @@ $(RM) /usr/local/bin/$(prog) endef # UNAVAIL_recipe install: - $(if $(PREFIX),,$(error variable "PREFIX" must be set)) $(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) ../bin/* $(DESTDIR)$(bindir) From b32c12dd831a85d9d15b57dde64e83fcf3513f15 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Wed, 27 Apr 2022 17:33:41 +0000 Subject: [PATCH 2/6] implement AddSubSearchPathFromWinBin() counterpart for unix this looks up paths relative to the binary used to start the specific application. --- src/common/searchpath.c | 138 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 12 deletions(-) diff --git a/src/common/searchpath.c b/src/common/searchpath.c index 70237a1c9..ac507d924 100644 --- a/src/common/searchpath.c +++ b/src/common/searchpath.c @@ -44,6 +44,12 @@ #else /* Anyone else */ # include +# include +# include +# ifndef PATH_MAX +# define PATH_MAX 4096 +# endif +# include "cmdline.h" #endif /* common */ @@ -157,18 +163,127 @@ void AddSubSearchPathFromEnv (SearchPaths* P, const char* EnvVar, const char* Su SB_Done (&Dir); } +#ifdef _WIN32 +#define PATHSEP "\\" +#undef PATH_MAX +#define PATH_MAX _MAX_PATH +#else +#define PATHSEP "/" + +/* + on POSIX-compatible operating system, a binary can be started in + 3 distinct ways: + + 1) using absolute path; in which case argv[0] starts with '/' + 2) using relative path; in which case argv[0] contains '/', but + does not start with it. e.g.: ./ca65 ; bin/cc65 + 3) using PATH environment variable, which is a colon-separated + list of directories which will be searched for a command + name used unprefixed. see execlp() and execvp() in man 3p exec: + +> The argument file is used to construct a pathname that identifies the new +> process image file. If the file argument contains a character, +> the file argument shall be used as the pathname for this file. +> Otherwise, the path prefix for this file is obtained by a search of the +> directories passed as the environment variable PATH (see the Base +> Definitions volume of POSIX.1*2008, Chapter 8, Environment Variables). +> If this environment variable is not present, the results of the search +> are implementation-defined. + +*/ + + + +static int SearchPathBin(const char* bin, char* buf, size_t buflen) +/* search colon-separated list of paths in PATH environment variable +** for the full path of argv[0]. +** returns 1 if successfull, in which case buf will contain the full path. +** bin = binary name (from argv[0]), buf = work buffer, buflen = sizeof buf +*/ +{ + char* p = getenv ("PATH"); + char* o; + size_t l; + + if (!p) { + return 0; + } + for (;;) { + o = buf; + l = buflen; + while (l && *p && *p != ':') { + *(o++) = *(p++); + l--; + } + snprintf (o, l, "/%s", bin); + if (access (buf, X_OK) == 0) { + return 1; + } + if (*p == ':') { + p++; + } else if (!p) { + break; + } + } + return 0; +} + + + +static char* MyDirname(char* in) +/* returns the dirname() part of a filename. +** the passed string is modified in place, then returned. +*/ +{ + char* p = strrchr (in, '/'); + + if (p) { + *p = 0; + } + return in; +} + + + +static char* GetProgPath(char* pathbuf, char* a0) +/* search for the full path of the binary using the argv[0] parameter +** passed to int main(), according to the description above. +** if the binary was started using a relative path, realpath(3p) will +** turn the relative path into an absolute path with pwd resolved, and +** gratuitous path components such as "./" or ".." removed. +** +** argument "pathbuf" is a work buffer of size PATH_MAX, +** "a0" the original argv[0]. +** returns pathbuf with the full path of the binary, minus the binary +** name itself. +*/ +{ + if (a0[0] == '/') { + strcpy (pathbuf, a0); + } else if (a0[0] == '.' || strrchr (a0, '/')) { + /* realpath returns the work buffer passed to it, so checking the + return value is superfluous. gcc11 warns anyway. */ + if (realpath (a0, pathbuf)) {} + } else { + SearchPathBin (a0, pathbuf, PATH_MAX); + } + return MyDirname(pathbuf); +} + +#endif + void AddSubSearchPathFromWinBin (SearchPaths* P, const char* SubDir) { /* Windows only: ** Add a search path from the running binary, adding a subdirectory to ** the parent directory of the directory containing the binary. */ -#if defined(_WIN32) - - char Dir[_MAX_PATH]; char* Ptr; + char Dir[PATH_MAX]; + +#if defined(_WIN32) if (GetModuleFileName (NULL, Dir, _MAX_PATH) == 0) { return; @@ -181,12 +296,18 @@ void AddSubSearchPathFromWinBin (SearchPaths* P, const char* SubDir) } *Ptr = '\0'; +#else + + GetProgPath(Dir, ArgVec[0]); + +#endif + /* Check for 'bin' directory */ - Ptr = strrchr (Dir, '\\'); + Ptr = strrchr (Dir, PATHSEP[0]); if (Ptr == 0) { return; } - if (strcmp (Ptr++, "\\bin") != 0) { + if (strcmp (Ptr++, PATHSEP "bin") != 0) { return; } @@ -195,13 +316,6 @@ void AddSubSearchPathFromWinBin (SearchPaths* P, const char* SubDir) /* Add the search path */ AddSearchPath (P, Dir); - -#else - - (void) P; - (void) SubDir; - -#endif } From d78672a4b437f894d6ec44a6bef087237310e767 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Wed, 27 Apr 2022 21:11:01 +0000 Subject: [PATCH 3/6] rename AddSubSearchPathFromWinBin to AddSubSearchPathFromBin --- src/ca65/incpath.c | 2 +- src/cc65/incpath.c | 2 +- src/cl65/main.c | 2 +- src/common/searchpath.c | 2 +- src/common/searchpath.h | 5 ++--- src/ld65/filepath.c | 6 +++--- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/ca65/incpath.c b/src/ca65/incpath.c index 42e54b2da..8ea67df6f 100644 --- a/src/ca65/incpath.c +++ b/src/ca65/incpath.c @@ -80,5 +80,5 @@ void FinishIncludePaths (void) #endif /* Add paths relative to the parent directory of the Windows binary. */ - AddSubSearchPathFromWinBin (IncSearchPath, "asminc"); + AddSubSearchPathFromBin (IncSearchPath, "asminc"); } diff --git a/src/cc65/incpath.c b/src/cc65/incpath.c index d32614cf9..85f6e070b 100644 --- a/src/cc65/incpath.c +++ b/src/cc65/incpath.c @@ -81,5 +81,5 @@ void FinishIncludePaths (void) #endif /* Add paths relative to the parent directory of the Windows binary. */ - AddSubSearchPathFromWinBin (SysIncSearchPath, "include"); + AddSubSearchPathFromBin (SysIncSearchPath, "include"); } diff --git a/src/cl65/main.c b/src/cl65/main.c index 701355904..5d84fb625 100644 --- a/src/cl65/main.c +++ b/src/cl65/main.c @@ -1218,7 +1218,7 @@ static void OptPrintTargetPath (const char* Opt attribute ((unused)), #if defined(CL65_TGT) && !defined(_WIN32) AddSearchPath (TargetPaths, CL65_TGT); #endif - AddSubSearchPathFromWinBin (TargetPaths, "target"); + AddSubSearchPathFromBin (TargetPaths, "target"); TargetPath = GetSearchPath (TargetPaths, 0); while (*TargetPath) { diff --git a/src/common/searchpath.c b/src/common/searchpath.c index ac507d924..f1ee0b6e2 100644 --- a/src/common/searchpath.c +++ b/src/common/searchpath.c @@ -274,7 +274,7 @@ static char* GetProgPath(char* pathbuf, char* a0) #endif -void AddSubSearchPathFromWinBin (SearchPaths* P, const char* SubDir) +void AddSubSearchPathFromBin (SearchPaths* P, const char* SubDir) { /* Windows only: ** Add a search path from the running binary, adding a subdirectory to diff --git a/src/common/searchpath.h b/src/common/searchpath.h index f078c0799..371388d38 100644 --- a/src/common/searchpath.h +++ b/src/common/searchpath.h @@ -75,9 +75,8 @@ void AddSubSearchPathFromEnv (SearchPaths* P, const char* EnvVar, const char* Su ** the environment variable value. */ -void AddSubSearchPathFromWinBin (SearchPaths* P, const char* SubDir); -/* Windows only: -** Add a search path from the running binary, adding a subdirectory to +void AddSubSearchPathFromBin (SearchPaths* P, const char* SubDir); +/* Add a search path from the running binary, adding a subdirectory to ** the parent directory of the directory containing the binary. */ diff --git a/src/ld65/filepath.c b/src/ld65/filepath.c index f722ad34b..1ceb2333e 100644 --- a/src/ld65/filepath.c +++ b/src/ld65/filepath.c @@ -99,7 +99,7 @@ void InitSearchPaths (void) #endif /* Add paths relative to the parent directory of the Windows binary. */ - AddSubSearchPathFromWinBin (LibDefaultPath, "lib"); - AddSubSearchPathFromWinBin (ObjDefaultPath, "lib"); - AddSubSearchPathFromWinBin (CfgDefaultPath, "cfg"); + AddSubSearchPathFromBin (LibDefaultPath, "lib"); + AddSubSearchPathFromBin (ObjDefaultPath, "lib"); + AddSubSearchPathFromBin (CfgDefaultPath, "cfg"); } From 74f92564c396464bad44cb94881bd9c0ac525f48 Mon Sep 17 00:00:00 2001 From: Bob Andrews Date: Sat, 30 Apr 2022 15:01:58 +0200 Subject: [PATCH 4/6] Try reading from /proc/self first on linux, this is needed to make the edgy "make avail" work --- src/common/searchpath.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/common/searchpath.c b/src/common/searchpath.c index f1ee0b6e2..ebf14106f 100644 --- a/src/common/searchpath.c +++ b/src/common/searchpath.c @@ -296,10 +296,23 @@ void AddSubSearchPathFromBin (SearchPaths* P, const char* SubDir) } *Ptr = '\0'; +#elif defined(__linux__) + + /* reading from proc will return the real location, excluding symlinked + pathes - which is needed for certain edgy cases */ + if (readlink("/proc/self/exe", Dir, sizeof(Dir) - 1) < 0) { + GetProgPath(Dir, ArgVec[0]); + } else { + /* Remove binary name */ + Ptr = strrchr (Dir, PATHSEP[0]); + if (Ptr == 0) { + return; + } + *Ptr = '\0'; + } + #else - GetProgPath(Dir, ArgVec[0]); - #endif /* Check for 'bin' directory */ From 20dd6fd8724597d02923440afb81f189a0eae2a5 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Mon, 2 May 2022 08:22:21 +0000 Subject: [PATCH 5/6] change GetProgPath() to return full & resolved binary path GetProgPath() now resolves the path derived from argv[0] always via realpath(3p) to its real location in the filesystem, and returns the path including binary name, effectively making it work like windows' GetModuleFileName(), so we can re-use the existing code to strip the trailing binary name. since symlinks are now always resolved, we no longer need the special case code for linux to use /proc/self/exe for this purpose. --- src/common/searchpath.c | 73 ++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 49 deletions(-) diff --git a/src/common/searchpath.c b/src/common/searchpath.c index ebf14106f..fc23f47cb 100644 --- a/src/common/searchpath.c +++ b/src/common/searchpath.c @@ -232,44 +232,32 @@ static int SearchPathBin(const char* bin, char* buf, size_t buflen) -static char* MyDirname(char* in) -/* returns the dirname() part of a filename. -** the passed string is modified in place, then returned. -*/ -{ - char* p = strrchr (in, '/'); - - if (p) { - *p = 0; - } - return in; -} - - - static char* GetProgPath(char* pathbuf, char* a0) /* search for the full path of the binary using the argv[0] parameter ** passed to int main(), according to the description above. -** if the binary was started using a relative path, realpath(3p) will -** turn the relative path into an absolute path with pwd resolved, and -** gratuitous path components such as "./" or ".." removed. +** +** the binary name will be passed to realpath(3p) to have all symlinks +** resolved and gratuitous path components like "../" removed. ** ** argument "pathbuf" is a work buffer of size PATH_MAX, ** "a0" the original argv[0]. -** returns pathbuf with the full path of the binary, minus the binary -** name itself. +** returns pathbuf with the full path of the binary. */ { - if (a0[0] == '/') { - strcpy (pathbuf, a0); - } else if (a0[0] == '.' || strrchr (a0, '/')) { - /* realpath returns the work buffer passed to it, so checking the - return value is superfluous. gcc11 warns anyway. */ - if (realpath (a0, pathbuf)) {} - } else { - SearchPathBin (a0, pathbuf, PATH_MAX); + char tmp[PATH_MAX]; + + if (!strchr(a0, '/')) { + /* path doesn't contain directory separator, so it was looked up + via PATH environment variable */ + SearchPathBin (a0, tmp, PATH_MAX); + a0 = tmp; } - return MyDirname(pathbuf); + + /* realpath returns the work buffer passed to it, so checking the + return value is superfluous. gcc11 warns anyway. */ + if (realpath (a0, pathbuf)) {} + + return pathbuf; } #endif @@ -289,32 +277,19 @@ void AddSubSearchPathFromBin (SearchPaths* P, const char* SubDir) return; } +#else + + GetProgPath(Dir, ArgVec[0]); + +#endif + /* Remove binary name */ - Ptr = strrchr (Dir, '\\'); + Ptr = strrchr (Dir, PATHSEP[0]); if (Ptr == 0) { return; } *Ptr = '\0'; -#elif defined(__linux__) - - /* reading from proc will return the real location, excluding symlinked - pathes - which is needed for certain edgy cases */ - if (readlink("/proc/self/exe", Dir, sizeof(Dir) - 1) < 0) { - GetProgPath(Dir, ArgVec[0]); - } else { - /* Remove binary name */ - Ptr = strrchr (Dir, PATHSEP[0]); - if (Ptr == 0) { - return; - } - *Ptr = '\0'; - } - -#else - GetProgPath(Dir, ArgVec[0]); -#endif - /* Check for 'bin' directory */ Ptr = strrchr (Dir, PATHSEP[0]); if (Ptr == 0) { From 71cec58d86172aa86d3d1b578eea0d44a51a2f95 Mon Sep 17 00:00:00 2001 From: Bob Andrews Date: Thu, 5 May 2022 14:24:02 +0200 Subject: [PATCH 6/6] Adjust comments --- src/common/searchpath.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/common/searchpath.c b/src/common/searchpath.c index fc23f47cb..3628dab5c 100644 --- a/src/common/searchpath.c +++ b/src/common/searchpath.c @@ -263,11 +263,14 @@ static char* GetProgPath(char* pathbuf, char* a0) #endif void AddSubSearchPathFromBin (SearchPaths* P, const char* SubDir) -{ -/* Windows only: -** Add a search path from the running binary, adding a subdirectory to +/* Add a search path from the running binary, adding a subdirectory to ** the parent directory of the directory containing the binary. +** +** currently this will work on POSIX systems and on Windows. Should +** we run into build errors on systems that are neither, we must add +** another exception below. */ +{ char* Ptr; char Dir[PATH_MAX]; @@ -277,7 +280,7 @@ void AddSubSearchPathFromBin (SearchPaths* P, const char* SubDir) return; } -#else +#else /* POSIX */ GetProgPath(Dir, ArgVec[0]);