From e281855dfaacebe0b9127bb15f1e3a207af2544b Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 18 Oct 2024 14:03:33 +0200 Subject: [PATCH] Restore a clean system environment ... in case we are being run from another instance of Qt Creator. Remember which environment variables were amended to allow Qt Creator to start and reset them to their original values on start-up. This makes it possible to e.g. use Qt versions different from the ones that Qt Creator itself was built with. Change-Id: I6fc30823acb977f6cad4f67ff2e112c58792e30d Reviewed-by: hjk --- src/app/main.cpp | 27 +++++++++++++++++++ src/libs/utils/buildablehelperlibrary.cpp | 2 ++ src/libs/utils/environment.cpp | 26 ++++++++++++++++-- src/libs/utils/environment.h | 4 +++ .../desktoprunconfiguration.cpp | 16 ++++++++++- .../devicesupport/sshparameters.cpp | 7 +++-- .../qbsprojectmanager/qbsprofilemanager.cpp | 2 ++ src/plugins/qbsprojectmanager/qbssession.cpp | 1 + src/plugins/qbsprojectmanager/qbssettings.cpp | 13 +++++++++ src/plugins/qbsprojectmanager/qbssettings.h | 3 +++ src/plugins/qtsupport/baseqtversion.cpp | 2 -- 11 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 6e632917532..8bfb8bb6093 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -552,6 +552,33 @@ int main(int argc, char **argv) Options options = parseCommandLine(argc, argv); applicationDirPath(argv[0]); + // Remove entries from environment variables that were set up by Qt Creator to run + // the application (in this case, us). + // TODO: We should be able to merge at least some of the stuff below with similar intent + // into a more generalized version of this. + EnvironmentItems specialItems; + EnvironmentItems diff; + Environment::systemEnvironment().forEachEntry( + [&specialItems](const QString &name, const QString &value, bool enabled) { + if (enabled && name.startsWith("_QTC_")) + specialItems.emplaceBack(name, value, EnvironmentItem::SetEnabled); + }); + for (const EnvironmentItem &item : std::as_const(specialItems)) { + const QString varName = item.name.mid(5); + const FilePaths addedPaths + = Environment::pathListFromValue(item.value, HostOsInfo::hostOs()); + FilePaths allPaths = Environment::systemEnvironment().pathListValue(varName); + Utils::eraseOne(allPaths, [&addedPaths](const FilePath &p) { + return addedPaths.contains(p); + }); + diff.emplaceBack( + varName, + Environment::valueFromPathList(allPaths, HostOsInfo::hostOs()), + EnvironmentItem::SetEnabled); + diff.emplaceBack(item.name, "", EnvironmentItem::Unset); + } + Environment::modifySystemEnvironment(diff); + if (qEnvironmentVariableIsSet("QTC_DO_NOT_PROPAGATE_LD_PRELOAD")) Environment::modifySystemEnvironment({{"LD_PRELOAD", "", EnvironmentItem::Unset}}); diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index 6530113bb3e..3a678ffcda2 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -26,6 +26,7 @@ FilePath BuildableHelperLibrary::qtChooserToQmakePath(const FilePath &qtChooser) { const QString toolDir = QLatin1String("QTTOOLDIR=\""); Process proc; + proc.setEnvironment(qtChooser.deviceEnvironment()); proc.setCommand({qtChooser, {"-print-env"}}); proc.runBlocking(1s); if (proc.result() != ProcessResult::FinishedWithSuccess) @@ -107,6 +108,7 @@ QString BuildableHelperLibrary::qtVersionForQMake(const FilePath &qmakePath) return QString(); Process qmake; + qmake.setEnvironment(qmakePath.deviceEnvironment()); qmake.setCommand({qmakePath, {"--version"}}); qmake.runBlocking(5s); if (qmake.result() != ProcessResult::FinishedWithSuccess) { diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 76906b5d599..f9324634a12 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -208,6 +208,12 @@ Environment Environment::systemEnvironment() return *staticSystemEnvironment(); } +const Environment &Environment::originalSystemEnvironment() +{ + static const Environment env(QProcessEnvironment::systemEnvironment().toStringList()); + return env; +} + void Environment::setupEnglishOutput() { addItem(Item{std::in_place_index_t()}); @@ -238,8 +244,24 @@ FilePaths Environment::path() const FilePaths Environment::pathListValue(const QString &varName) const { - const QStringList pathComponents = expandedValueForKey(varName).split( - OsSpecificAspects::pathListSeparator(osType()), Qt::SkipEmptyParts); + return pathListFromValue(expandedValueForKey(varName), osType()); +} + +void Environment::setPathListValue(const QString &varName, const FilePaths &paths) +{ + set(varName, valueFromPathList(paths, osType())); +} + +QString Environment::valueFromPathList(const FilePaths &paths, OsType osType) +{ + return transform(paths, &FilePath::toUserOutput) + .join(OsSpecificAspects::pathListSeparator(osType)); +} + +FilePaths Environment::pathListFromValue(const QString &value, OsType osType) +{ + const QStringList pathComponents + = value.split(OsSpecificAspects::pathListSeparator(osType), Qt::SkipEmptyParts); return transform(pathComponents, &FilePath::fromUserInput); } diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 1b6b7d2c0e0..341facfab5b 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -72,6 +72,9 @@ public: FilePaths path() const; FilePaths pathListValue(const QString &varName) const; + void setPathListValue(const QString &varName, const FilePaths &paths); + static QString valueFromPathList(const FilePaths &paths, OsType osType); + static FilePaths pathListFromValue(const QString &value, OsType osType); QString expandedValueForKey(const QString &key) const; QString expandVariables(const QString &input) const; @@ -91,6 +94,7 @@ public: bool operator==(const Environment &other) const; static Environment systemEnvironment(); + static const Environment &originalSystemEnvironment(); static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!! static void setSystemEnvironment(const Environment &environment); // don't use at all!!! diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index 7842e501fd4..3cbe11125b9 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -52,8 +52,22 @@ protected: environment.addModifier([this](Environment &env) { BuildTargetInfo bti = buildTargetInfo(); - if (bti.runEnvModifier) + if (bti.runEnvModifier) { + Environment old = env; bti.runEnvModifier(env, useLibraryPaths()); + const EnvironmentItems diff = old.diff(env, true); + for (const EnvironmentItem &i : diff) { + switch (i.operation) { + case EnvironmentItem::SetEnabled: + case EnvironmentItem::Prepend: + case EnvironmentItem::Append: + env.addItem(std::make_tuple("_QTC_" + i.name, i.value)); + break; + default: + break; + } + } + } }); setUpdater([this] { updateTargetInformation(); }); diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index c266055003c..70e6cf9e91f 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -80,8 +80,11 @@ void SshParameters::setupSshEnvironment(Process *process) Environment env = process->controlEnvironment(); if (!env.hasChanges()) env = Environment::systemEnvironment(); - if (SshSettings::askpassFilePath().exists()) { - env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput()); + const FilePath askPass = SshSettings::askpassFilePath(); + if (askPass.exists()) { + if (askPass.fileName().contains("qtc")) + env = Environment::originalSystemEnvironment(); + env.set("SSH_ASKPASS", askPass.toUserOutput()); env.set("SSH_ASKPASS_REQUIRE", "force"); // OpenSSH only uses the askpass program if DISPLAY is set, regardless of the platform. diff --git a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp index 4968d3d2163..b7f831b8dee 100644 --- a/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp +++ b/src/plugins/qbsprojectmanager/qbsprofilemanager.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -224,6 +225,7 @@ QString QbsProfileManager::runQbsConfig(QbsConfigOp op, const QString &key, cons if (qbsConfigExe.isEmpty() || !qbsConfigExe.exists()) return {}; Utils::Process qbsConfig; + qbsConfig.setEnvironment(QbsSettings::qbsProcessEnvironment()); qbsConfig.setCommand({qbsConfigExe, args}); qbsConfig.start(); using namespace std::chrono_literals; diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 5920487bce8..ac3ed5724ec 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -201,6 +201,7 @@ void QbsSession::initialize() QTimer::singleShot(0, this, [this] { setError(Error::InvalidQbsExecutable); }); return; } + d->qbsProcess->setEnvironment(QbsSettings::qbsProcessEnvironment()); d->qbsProcess->setCommand({qbsExe, {"session"}}); d->qbsProcess->start(); } diff --git a/src/plugins/qbsprojectmanager/qbssettings.cpp b/src/plugins/qbsprojectmanager/qbssettings.cpp index ea89d659855..00426e001fd 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.cpp +++ b/src/plugins/qbsprojectmanager/qbssettings.cpp @@ -28,12 +28,20 @@ const char QBS_EXE_KEY[] = "QbsProjectManager/QbsExecutable"; const char QBS_DEFAULT_INSTALL_DIR_KEY[] = "QbsProjectManager/DefaultInstallDir"; const char USE_CREATOR_SETTINGS_KEY[] = "QbsProjectManager/useCreatorDir"; +static Environment getQbsProcessEnvironment(const FilePath &qbsExe) +{ + if (qbsExe == QbsSettings::defaultQbsExecutableFilePath()) + return Environment::originalSystemEnvironment(); + return qbsExe.deviceEnvironment(); +} + static QString getQbsVersion(const FilePath &qbsExe) { if (qbsExe.isEmpty() || !qbsExe.exists()) return {}; Process qbsProc; qbsProc.setCommand({qbsExe, {"--version"}}); + qbsProc.setEnvironment(getQbsProcessEnvironment(qbsExe)); qbsProc.start(); using namespace std::chrono_literals; if (!qbsProc.waitForFinished(5s) || qbsProc.exitCode() != 0) @@ -82,6 +90,11 @@ FilePath QbsSettings::qbsConfigFilePath() return qbsConfig; } +Environment QbsSettings::qbsProcessEnvironment() +{ + return getQbsProcessEnvironment(qbsExecutableFilePath()); +} + QString QbsSettings::defaultInstallDirTemplate() { return instance().m_settings.defaultInstallDirTemplate; diff --git a/src/plugins/qbsprojectmanager/qbssettings.h b/src/plugins/qbsprojectmanager/qbssettings.h index 434a9af34f3..f996eb2e9a7 100644 --- a/src/plugins/qbsprojectmanager/qbssettings.h +++ b/src/plugins/qbsprojectmanager/qbssettings.h @@ -9,6 +9,8 @@ #include +namespace Utils { class Environment; } + namespace QbsProjectManager::Internal { class QbsSettingsData @@ -29,6 +31,7 @@ public: static Utils::FilePath qbsExecutableFilePath(); static Utils::FilePath defaultQbsExecutableFilePath(); static Utils::FilePath qbsConfigFilePath(); + static Utils::Environment qbsProcessEnvironment(); static bool hasQbsExecutable(); static QString defaultInstallDirTemplate(); static bool useCreatorSettingsDirForQbs(); diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index e686e448b30..2528912b757 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1337,8 +1337,6 @@ void QtVersionPrivate::updateVersionInfo() m_qmakeIsExecutable = false; qWarning("Cannot update Qt version information from %s: %s.", qPrintable(m_qmakeCommand.displayName()), qPrintable(error)); - qWarning("If this appears when running Qt Creator in Qt Creator make " - "sure to disable \"Add build library search path to LD_LIBRARY_PATH\""); return; } m_qmakeIsExecutable = true;