Linux 在没有 /proc/self/exe 的情况下查找当前可执行文件的路径
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1023306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Finding current executable's path without /proc/self/exe
提问by Uros Dimitrijevic
It seems to me that Linux has it easy with /proc/self/exe. But I'd like to know if there is a convenient way to find the current application's directory in C/C++ with cross-platform interfaces. I've seen some projects mucking around with argv[0], but it doesn't seem entirely reliable.
在我看来,Linux 使用 /proc/self/exe 很容易。但是我想知道是否有一种方便的方法可以在具有跨平台接口的 C/C++ 中找到当前应用程序的目录。我已经看到一些项目在使用 argv[0],但它似乎并不完全可靠。
If you ever had to support, say, Mac OS X, which doesn't have /proc/, what would you have done? Use #ifdefs to isolate the platform-specific code (NSBundle, for example)? Or try to deduce the executable's path from argv[0], $PATH and whatnot, risking finding bugs in edge cases?
如果你不得不支持,比如说,没有 /proc/ 的 Mac OS X,你会怎么做?使用 #ifdefs 来隔离特定于平台的代码(例如 NSBundle)?或者尝试从 argv[0]、$PATH 等推导出可执行文件的路径,冒着在边缘情况下发现错误的风险?
回答by zvrba
AFAIK, no such way. And there is also an ambuiguity: what would you like to get as the answer if the same executable has multiple hard-links "pointing" to it? (Hard-links don't actually "point", they arethe same file, just at another place in the FS hierarchy.) Once execve() successfully executes a new binary, all information about its arguments is lost.
AFAIK,没有这样的方式。还有一个歧义:如果同一个可执行文件有多个“指向”它的硬链接,您希望得到什么答案?(硬链接实际上并不“指向”,它们是同一个文件,只是在 FS 层次结构中的另一个位置。)一旦 execve() 成功执行一个新的二进制文件,有关其参数的所有信息都将丢失。
回答by bill
You can use argv[0] and analyze the PATH environment variable. Look at : A sample of a program that can find itself
您可以使用 argv[0] 并分析 PATH 环境变量。看:一个可以找到自己的程序示例
回答by StackedCrooked
If you ever had to support, say, Mac OS X, which doesn't have /proc/, what would you have done? Use #ifdefs to isolate the platform-specific code (NSBundle, for example)?
如果你不得不支持,比如说,没有 /proc/ 的 Mac OS X,你会怎么做?使用 #ifdefs 来隔离特定于平台的代码(例如 NSBundle)?
Yes isolating platform specific code with #ifdefs
is the conventional way this is done.
是的,隔离特定于平台的代码#ifdefs
是完成此操作的常规方式。
Another approach would be to have a have clean #ifdef
-less header wich contains function declarations and put the implementations in platform specific source files. For example, check out how Poco C++ library does something similar for their Environmentclass.
另一种方法是拥有一个干净的#ifdef
-less 头文件,其中包含函数声明并将实现放在特定于平台的源文件中。例如,查看 Poco C++ 库如何为其Environment类做类似的事情。
回答by mark4o
Some OS-specific interfaces:
一些特定于操作系统的接口:
- Mac OS X:
_NSGetExecutablePath()
(man 3 dyld) - Linux:
readlink /proc/self/exe
- Solaris:
getexecname()
- FreeBSD:
sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
- FreeBSD ifit has procfs:
readlink /proc/curproc/file
(FreeBSD doesn't have procfs by default) - NetBSD:
readlink /proc/curproc/exe
- DragonFly BSD:
readlink /proc/curproc/file
- Windows:
GetModuleFileName()
withhModule
=NULL
- Mac OS X的:
_NSGetExecutablePath()
(男子3使dyld) - Linux:
readlink /proc/self/exe
- 索拉里斯:
getexecname()
- FreeBSD:
sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
- 如果FreeBSD有 procfs:
readlink /proc/curproc/file
(FreeBSD 默认没有 procfs) - NetBSD:
readlink /proc/curproc/exe
- 蜻蜓BSD:
readlink /proc/curproc/file
- 视窗:
GetModuleFileName()
与hModule
=NULL
The portable (but less reliable) method is to use argv[0]
. Although it could be set to anything by the calling program, by convention it is set to either a path name of the executable or a name that was found using $PATH
.
便携(但不太可靠)的方法是使用argv[0]
. 尽管调用程序可以将其设置为任何内容,但按照惯例,它被设置为可执行文件的路径名或使用$PATH
.
Some shells, including bash and ksh, set the environment variable "_
"to the full path of the executable before it is executed. In that case you can use getenv("_")
to get it. However this is unreliable because not all shells do this, and it could be set to anything or be left over from a parent process which did not change it before executing your program.
一些 shell,包括 bash 和 ksh,在执行之前将环境变量“ _
”设置为可执行文件的完整路径。在这种情况下,您可以使用getenv("_")
它来获取它。然而,这是不可靠的,因为并非所有 shell 都这样做,并且它可以设置为任何内容,也可以从父进程中遗留下来,而父进程在执行您的程序之前没有对其进行更改。
回答by dacres
The absolute value path of a program is in the PWD of the envp of your main function, also there's a function in C called getenv, so there's that.
程序的绝对值路径在主函数的 envp 的 PWD 中,在 C 中有一个名为 getenv 的函数,所以就是这样。
回答by MichaelMoser
More portable way to get path name of executable image:
获取可执行映像路径名的更便携方法:
ps can give you the path of the executable, given you have the process id. Also ps is a POSIX utility so it should be portable
ps 可以为您提供可执行文件的路径,前提是您有进程 ID。另外 ps 是一个 POSIX 实用程序,因此它应该是可移植的
so if process id is 249297 then this command gives you the path name only.
所以如果进程 id 是 249297 那么这个命令只给你路径名。
ps -p 24297 -o comm --no-heading
Explanation of arguments
论据的解释
-p - selects given process
-p - 选择给定的进程
-o comm - displays the command name ( -o cmd selects the whole command line)
-o comm - 显示命令名称( -o cmd 选择整个命令行)
--no-heading - do not display a heading line, just the output.
--no-heading - 不显示标题行,只显示输出。
A C program can run this via popen.
AC 程序可以通过 popen 运行它。
回答by Dolda2000
An alternative on Linux to using either /proc/self/exe
or argv[0]
is using the information passed by the ELF interpreter, made available by glibc as such:
Linux 上的另一种方法是使用/proc/self/exe
或argv[0]
使用由 ELF 解释器传递的信息,由 glibc 提供,如下所示:
#include <stdio.h>
#include <sys/auxv.h>
int main(int argc, char **argv)
{
printf("%s\n", (char *)getauxval(AT_EXECFN));
return(0);
}
Note that getauxval
is a glibc extension, and to be robust you should check so that it doesn't return NULL
(indicating that the ELF interpreter hasn't provided the AT_EXECFN
parameter), but I don't think this is ever actually a problem on Linux.
请注意,这getauxval
是一个 glibc 扩展,为了健壮,您应该检查它以使其不返回NULL
(表明 ELF 解释器未提供AT_EXECFN
参数),但我认为这实际上不是 Linux 上的问题。
回答by prideout
Check out the whereamilibrary from Gregory Pakosz (which has just a single C file); it allows you to get the full path to the current executable on a variety of platforms. Currently, it's available as a repo on github here.
查看Gregory Pakosz的whereami库(只有一个 C 文件);它允许您在各种平台上获取当前可执行文件的完整路径。目前,它可以作为 github 上的 repo here。
回答by jtbr
Making this work reliably across platforms requires using #ifdef statements.
使这项工作跨平台可靠地工作需要使用 #ifdef 语句。
The below code finds the executable's path in Windows, Linux, MacOS, Solaris or FreeBSD (although FreeBSD is untested). It uses boost>=1.55.0 to simplify the code but it's easy enough to remove if you want. Just use defines like _MSC_VER and __linux as the OS and compiler require.
下面的代码在 Windows、Linux、MacOS、Solaris 或 FreeBSD 中查找可执行文件的路径(尽管 FreeBSD 未经测试)。它使用boost>=1.55.0 来简化代码,但如果您愿意,可以轻松删除。只需使用像 _MSC_VER 和 __linux 这样的定义作为操作系统和编译器的要求。
#include <string>
#include <boost/predef/os.h>
#if (BOOST_OS_WINDOWS)
# include <stdlib.h>
#elif (BOOST_OS_SOLARIS)
# include <stdlib.h>
# include <limits.h>
#elif (BOOST_OS_LINUX)
# include <unistd.h>
# include <limits.h>
#elif (BOOST_OS_MACOS)
# include <mach-o/dyld.h>
#elif (BOOST_OS_BSD_FREE)
# include <sys/types.h>
# include <sys/sysctl.h>
#endif
/*
* Returns the full path to the currently running executable,
* or an empty string in case of failure.
*/
std::string getExecutablePath() {
#if (BOOST_OS_WINDOWS)
char *exePath;
if (_get_pgmptr(&exePath) != 0)
exePath = "";
#elif (BOOST_OS_SOLARIS)
char exePath[PATH_MAX];
if (realpath(getexecname(), exePath) == NULL)
exePath[0] = 'return strlen(exePath)>0 ? boost::filesystem::path(exePath).remove_filename().make_preferred().string() : std::string();
';
#elif (BOOST_OS_LINUX)
char exePath[PATH_MAX];
ssize_t len = ::readlink("/proc/self/exe", exePath, sizeof(exePath));
if (len == -1 || len == sizeof(exePath))
len = 0;
exePath[len] = '##代码##';
#elif (BOOST_OS_MACOS)
char exePath[PATH_MAX];
uint32_t len = sizeof(exePath);
if (_NSGetExecutablePath(exePath, &len) != 0) {
exePath[0] = '##代码##'; // buffer too small (!)
} else {
// resolve symlinks, ., .. if possible
char *canonicalPath = realpath(exePath, NULL);
if (canonicalPath != NULL) {
strncpy(exePath,canonicalPath,len);
free(canonicalPath);
}
}
#elif (BOOST_OS_BSD_FREE)
char exePath[2048];
int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = -1;
size_t len = sizeof(exePath);
if (sysctl(mib, 4, exePath, &len, NULL, 0) != 0)
exePath[0] = '##代码##';
#endif
return std::string(exePath);
}
The above version returns full paths including the executable name. If instead you want the path without the executable name, #include boost/filesystem.hpp>
and change the return statement to:
上述版本返回包括可执行文件名称的完整路径。如果您想要没有可执行文件名称的路径,#include boost/filesystem.hpp>
请将 return 语句更改为:
回答by Dr. Koutheir Attouchi
Depending on the version of QNX Neutrino, there are different ways to find the full path and name of the executable file that was used to start the running process. I denote the process identifier as <PID>
. Try the following:
根据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 theprocfs_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)
wheredlinfo
is aDl_info
structure whosedli_fname
might contain the requested information.
- 如果文件
/proc/self/exefile
存在,那么它的内容就是请求的信息。 - 如果文件
/proc/<PID>/exefile
存在,那么它的内容就是请求的信息。 - 如果文件
/proc/self/as
存在,则:open()
文件。- 至少分配一个缓冲区
sizeof(procfs_debuginfo) + _POSIX_PATH_MAX
。 - 将该缓冲区作为
devctl(fd, DCMD_PROC_MAPDEBUG_BASE,...
. - 将缓冲区强制转换为
procfs_debuginfo*
. - 请求的信息位于结构
path
字段中procfs_debuginfo
。警告:出于某种原因,有时 QNX 会省略/
文件路径的第一个斜杠。/
在需要时预先设置。 - 清理(关闭文件、释放缓冲区等)。
- 尝试
3.
使用文件中的过程/proc/<PID>/as
。 - 试试
dladdr(dlsym(RTLD_DEFAULT, "main"), &dlinfo)
wheredlinfo
是一个可能包含请求信息的Dl_info
结构dli_fname
。
I hope this helps.
我希望这有帮助。