macOS: Fix importing command line builds with CMake

When configuring a CMake project on the command line, CMake will
(correctly) find and use the compiler from the current developer
directory, usually somewhere in
/Applications/Xcode.app/Contents/Developer

But Qt Creator auto-detects and sets up the compiler /usr/bin/clang(++)
for desktop kits. This leads to a compiler mismatch between kits and the
imported build, and to new kits registered in Qt Creator for the import.

Since /usr/bin/clang(++) is just a thin wrapper that resolves to the
compiler in the current developer directory, resolve that in Qt Creator
with "xcrun -f <command>" too (caching the result), and include that
when comparing toolchains for importing builds.

Fixes: QTCREATORBUG-27591
Change-Id: I301e2a4e267450b488b49d0c32d4ce89001bb5ec
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Eike Ziller
2022-06-08 16:00:13 +02:00
parent 4612a052f4
commit 948f0070fa
7 changed files with 40 additions and 8 deletions

View File

@@ -394,10 +394,7 @@ bool CMakeProjectImporter::matchKit(void *directoryData, const Kit *k) const
if (!Utils::contains(allLanguages, [&tcd](const Id& language) {return language == tcd.language;}))
continue;
ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language);
if (!tc
|| !Utils::Environment::systemEnvironment()
.isSameExecutable(tc->compilerCommand().toString(),
tcd.compilerPath.toString())) {
if (!tc || !tc->matchesCompilerCommand(tcd.compilerPath)) {
return false;
}
}

View File

@@ -1580,6 +1580,27 @@ ClangToolChain::~ClangToolChain()
QObject::disconnect(m_mingwToolchainAddedConnection);
}
bool ClangToolChain::matchesCompilerCommand(const Utils::FilePath &command,
const Utils::Environment &env) const
{
if (!m_resolvedCompilerCommand) {
m_resolvedCompilerCommand = FilePath();
if (HostOsInfo::isMacHost()
&& compilerCommand().parentDir() == FilePath::fromString("/usr/bin")) {
std::unique_ptr<QtcProcess> xcrun(new QtcProcess);
xcrun->setCommand({"/usr/bin/xcrun", {"-f", compilerCommand().fileName()}});
xcrun->runBlocking();
const FilePath output = FilePath::fromString(xcrun->stdOut().trimmed());
if (output.isExecutableFile() && output != compilerCommand())
m_resolvedCompilerCommand = output;
}
}
if (!m_resolvedCompilerCommand->isEmpty()
&& env.isSameExecutable(m_resolvedCompilerCommand->toString(), command.toString()))
return true;
return GccToolChain::matchesCompilerCommand(command, env);
}
static FilePath mingwAwareMakeCommand(const Environment &environment)
{
const QStringList makes

View File

@@ -33,6 +33,7 @@
#include "headerpath.h"
#include <utils/fileutils.h>
#include <utils/optional.h>
#include <functional>
#include <memory>
@@ -211,6 +212,10 @@ public:
explicit ClangToolChain(Utils::Id typeId);
~ClangToolChain() override;
bool matchesCompilerCommand(
const Utils::FilePath &command,
const Utils::Environment &env = Utils::Environment::systemEnvironment()) const override;
Utils::FilePath makeCommand(const Utils::Environment &environment) const override;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
@@ -237,6 +242,9 @@ protected:
void syncAutodetectedWithParentToolchains();
private:
// "resolved" on macOS from /usr/bin/clang(++) etc to <DeveloperDir>/usr/bin/clang(++)
// which is used for comparison with matchesCompileCommand
mutable Utils::optional<Utils::FilePath> m_resolvedCompilerCommand;
QByteArray m_parentToolChainId;
QMetaObject::Connection m_mingwToolchainAddedConnection;
QMetaObject::Connection m_thisToolchainRemovedConnection;

View File

@@ -414,9 +414,7 @@ ProjectImporter::findOrCreateToolChains(const ToolChainDescription &tcd) const
{
ToolChainData result;
result.tcs = ToolChainManager::toolchains([&tcd](const ToolChain *tc) {
return tc->language() == tcd.language &&
Utils::Environment::systemEnvironment().isSameExecutable(
tc->compilerCommand().toString(), tcd.compilerPath.toString());
return tc->language() == tcd.language && tc->matchesCompilerCommand(tcd.compilerPath);
});
for (const ToolChain *tc : qAsConst(result.tcs)) {
const QByteArray tcId = tc->id();

View File

@@ -343,6 +343,11 @@ void ToolChain::setCompilerCommand(const FilePath &command)
toolChainUpdated();
}
bool ToolChain::matchesCompilerCommand(const Utils::FilePath &command, const Environment &env) const
{
return env.isSameExecutable(compilerCommand().toString(), command.toString());
}
void ToolChain::setCompilerCommandKey(const QString &commandKey)
{
d->m_compilerCommandKey = commandKey;

View File

@@ -156,6 +156,9 @@ public:
virtual Utils::FilePath compilerCommand() const; // FIXME: De-virtualize.
void setCompilerCommand(const Utils::FilePath &command);
virtual bool matchesCompilerCommand(
const Utils::FilePath &command,
const Utils::Environment &env = Utils::Environment::systemEnvironment()) const;
virtual QList<Utils::OutputLineParser *> createOutputParsers() const = 0;

View File

@@ -1390,7 +1390,7 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const
const Utils::FilePath expected = tc->compilerCommand();
Environment env = buildConfiguration()->environment();
if (env.isSameExecutable(path.toString(), expected.toString()))
if (tc->matchesCompilerCommand(expected, env))
return;
const QPair<Utils::FilePath, Utils::FilePath> pair = qMakePair(expected, path);
if (m_toolChainWarnings.contains(pair))