forked from qt-creator/qt-creator
CMakeProjectManager: Fix importing Qt6 projects
The code that detected the qmake path for the project stopped working with Qt 6.0. The new code will run a small CMake project that will output the path of qmake from the CMake world, and not something that Qt Creator does from outside. Fixes: QTCREATORBUG-25100 Change-Id: I9071648c2e60eb89d0dc8f08aed793167b42a365 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -155,76 +155,97 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
|||||||
const FilePath baseQtDir = canQtCMakeDir.parentDir().parentDir().parentDir(); // Up 3 levels...
|
const FilePath baseQtDir = canQtCMakeDir.parentDir().parentDir().parentDir(); // Up 3 levels...
|
||||||
qCDebug(cmInputLog) << "BaseQtDir:" << baseQtDir.toUserOutput();
|
qCDebug(cmInputLog) << "BaseQtDir:" << baseQtDir.toUserOutput();
|
||||||
|
|
||||||
// "Parse" Qt5Core/Qt5CoreConfigExtras.cmake:
|
// Run a CMake project that would do qmake probing
|
||||||
{
|
TemporaryDirectory qtcQMakeProbeDir("qtc-cmake-qmake-probe-XXXXXXXX");
|
||||||
// This assumes that roughly this kind of data is found in
|
|
||||||
// inside Qt5Core/Qt5CoreConfigExtras.cmake:
|
|
||||||
//
|
|
||||||
// if (NOT TARGET Qt5::qmake)
|
|
||||||
// add_executable(Qt5::qmake IMPORTED)
|
|
||||||
// set(imported_location "${_qt5Core_install_prefix}/bin/qmake")
|
|
||||||
// _qt5_Core_check_file_exists(${imported_location})
|
|
||||||
// set_target_properties(Qt5::qmake PROPERTIES
|
|
||||||
// IMPORTED_LOCATION ${imported_location}
|
|
||||||
// )
|
|
||||||
// endif()
|
|
||||||
|
|
||||||
QFile extras(qtCMakeDir.toString() + "/Qt5CoreConfigExtras.cmake");
|
QFile cmakeListTxt(qtcQMakeProbeDir.path() + "/CMakeLists.txt");
|
||||||
if (!extras.open(QIODevice::ReadOnly)) {
|
if (!cmakeListTxt.open(QIODevice::WriteOnly)) {
|
||||||
extras.setFileName(qtCMakeDir.toString() + "/Qt6CoreConfigExtras.cmake");
|
|
||||||
if (!extras.open(QIODevice::ReadOnly))
|
|
||||||
return FilePath();
|
return FilePath();
|
||||||
}
|
}
|
||||||
|
cmakeListTxt.write(QByteArray(R"(
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
QByteArray data;
|
project(qmake-probe LANGUAGES NONE)
|
||||||
bool inQmakeSection = false;
|
|
||||||
// Read in 4k chunks, lines longer than that are going to be ignored
|
# Bypass Qt6's usage of find_dependency, which would require compiler
|
||||||
while (!extras.atEnd()) {
|
# and source code probing, which slows things unnecessarily
|
||||||
data = extras.read(4 * 1024 - data.count());
|
file(WRITE "${CMAKE_SOURCE_DIR}/CMakeFindDependencyMacro.cmake"
|
||||||
int startPos = 0;
|
[=[
|
||||||
forever {
|
macro(find_dependency dep)
|
||||||
const int pos = data.indexOf('\n', startPos);
|
endmacro()
|
||||||
if (pos < 0) {
|
]=])
|
||||||
data = data.mid(startPos);
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
||||||
break;
|
|
||||||
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
|
||||||
|
|
||||||
|
if (CMAKE_CROSSCOMPILING)
|
||||||
|
find_program(qmake_binary
|
||||||
|
NAMES qmake qmake.bat
|
||||||
|
PATHS "${Qt${QT_VERSION_MAJOR}_DIR}/../../../bin"
|
||||||
|
NO_DEFAULT_PATH)
|
||||||
|
file(WRITE "${CMAKE_SOURCE_DIR}/qmake-location.txt" "${qmake_binary}")
|
||||||
|
else()
|
||||||
|
file(GENERATE
|
||||||
|
OUTPUT "${CMAKE_SOURCE_DIR}/qmake-location.txt"
|
||||||
|
CONTENT "$<TARGET_PROPERTY:Qt${QT_VERSION_MAJOR}::qmake,IMPORTED_LOCATION>")
|
||||||
|
endif()
|
||||||
|
)"));
|
||||||
|
cmakeListTxt.close();
|
||||||
|
|
||||||
|
SynchronousProcess cmake;
|
||||||
|
cmake.setTimeoutS(5);
|
||||||
|
cmake.setFlags(SynchronousProcess::UnixTerminalDisabled);
|
||||||
|
Environment env = Environment::systemEnvironment();
|
||||||
|
Environment::setupEnglishOutput(&env);
|
||||||
|
cmake.setProcessEnvironment(env.toProcessEnvironment());
|
||||||
|
cmake.setTimeOutMessageBoxEnabled(false);
|
||||||
|
|
||||||
|
QString cmakeGenerator
|
||||||
|
= QString::fromUtf8(CMakeConfigItem::valueOf(QByteArray("CMAKE_GENERATOR"), config));
|
||||||
|
FilePath cmakeExecutable
|
||||||
|
= FilePath::fromUtf8(CMakeConfigItem::valueOf(QByteArray("CMAKE_COMMAND"), config));
|
||||||
|
FilePath cmakeMakeProgram
|
||||||
|
= FilePath::fromUtf8(CMakeConfigItem::valueOf(QByteArray("CMAKE_MAKE_PROGRAM"), config));
|
||||||
|
FilePath toolchainFile
|
||||||
|
= FilePath::fromUtf8(CMakeConfigItem::valueOf(QByteArray("CMAKE_TOOLCHAIN_FILE"), config));
|
||||||
|
FilePath hostPath
|
||||||
|
= FilePath::fromUtf8(CMakeConfigItem::valueOf(QByteArray("QT_HOST_PATH"), config));
|
||||||
|
|
||||||
|
QStringList args;
|
||||||
|
args.push_back("-S");
|
||||||
|
args.push_back(qtcQMakeProbeDir.path());
|
||||||
|
args.push_back("-B");
|
||||||
|
args.push_back(qtcQMakeProbeDir.path() + "/build");
|
||||||
|
args.push_back("-G");
|
||||||
|
args.push_back(cmakeGenerator);
|
||||||
|
|
||||||
|
if (!cmakeMakeProgram.isEmpty()) {
|
||||||
|
args.push_back(QStringLiteral("-DCMAKE_MAKE_PROGRAM=%1").arg(cmakeMakeProgram.toString()));
|
||||||
|
}
|
||||||
|
if (toolchainFile.isEmpty()) {
|
||||||
|
args.push_back(QStringLiteral("-DCMAKE_PREFIX_PATH=%1").arg(baseQtDir.toString()));
|
||||||
|
} else {
|
||||||
|
args.push_back(QStringLiteral("-DCMAKE_FIND_ROOT_PATH=%1").arg(baseQtDir.toString()));
|
||||||
|
args.push_back(QStringLiteral("-DCMAKE_TOOLCHAIN_FILE=%1").arg(toolchainFile.toString()));
|
||||||
|
}
|
||||||
|
if (!hostPath.isEmpty()) {
|
||||||
|
args.push_back(QStringLiteral("-DQT_HOST_PATH=%1").arg(hostPath.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray line = data.mid(startPos, pos - startPos);
|
qCDebug(cmInputLog) << "CMake probing for qmake path: " << cmakeExecutable.toUserOutput() << args;
|
||||||
const QByteArray origLine = line;
|
cmake.runBlocking({cmakeExecutable, args});
|
||||||
|
|
||||||
startPos = pos + 1;
|
|
||||||
|
|
||||||
line.replace("(", " ( ");
|
QFile qmakeLocationTxt(qtcQMakeProbeDir.path() + "/qmake-location.txt");
|
||||||
line.replace(")", " ) ");
|
if (!qmakeLocationTxt.open(QIODevice::ReadOnly)) {
|
||||||
line = line.simplified();
|
|
||||||
|
|
||||||
if (line == "if ( NOT TARGET Qt5::qmake )"
|
|
||||||
|| line == "if ( NOT TARGET Qt6::qmake )")
|
|
||||||
inQmakeSection = true;
|
|
||||||
|
|
||||||
if (!inQmakeSection)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const QByteArray set = "set ( imported_location ";
|
|
||||||
if (line.startsWith(set)) {
|
|
||||||
const int sp = origLine.indexOf('}');
|
|
||||||
const int ep = origLine.lastIndexOf('"');
|
|
||||||
|
|
||||||
QTC_ASSERT(sp > 0, return FilePath());
|
|
||||||
QTC_ASSERT(ep > sp + 2, return FilePath());
|
|
||||||
QTC_ASSERT(ep < origLine.count(), return FilePath());
|
|
||||||
|
|
||||||
// Eat the leading "}/" and trailing "
|
|
||||||
const QByteArray locationPart = origLine.mid(sp + 2, ep - 2 - sp);
|
|
||||||
return baseQtDir.pathAppended(QString::fromUtf8(locationPart));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now try to make sense of .../Qt5CoreConfig.cmake:
|
|
||||||
return FilePath();
|
return FilePath();
|
||||||
}
|
}
|
||||||
|
FilePath qmakeLocation = FilePath::fromUtf8(qmakeLocationTxt.readLine().data());
|
||||||
|
qCDebug(cmInputLog) << "qmake location: " << qmakeLocation.toUserOutput();
|
||||||
|
|
||||||
|
return qmakeLocation;
|
||||||
|
}
|
||||||
|
|
||||||
static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfig &config)
|
static QVector<ToolChainDescription> extractToolChainsFromCache(const CMakeConfig &config)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user