argv[0]
引用导致当前进程加载的 shell 命令。getcwd()
返回当前工作目录。根据该信息,我可以构造程序的二进制可执行文件的绝对路径吗?如果程序cd
自首次加载以来已经完成了 a,我不希望它起作用。
答案1
在编程语言解释器的内部,我使用以下代码来获取自身路径。
它有针对 Linux、Windows(包括 Cygwin)、Mac 和 Solaris 的特殊代码:
#if __APPLE__
#include <mach-o/dyld.h>
#endif
#if __linux__
static val get_self_path(void)
{
char self[PATH_MAX] = { 0 };
int nchar = readlink("/proc/self/exe", self, sizeof self);
if (nchar < 0 || nchar >= convert(int, sizeof self))
return nil;
return string_utf8(self);
}
#elif HAVE_WINDOWS_H
static val get_self_path(void)
{
wchar_t self[MAX_PATH] = { 0 };
DWORD nchar;
SetLastError(0);
nchar = GetModuleFileNameW(NULL, self, MAX_PATH);
if (nchar == 0 ||
(nchar == MAX_PATH &&
((GetLastError() == ERROR_INSUFFICIENT_BUFFER) ||
(self[MAX_PATH - 1] != 0))))
return nil;
return string(self);
}
#elif __APPLE__
static val get_self_path(void)
{
char self[PATH_MAX] = { 0 };
uint32_t size = sizeof self;
if (_NSGetExecutablePath(self, &size) != 0)
return nil;
return string_utf8(self);
}
#elif HAVE_GETEXECNAME
static val get_self_path(void)
{
val execname = string_utf8(getexecname());
if (car(execname) == chr('/'))
return execname;
return scat3(getcwd_wrap(), chr('/'), execname);
}
#else
static val get_self_path(void)
{
char self[PATH_MAX];
if (argv[0] && realpath(argv[0], self))
return string_utf8(self);
return lit(HARD_INSTALLATION_PATH);
}
#endif
类型val
、符号和nil
函数是解释器内部的。只是一个抽象铸造的宏。当然,还需要一些头文件,等等。string
string_utf8
convert
readlink
realpath
该getexecname
函数是 Solaris 上的东西。似乎出于某种原因,我在处理相对路径的情况下进行了编码,在这种情况下,必须将当前目录粘贴到其上才能获得绝对路径。
后备策略是,如果argv[0]
frommain
可用,则调用realpath
它并运行它。如果argv[0]
不可用,那么我们依赖于来自变量的硬编码安装路径Makefile
。例如,如果程序安装为/usr/bin/foo
,则Makefile
配方会将其作为 插入到编译器命令行中-DHARD_INSTALLATION_PATH=/usr/bin/foo
。当然,只有当程序安装在其构建路径时,这才是正确的。
答案2
在 Linux 上,您可以使用符号链接/proc/self/exe
$ ls -l /proc/self/exe
lrwxrwxrwx 1 rudi users 0 2016-10-18 16:20 /proc/self/exe -> /usr/bin/ls