是否有一个exec
变体,将使用当前的应用程序目录来定位目标程序?
我正在使用C ++和Qt来实现“最后的沟渠”错误报告系统。 使用Google Breakpad ,我可以创build一个小型转储并直接执行到一个处理程序。 因为我的应用程序处于不稳定状态,所以我只想使用最小的依赖关系来分叉并启动一个单独的error handling过程。 错误报告应用程序将被部署在与应用程序可执行文件相同的目录中。
我很不熟悉fork
和exec
选项,并且没有find包含searchpath中当前应用程序目录的exec
选项。 这是我到目前为止:
static bool dumpCallback(const char* /*dump_path*/, const char* /*minidump_id*/, void* /*context*/, bool succeeded) { pid_t pid = fork(); if (pid == 0) { // This is what I would *like* to work. const char* error_reporter_path = "error_reporter"; // This works, but requires hard-coding the entire path, which seems lame, // and really isn't an option, given our deployment model. // // const char* error_reporter_path = "/path/to/app/error_reporter"; // This also works, but I don't like the dependency on QApplication at this // point, since the application is unstable. // // const char* error_reporter_path = // QString("%1/%2") // .arg(QApplication::applicationDirPath()) // .arg("error_reporter").toLatin1().constData(); execlp(error_reporter_path, error_reporter_path, (char *) 0); } return succeeded; }
有关使用fork
和exec
最佳实践的任何其他build议也将被赞赏; 这是我第一次使用它们的介绍。 我现在只关心Linux(Ubuntu,Fedora) 稍后,我将为其他操作系统的处理程序工作。
你所要求的其实很简单:
{ pid_t pid = fork(); if (pid == 0) { const char* error_reporter_path = "./error_reporter"; execl(error_reporter_path, error_reporter_path, (char *) 0); _exit(127); } else return pid != -1; }
但它没有做你想要的。 当前的工作目录与包含当前可执行文件的目录不一定是相同的 – 事实上,在几乎所有情况下,它都不会。
我建议你做的是使error_reporter_path
一个全局变量,并初始化它在main
开始,使用你的“选项2”代码
QString("%1/%2") .arg(QApplication::applicationDirPath()) .arg("error_reporter").toLatin1().constData();
QString
对象(不只是它的constData
)然后必须在程序的整个生命周期中生存,但这不应该是一个问题。 请注意,你应该转换为UTF-8,而不是Latin1(我猜QString
使用宽字符?)
我想你有两个选择:
getcwd()
的结果添加到可执行文件名称。 你应该在你的程序启动时建立你的助手可执行文件的路径,并保存在某个地方(全局变量或静态变量)。 如果你只需要在Linux上运行,你可以通过读/ proc / self / exe来获得你的可执行文件的位置。 像这样的东西:
// Locate helper binary next to the current binary. char self_path[PATH_MAX]; if (readlink("/proc/self/exe", self_path, sizeof(self_path) - 1) == -1) { exit(1); } string helper_path(self_path); size_t pos = helper_path.rfind('/'); if (pos == string::npos) { exit(1); } helper_path.erase(pos + 1); helper_path += "helper";
摘自一个完整的工作示例: http : //code.google.com/p/google-breakpad/source/browse/trunk/src/client/linux/minidump_writer/linux_dumper_unittest.cc#92
从来没有,在任何情况下添加“。” 到$ PATH!
如果您将getcwd()添加到可执行文件的名称(argv [0])中,则必须首先在main中执行此操作,然后才能更改当前工作目录。 然后,你必须考虑如何处理结果文件名中的符号链接。 甚至在这之后,你永远无法确定argv [0]是否被设置为用于执行程序的命令
备选案文3:
在可执行文件中对完整文件名进行硬编码,但使用配置脚本来设置文件名。 (你正在使用配置脚本,对吧?)
备选方案4;
不要调用exec。 分叉之后,您不必调用exec。 只要假装你刚刚进入“主”,并在你的错误报告完成后调用“退出”。