forked from qt-creator/qt-creator
CMakePM: Better Qt import detection
Qt6_DIR and Qt5_DIR CMake variables are additionally checked for existence. Qt6_ROOT and Qt5_ROOT are taken into consideration for both environment and CMake variables. CMAKE_PREFIX_PATH is also returned from the qmake probe. This fixes the case when qt.toolchain.cmake is used exclusively. Task-number: QTCREATORBUG-29075 Change-Id: I6e0c3adf7f5d9860a1cb776371e66dea1dfc26cc Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
@@ -247,44 +247,66 @@ static CMakeConfig configurationFromPresetProbe(
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
struct QMakeAndCMakePrefixPath
|
||||||
|
{
|
||||||
|
FilePath qmakePath;
|
||||||
|
QString cmakePrefixPath; // can be a semicolon-separated list
|
||||||
|
};
|
||||||
|
|
||||||
|
static QMakeAndCMakePrefixPath qtInfoFromCMakeCache(const CMakeConfig &config,
|
||||||
|
const Environment &env)
|
||||||
{
|
{
|
||||||
// Qt4 way to define things (more convenient for us, so try this first;-)
|
// Qt4 way to define things (more convenient for us, so try this first;-)
|
||||||
const FilePath qmake = config.filePathValueOf("QT_QMAKE_EXECUTABLE");
|
const FilePath qmake = config.filePathValueOf("QT_QMAKE_EXECUTABLE");
|
||||||
qCDebug(cmInputLog) << "QT_QMAKE_EXECUTABLE=" << qmake.toUserOutput();
|
qCDebug(cmInputLog) << "QT_QMAKE_EXECUTABLE=" << qmake.toUserOutput();
|
||||||
if (!qmake.isEmpty())
|
|
||||||
return qmake;
|
|
||||||
|
|
||||||
// Check Qt5 settings: oh, the horror!
|
// Check Qt5 settings: oh, the horror!
|
||||||
const FilePath qtCMakeDir = [config] {
|
const FilePath qtCMakeDir = [config, env] {
|
||||||
FilePath tmp = config.filePathValueOf("Qt5Core_DIR");
|
FilePath tmp;
|
||||||
if (tmp.isEmpty())
|
// Check the CMake "<package-name>_DIR" variable
|
||||||
tmp = config.filePathValueOf("Qt6Core_DIR");
|
for (const auto &var : {"Qt6", "Qt6Core", "Qt5", "Qt5Core"}) {
|
||||||
|
tmp = config.filePathValueOf(QByteArray(var) + "_DIR");
|
||||||
|
if (!tmp.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
}();
|
}();
|
||||||
qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput();
|
qCDebug(cmInputLog) << "QtXCore_DIR=" << qtCMakeDir.toUserOutput();
|
||||||
const FilePath canQtCMakeDir = FilePath::fromString(qtCMakeDir.toFileInfo().canonicalFilePath());
|
const FilePath canQtCMakeDir = FilePath::fromString(qtCMakeDir.toFileInfo().canonicalFilePath());
|
||||||
qCInfo(cmInputLog) << "QtXCore_DIR (canonical)=" << canQtCMakeDir.toUserOutput();
|
qCInfo(cmInputLog) << "QtXCore_DIR (canonical)=" << canQtCMakeDir.toUserOutput();
|
||||||
QString prefixPath;
|
|
||||||
if (!qtCMakeDir.isEmpty()) {
|
const QString prefixPath = [qtCMakeDir, canQtCMakeDir, config, env] {
|
||||||
prefixPath = canQtCMakeDir.parentDir().parentDir().parentDir().toString(); // Up 3 levels...
|
QString result;
|
||||||
} else {
|
if (!qtCMakeDir.isEmpty()) {
|
||||||
prefixPath = config.stringValueOf("CMAKE_PREFIX_PATH");
|
result = canQtCMakeDir.parentDir().parentDir().parentDir().path(); // Up 3 levels...
|
||||||
}
|
} else {
|
||||||
|
// Check the CMAKE_PREFIX_PATH and "<package-name>_ROOT" CMake or environment variables
|
||||||
|
// This can be a single value or a semicolon-separated list
|
||||||
|
for (const auto &var : {"CMAKE_PREFIX_PATH", "Qt6_ROOT", "Qt5_ROOT"}) {
|
||||||
|
result = config.stringValueOf(var);
|
||||||
|
if (result.isEmpty())
|
||||||
|
result = env.value(QString::fromUtf8(var));
|
||||||
|
if (!result.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
qCDebug(cmInputLog) << "PrefixPath:" << prefixPath;
|
qCDebug(cmInputLog) << "PrefixPath:" << prefixPath;
|
||||||
|
|
||||||
|
if (!qmake.isEmpty() && !prefixPath.isEmpty())
|
||||||
|
return {qmake, prefixPath};
|
||||||
|
|
||||||
FilePath toolchainFile = config.filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"));
|
FilePath toolchainFile = config.filePathValueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"));
|
||||||
if (prefixPath.isEmpty() && toolchainFile.isEmpty())
|
if (prefixPath.isEmpty() && toolchainFile.isEmpty())
|
||||||
return FilePath();
|
return {qmake, QString()};
|
||||||
|
|
||||||
// Run a CMake project that would do qmake probing
|
// Run a CMake project that would do qmake probing
|
||||||
TemporaryDirectory qtcQMakeProbeDir("qtc-cmake-qmake-probe-XXXXXXXX");
|
TemporaryDirectory qtcQMakeProbeDir("qtc-cmake-qmake-probe-XXXXXXXX");
|
||||||
|
|
||||||
QFile cmakeListTxt(qtcQMakeProbeDir.filePath("CMakeLists.txt").toString());
|
FilePath cmakeListTxt(qtcQMakeProbeDir.filePath("CMakeLists.txt"));
|
||||||
if (!cmakeListTxt.open(QIODevice::WriteOnly)) {
|
|
||||||
return FilePath();
|
cmakeListTxt.writeFileContents(QByteArray(R"(
|
||||||
}
|
|
||||||
cmakeListTxt.write(QByteArray(R"(
|
|
||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
project(qmake-probe LANGUAGES NONE)
|
project(qmake-probe LANGUAGES NONE)
|
||||||
@@ -312,15 +334,20 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
|||||||
OUTPUT "${CMAKE_SOURCE_DIR}/qmake-location.txt"
|
OUTPUT "${CMAKE_SOURCE_DIR}/qmake-location.txt"
|
||||||
CONTENT "$<TARGET_PROPERTY:Qt${QT_VERSION_MAJOR}::qmake,IMPORTED_LOCATION>")
|
CONTENT "$<TARGET_PROPERTY:Qt${QT_VERSION_MAJOR}::qmake,IMPORTED_LOCATION>")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Remove a Qt CMake hack that adds lib/cmake at the end of every path in CMAKE_PREFIX_PATH
|
||||||
|
list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)
|
||||||
|
list(TRANSFORM CMAKE_PREFIX_PATH REPLACE "/lib/cmake$" "")
|
||||||
|
file(WRITE "${CMAKE_SOURCE_DIR}/cmake-prefix-path.txt" "${CMAKE_PREFIX_PATH}")
|
||||||
)"));
|
)"));
|
||||||
cmakeListTxt.close();
|
|
||||||
|
|
||||||
QtcProcess cmake;
|
QtcProcess cmake;
|
||||||
cmake.setTimeoutS(5);
|
cmake.setTimeoutS(5);
|
||||||
cmake.setDisableUnixTerminal();
|
cmake.setDisableUnixTerminal();
|
||||||
Environment env = Environment::systemEnvironment();
|
|
||||||
env.setupEnglishOutput();
|
Environment cmakeEnv(env);
|
||||||
cmake.setEnvironment(env);
|
cmakeEnv.setupEnglishOutput();
|
||||||
|
cmake.setEnvironment(cmakeEnv);
|
||||||
cmake.setTimeOutMessageBoxEnabled(false);
|
cmake.setTimeOutMessageBoxEnabled(false);
|
||||||
|
|
||||||
QString cmakeGenerator = config.stringValueOf(QByteArray("CMAKE_GENERATOR"));
|
QString cmakeGenerator = config.stringValueOf(QByteArray("CMAKE_GENERATOR"));
|
||||||
@@ -364,14 +391,17 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
|||||||
cmake.setCommand({cmakeExecutable, args});
|
cmake.setCommand({cmakeExecutable, args});
|
||||||
cmake.runBlocking();
|
cmake.runBlocking();
|
||||||
|
|
||||||
QFile qmakeLocationTxt(qtcQMakeProbeDir.filePath("qmake-location.txt").path());
|
const FilePath qmakeLocationTxt = qtcQMakeProbeDir.filePath("qmake-location.txt");
|
||||||
if (!qmakeLocationTxt.open(QIODevice::ReadOnly)) {
|
const FilePath qmakeLocation = FilePath::fromUtf8(
|
||||||
return FilePath();
|
qmakeLocationTxt.fileContents().value_or(QByteArray()));
|
||||||
}
|
|
||||||
FilePath qmakeLocation = FilePath::fromUtf8(qmakeLocationTxt.readLine().constData());
|
|
||||||
qCDebug(cmInputLog) << "qmake location: " << qmakeLocation.toUserOutput();
|
qCDebug(cmInputLog) << "qmake location: " << qmakeLocation.toUserOutput();
|
||||||
|
|
||||||
return qmakeLocation;
|
const FilePath prefixPathTxt = qtcQMakeProbeDir.filePath("cmake-prefix-path.txt");
|
||||||
|
const QString resultedPrefixPath = QString::fromUtf8(
|
||||||
|
prefixPathTxt.fileContents().value_or(QByteArray()));
|
||||||
|
qCDebug(cmInputLog) << "PrefixPath [after qmake probe]: " << resultedPrefixPath;
|
||||||
|
|
||||||
|
return {qmakeLocation, resultedPrefixPath};
|
||||||
}
|
}
|
||||||
|
|
||||||
static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfig &config)
|
static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfig &config)
|
||||||
@@ -686,10 +716,15 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
|||||||
configurePreset.generator.value().toUtf8());
|
configurePreset.generator.value().toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
const FilePath qmake = qmakeFromCMakeCache(config);
|
const auto [qmake, cmakePrefixPath] = qtInfoFromCMakeCache(config, env);
|
||||||
if (!qmake.isEmpty())
|
if (!qmake.isEmpty())
|
||||||
data->qt = findOrCreateQtVersion(qmake);
|
data->qt = findOrCreateQtVersion(qmake);
|
||||||
|
|
||||||
|
if (!cmakePrefixPath.isEmpty() && config.valueOf("CMAKE_PREFIX_PATH").isEmpty())
|
||||||
|
config << CMakeConfigItem("CMAKE_PREFIX_PATH",
|
||||||
|
CMakeConfigItem::PATH,
|
||||||
|
cmakePrefixPath.toUtf8());
|
||||||
|
|
||||||
// ToolChains:
|
// ToolChains:
|
||||||
data->toolChains = extractToolChainsFromCache(config);
|
data->toolChains = extractToolChainsFromCache(config);
|
||||||
|
|
||||||
@@ -746,6 +781,8 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
|||||||
buildConfigurationTypes = buildConfigurationTypesString.split(';');
|
buildConfigurationTypes = buildConfigurationTypesString.split(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Environment env = projectDirectory().deviceEnvironment();
|
||||||
|
|
||||||
for (auto const &buildType: std::as_const(buildConfigurationTypes)) {
|
for (auto const &buildType: std::as_const(buildConfigurationTypes)) {
|
||||||
auto data = std::make_unique<DirectoryData>();
|
auto data = std::make_unique<DirectoryData>();
|
||||||
|
|
||||||
@@ -777,7 +814,7 @@ QList<void *> CMakeProjectImporter::examineDirectory(const FilePath &importPath,
|
|||||||
data->sysroot = config.filePathValueOf("CMAKE_SYSROOT");
|
data->sysroot = config.filePathValueOf("CMAKE_SYSROOT");
|
||||||
|
|
||||||
// Qt:
|
// Qt:
|
||||||
const FilePath qmake = qmakeFromCMakeCache(config);
|
const auto [qmake, cmakePrefixPath] = qtInfoFromCMakeCache(config, env);
|
||||||
if (!qmake.isEmpty())
|
if (!qmake.isEmpty())
|
||||||
data->qt = findOrCreateQtVersion(qmake);
|
data->qt = findOrCreateQtVersion(qmake);
|
||||||
|
|
||||||
@@ -1021,8 +1058,9 @@ void CMakeProjectPlugin::testCMakeProjectImporterQt()
|
|||||||
config.append(CMakeConfigItem(key.toUtf8(), value.toUtf8()));
|
config.append(CMakeConfigItem(key.toUtf8(), value.toUtf8()));
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath realQmake = qmakeFromCMakeCache(config);
|
auto [realQmake, cmakePrefixPath] = qtInfoFromCMakeCache(config,
|
||||||
QCOMPARE(realQmake.toString(), expectedQmake);
|
Environment::systemEnvironment());
|
||||||
|
QCOMPARE(realQmake.path(), expectedQmake);
|
||||||
}
|
}
|
||||||
void CMakeProjectPlugin::testCMakeProjectImporterToolChain_data()
|
void CMakeProjectPlugin::testCMakeProjectImporterToolChain_data()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user