在我看来,Linux使用/proc/self/exe很容易但是我想知道是否有一种方便的方法来找到当前应用程序的目录在C/ c++与跨平台接口。我见过一些项目胡乱摆弄argv[0],但它似乎并不完全可靠。
如果你必须支持,比如说,Mac OS X,它没有/proc/,你会怎么做?使用#ifdefs来隔离平台特定的代码(例如NSBundle)?或者尝试从argv[0], $ path和诸如此类的东西中推断可执行文件的路径,冒着在边缘情况下发现错误的风险?
在我看来,Linux使用/proc/self/exe很容易但是我想知道是否有一种方便的方法来找到当前应用程序的目录在C/ c++与跨平台接口。我见过一些项目胡乱摆弄argv[0],但它似乎并不完全可靠。
如果你必须支持,比如说,Mac OS X,它没有/proc/,你会怎么做?使用#ifdefs来隔离平台特定的代码(例如NSBundle)?或者尝试从argv[0], $ path和诸如此类的东西中推断可执行文件的路径,冒着在边缘情况下发现错误的风险?
当前回答
依我看,没有这种办法。还有一个不明确的地方:如果同一个可执行文件有多个硬链接指向它,您希望得到什么作为答案?(硬链接实际上并不“指向”,它们是同一个文件,只是位于文件系统层次结构中的另一个位置。)
一旦execve()成功执行了一个新的二进制文件,所有关于原始程序参数的信息都将丢失。
其他回答
根据QNX Neutrino版本的不同,有不同的方法来查找用于启动运行进程的可执行文件的完整路径和名称。我将进程标识符表示为<PID>。试试下面的方法:
If the file /proc/self/exefile exists, then its contents are the requested information. If the file /proc/<PID>/exefile exists, then its contents are the requested information. If the file /proc/self/as exists, then: open() the file. Allocate a buffer of, at least, sizeof(procfs_debuginfo) + _POSIX_PATH_MAX. Give that buffer as input to devctl(fd, DCMD_PROC_MAPDEBUG_BASE,.... Cast the buffer to a procfs_debuginfo*. The requested information is at the path field of the procfs_debuginfo structure. Warning: For some reason, sometimes, QNX omits the first slash / of the file path. Prepend that / when needed. Clean up (close the file, free the buffer, etc.). Try the procedure in 3. with the file /proc/<PID>/as. Try dladdr(dlsym(RTLD_DEFAULT, "main"), &dlinfo) where dlinfo is a Dl_info structure whose dli_fname might contain the requested information.
我希望这能有所帮助。
当然,这并不适用于所有项目。 尽管如此,QCoreApplication::applicationFilePath()在6年的c++ /Qt开发中从未让我失望过。
当然,在尝试使用它之前,应该彻底阅读文档:
警告:在Linux上,此函数将尝试从 /proc文件系统。如果失败,则假定argv[0]包含 可执行文件的绝对文件名。这个函数也假设 应用程序没有更改当前目录。
老实说,我认为#ifdef和其他类似的解决方案根本不应该在现代代码中使用。
我相信更小的跨平台库也存在。让他们把所有特定于平台的东西封装在里面。
一些特定于操作系统的接口:
Mac OS X: _NSGetExecutablePath() (man 3 dyld) Linux: readlink /proc/self/exe Solaris: getexecname () sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1 readlink /proc/curproc/file (FreeBSD默认没有procfs) NetBSD: readlink /proc/curproc/exe DragonFly BSD: readlink /proc/curproc/file Windows: GetModuleFileName() with hModule = NULL
也有第三方库可以用来获取这些信息,比如在prideout的回答中提到的whereami,或者如果你使用Qt,评论中提到的QCoreApplication::applicationFilePath()。
可移植的(但不太可靠)方法是使用argv[0]。尽管调用程序可以将它设置为任何东西,但按照惯例,它要么被设置为可执行文件的路径名,要么被设置为使用$ path找到的名称。
一些shell,包括bash和ksh,在执行可执行文件之前将环境变量“_”设置为可执行文件的完整路径。在这种情况下,您可以使用getenv("_")来获取它。然而,这是不可靠的,因为不是所有的shell都这样做,并且它可以被设置为任何东西,或者是在执行程序之前没有更改它的父进程遗留下来的。
如果您正在编写GPLed代码并使用GNU autotools,那么在许多操作系统(包括Windows和macOS)上处理细节的可移植方法是gnulib的reloctable -prog模块。
如果你曾经支持过,比如说,麦克 OS X没有/proc/ 你会这么做吗?使用#ifdefs来 隔离特定于平台的代码 (例如NSBundle)?
是的,使用#ifdefs隔离特定于平台的代码是实现这一点的常规方法。
另一种方法是有一个干净的#ifdef-less头,其中包含函数声明,并将实现放在特定于平台的源文件中。
例如,查看POCO(可移植组件)c++库如何为它们的Environment类做类似的事情。