diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2021-02-18 14:17:35 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2021-03-04 09:14:04 -0800 |
commit | 224c638f781b0bf15cf1dc5f59124f8be04753cd (patch) | |
tree | f97c048550c2e6be6ff7405258b4762c8d940526 | |
parent | 3875575ab622d8fa41cfcf3c1f7f08dfc9e755f4 (diff) |
QProcess/Unix: use a common function to find the target executable
This harmonizes the execution between start() and startDetached(). Both
did QStandardDirs::findExecutable(), but duplicated code. However, only
start() supported launching .app bundles on Mac.
[ChangeLog][QtCore][QProcess] startDetached() now supports launching
.app executable bundles on macOS / iOS systems, like start() already
did.
Change-Id: Ic90d8429a0eb4837971dfffd1664f776b2c0edfd
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 87 |
1 files changed, 39 insertions, 48 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 5529161e8d..f1c8039b6b 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -367,6 +367,41 @@ void QProcessPrivate::commitChannels() } } +static QString resolveExecutable(const QString &program) +{ +#ifdef Q_OS_DARWIN + // allow invoking of .app bundles on the Mac. + QFileInfo fileInfo(program); + if (program.endsWith(QLatin1String(".app")) && fileInfo.isDir()) { + QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, + QCFString(fileInfo.absoluteFilePath()), + kCFURLPOSIXPathStyle, true); + { + // CFBundle is not reentrant, since CFBundleCreate might return a reference + // to a cached bundle object. Protect the bundle calls with a mutex lock. + static QBasicMutex cfbundleMutex; + const auto locker = qt_scoped_lock(cfbundleMutex); + QCFType<CFBundleRef> bundle = CFBundleCreate(0, url); + // 'executableURL' can be either relative or absolute ... + QCFType<CFURLRef> executableURL = CFBundleCopyExecutableURL(bundle); + // not to depend on caching - make sure it's always absolute. + url = CFURLCopyAbsoluteURL(executableURL); + } + if (url) { + const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + return QString::fromCFString(str); + } + } +#endif + + if (!program.contains(QLatin1Char('/'))) { + QString exeFilePath = QStandardPaths::findExecutable(program); + if (!exeFilePath.isEmpty()) + return exeFilePath; + } + return program; +} + static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Map &environment, int *envc) { *envc = 0; @@ -425,44 +460,9 @@ void QProcessPrivate::startProcess() char **argv = new char *[arguments.count() + 2]; argv[arguments.count() + 1] = nullptr; - // Encode the program name. - QByteArray encodedProgramName = QFile::encodeName(program); -#ifdef Q_OS_MAC - // allow invoking of .app bundles on the Mac. - QFileInfo fileInfo(program); - if (encodedProgramName.endsWith(".app") && fileInfo.isDir()) { - QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, - QCFString(fileInfo.absoluteFilePath()), - kCFURLPOSIXPathStyle, true); - { - // CFBundle is not reentrant, since CFBundleCreate might return a reference - // to a cached bundle object. Protect the bundle calls with a mutex lock. - static QBasicMutex cfbundleMutex; - const auto locker = qt_scoped_lock(cfbundleMutex); - QCFType<CFBundleRef> bundle = CFBundleCreate(0, url); - // 'executableURL' can be either relative or absolute ... - QCFType<CFURLRef> executableURL = CFBundleCopyExecutableURL(bundle); - // not to depend on caching - make sure it's always absolute. - url = CFURLCopyAbsoluteURL(executableURL); - } - if (url) { - const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - encodedProgramName += (QDir::separator() + QDir(program).relativeFilePath(QString::fromCFString(str))).toUtf8(); - } - } -#endif - - // Add the program name to the argument list. - argv[0] = nullptr; - if (!program.contains(QLatin1Char('/'))) { - const QString &exeFilePath = QStandardPaths::findExecutable(program); - if (!exeFilePath.isEmpty()) { - const QByteArray &tmp = QFile::encodeName(exeFilePath); - argv[0] = ::strdup(tmp.constData()); - } - } - if (!argv[0]) - argv[0] = ::strdup(encodedProgramName.constData()); + // Resolve the program name + QString resolvedProgram = resolveExecutable(program); + argv[0] = ::strdup(QFile::encodeName(resolvedProgram).constData()); // Add every argument to the list for (int i = 0; i < arguments.count(); ++i) @@ -943,6 +943,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) char **argv = new char *[arguments.size() + 2]; for (int i = 0; i < arguments.size(); ++i) argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData()); + argv[0] = ::strdup(QFile::encodeName(resolveExecutable(program)).constData()); argv[arguments.size() + 1] = nullptr; // Duplicate the environment. @@ -952,16 +953,6 @@ bool QProcessPrivate::startDetached(qint64 *pid) envp = _q_dupEnvironment(environment.d.constData()->vars, &envc); } - QByteArray tmp; - if (!program.contains(QLatin1Char('/'))) { - const QString &exeFilePath = QStandardPaths::findExecutable(program); - if (!exeFilePath.isEmpty()) - tmp = QFile::encodeName(exeFilePath); - } - if (tmp.isEmpty()) - tmp = QFile::encodeName(program); - argv[0] = tmp.data(); - if (envp) qt_safe_execve(argv[0], argv, envp); else |