summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2021-02-18 14:17:35 -0800
committerThiago Macieira <thiago.macieira@intel.com>2021-03-04 09:14:04 -0800
commit224c638f781b0bf15cf1dc5f59124f8be04753cd (patch)
treef97c048550c2e6be6ff7405258b4762c8d940526
parent3875575ab622d8fa41cfcf3c1f7f08dfc9e755f4 (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.cpp87
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