diff --git a/src/engine/src/builtins.c b/src/engine/src/builtins.c index 2170af40e..39c8a7821 100644 --- a/src/engine/src/builtins.c +++ b/src/engine/src/builtins.c @@ -381,6 +381,11 @@ void load_builtins() builtin_precious, 0, args ); } + { + char * args [] = { 0 }; + bind_builtin( "SELF_PATH", builtin_self_path, 0, args ); + } + /* Initialize builtin modules. */ init_set(); init_path(); @@ -1707,6 +1712,22 @@ LIST *builtin_precious( PARSE *parse, FRAME *frame ) return L0; } +LIST *builtin_self_path( PARSE *parse, FRAME *frame ) +{ + extern char *saved_argv0; + char *p = executable_path (saved_argv0); + if (p) + { + LIST* result = list_new (0, newstr (p)); + free(p); + return result; + } + else + { + return L0; + } +} + #ifdef HAVE_PYTHON diff --git a/src/engine/src/builtins.h b/src/engine/src/builtins.h index 8ecc6616a..9ed3e6dc9 100644 --- a/src/engine/src/builtins.h +++ b/src/engine/src/builtins.h @@ -60,6 +60,7 @@ LIST *builtin_md5( PARSE *parse, FRAME *frame ); LIST *builtin_file_open( PARSE *parse, FRAME *frame ); LIST *builtin_pad( PARSE *parse, FRAME *frame ); LIST *builtin_precious( PARSE *parse, FRAME *frame ); +LIST *builtin_self_path( PARSE *parse, FRAME *frame ); void backtrace( FRAME *frame ); extern int last_update_now_status; diff --git a/src/engine/src/jam.c b/src/engine/src/jam.c index 2d06316e6..1ef741f83 100644 --- a/src/engine/src/jam.c +++ b/src/engine/src/jam.c @@ -210,6 +210,8 @@ int anyhow = 0; extern PyObject * bjam_backtrace ( PyObject * self, PyObject * args ); #endif +char *saved_argv0; + int main( int argc, char * * argv, char * * arg_environ ) { int n; @@ -221,6 +223,8 @@ int main( int argc, char * * argv, char * * arg_environ ) char * * arg_v = argv; char const * progname = argv[0]; + saved_argv0 = argv[0]; + BJAM_MEM_INIT(); # ifdef OS_MAC @@ -562,3 +566,58 @@ int main( int argc, char * * argv, char * * arg_environ ) return status ? EXITBAD : EXITOK; } + +#if defined(_WIN32) +#include +char *executable_path(char *arvg0) { + char buf[1024]; + DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf)); + if (ret == 0 || ret == sizeof(buf)) return NULL; + return strdup (buf); +} +#elif defined(__APPLE__) // Not tested +#include +char *executable_path(char *arvg0) { + char buf[1024]; + uint32_t size = sizeof(buf); + int ret = _NSGetExecutablePath(buf, &size); + if (ret != 0) return NULL; + return strdup(buf); +} +#elif defined(sun) || defined(__sun) // Not tested +#include + +char *executable_path(char *arvg0) { + return stdrup(getexecname()); +} +#elif defined(__FreeBSD__) +#include +char *executable_path(char *arvg0) { + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char buf[1024]; + size_t size = sizeof(buf); + sysctl(mib, 4, buf, &size, NULL, 0); + if (size == 0 || size == sizeof(buf)) return NULL; + return strndup(buf, size); +} +#elif defined(__linux__) +#include +char *executable_path(char *arvg0) { + char buf[1024]; + ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf)); + if (ret == 0 || ret == sizeof(buf)) return NULL; + return strndup(buf, ret); +} +#else +char *executable_path(char *arvg0) { + // If argv0 is absolute path, assume it's the right + // absolute path. + if (argv0[0] == "/") + return strdup(argv0); + return NULL; +} +#endif diff --git a/src/engine/src/pathsys.h b/src/engine/src/pathsys.h index 49d2bf8e2..737758105 100644 --- a/src/engine/src/pathsys.h +++ b/src/engine/src/pathsys.h @@ -79,4 +79,13 @@ const char * path_tmpnam( void ); const char * path_tmpfile( void ); #endif +/** Give the first argument to 'main', return a full path to + our executable. Returns null in the unlikely case it + cannot be determined. Caller is responsible for freeing + the string. + + Implemented in jam.c +*/ +char * executable_path (char *argv0); + #endif