考虑一下:
那么,嵌入的Python如何找到这些文件呢?
需要知道可执行程序自身路径,可是,C、C++ 标准库没有提供这种东西
只能使用系统api了,而系统api用起来需要注意的问题似乎总是不少,
不过呢,Qt 中提供的这种功能,我们不妨看看它是如何做的:
QString QCoreApplication::applicationFilePath () [static] Returns the file path of the application executable. For example, if you have installed Qt in the /usr/local/qt directory, and you run the regexp example, this function will return "/usr/local/qt/examples/tools/regexp/regexp". Warning: On Linux, this function will try to get the path from the /proc file system. If that fails, it assumes that argv[0] contains the absolute file name of the executable. The function also assumes that the current directory has not been changed by the application.
恩,这儿已经介绍了 Linux 下是如何实现的了,不过还是看看源码吧,毕竟,
在离开Qt的C++下,需要我们自己写类似的代码。
如果是Linux,根据自身的pid,去查找 /proc/<pid>/exe
源码如下:
#if defined( Q_OS_UNIX ) # ifdef Q_OS_LINUX // Try looking for a /proc/<pid>/exe symlink first which points to // the absolute path of the executable QFileInfo pfi(QString::fromLatin1("/proc/%1/exe").arg(getpid())); if (pfi.exists() && pfi.isSymLink()) { d->cachedApplicationFilePath = pfi.canonicalFilePath(); return d->cachedApplicationFilePath; } # endif QString argv0 = QFile::decodeName(QByteArray(argv()[0])); QString absPath; if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) { /* If argv0 starts with a slash, it is already an absolute file path. */ absPath = argv0; } else if (argv0.contains(QLatin1Char('/'))) { /* If argv0 contains one or more slashes, it is a file path relative to the current directory. */ absPath = QDir::current().absoluteFilePath(argv0); } else { /* Otherwise, the file path has to be determined using the PATH environment variable. */ QByteArray pEnv = qgetenv("PATH"); QDir currentDir = QDir::current(); QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1Char(':')); for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) { if ((*p).isEmpty()) continue; QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0); QFileInfo candidate_fi(candidate); if (candidate_fi.exists() &&
Windows 提供了 GetModuleFileName 这种函数,所以操作就容易多了,不过Qt源码中也还是一大段哈。
// We do MAX_PATH + 2 here, and request with MAX_PATH + 1, so we can handle all paths // up to, and including MAX_PATH size perfectly fine with string termination, as well // as easily detect if the file path is indeed larger than MAX_PATH, in which case we // need to use the heap instead. This is a work-around, since contrary to what the // MSDN documentation states, GetModuleFileName sometimes doesn't set the // ERROR_INSUFFICIENT_BUFFER error number, and we thus cannot rely on this value if // GetModuleFileName(0, buffer, MAX_PATH) == MAX_PATH. // GetModuleFileName(0, buffer, MAX_PATH + 1) == MAX_PATH just means we hit the normal // file path limit, and we handle it normally, if the result is MAX_PATH + 1, we use // heap (even if the result _might_ be exactly MAX_PATH + 1, but that's ok). wchar_t buffer[MAX_PATH + 2]; DWORD v = GetModuleFileName(0, buffer, MAX_PATH + 1); buffer[MAX_PATH + 1] = 0; if (v == 0) return QString(); else if (v <= MAX_PATH) return QString::fromWCharArray(buffer); // MAX_PATH sized buffer wasn't large enough to contain the full path, use heap wchar_t *b = 0; int i = 1; size_t size; do { ++i; size = MAX_PATH * i; b = reinterpret_cast<wchar_t *>(realloc(b, (size + 1) * sizeof(wchar_t))); if (b) v = GetModuleFileName(NULL, b, size); } while (b && v == size); if (b) *(b + size) = 0; QString res = QString::fromWCharArray(b); free(b);