2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2014-03-12 08:36:36 +01:00
|
|
|
#include "cmaketool.h"
|
2020-04-17 15:30:05 +02:00
|
|
|
|
2022-09-29 15:26:31 +02:00
|
|
|
#include "cmakeprojectmanagertr.h"
|
2015-02-24 21:57:00 +01:00
|
|
|
#include "cmaketoolmanager.h"
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2023-09-17 20:19:04 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2022-02-03 16:12:41 +01:00
|
|
|
#include <coreplugin/helpmanager.h>
|
|
|
|
|
|
2016-01-22 13:50:58 +01:00
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
#include <utils/environment.h>
|
2023-09-05 14:11:33 +02:00
|
|
|
#include <utils/persistentcachestore.h>
|
2023-05-03 17:05:35 +02:00
|
|
|
#include <utils/process.h>
|
2015-02-04 17:54:46 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2023-09-22 16:22:49 +02:00
|
|
|
#include <utils/temporarydirectory.h>
|
2015-02-04 17:54:46 +01:00
|
|
|
|
2019-10-10 11:30:51 +02:00
|
|
|
#include <QDir>
|
2016-09-28 15:18:29 +02:00
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <QJsonObject>
|
2022-04-07 14:04:20 +02:00
|
|
|
#include <QLoggingCategory>
|
2016-09-28 17:25:29 +02:00
|
|
|
#include <QRegularExpression>
|
2016-01-22 13:50:58 +01:00
|
|
|
#include <QSet>
|
2023-09-17 20:19:04 +02:00
|
|
|
#include <QXmlStreamReader>
|
2015-02-04 17:54:46 +01:00
|
|
|
#include <QUuid>
|
2020-04-17 15:30:05 +02:00
|
|
|
|
|
|
|
|
#include <memory>
|
2015-02-04 17:54:46 +01:00
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2016-02-12 12:30:55 +01:00
|
|
|
namespace CMakeProjectManager {
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2022-04-07 14:04:20 +02:00
|
|
|
static Q_LOGGING_CATEGORY(cmakeToolLog, "qtc.cmake.tool", QtWarningMsg);
|
|
|
|
|
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
const char CMAKE_INFORMATION_ID[] = "Id";
|
|
|
|
|
const char CMAKE_INFORMATION_COMMAND[] = "Binary";
|
|
|
|
|
const char CMAKE_INFORMATION_DISPLAYNAME[] = "DisplayName";
|
2016-06-27 13:09:14 +02:00
|
|
|
const char CMAKE_INFORMATION_AUTORUN[] = "AutoRun";
|
2019-10-10 11:30:51 +02:00
|
|
|
const char CMAKE_INFORMATION_QCH_FILE_PATH[] = "QchFile";
|
2021-06-09 15:08:13 +02:00
|
|
|
// obsolete since Qt Creator 5. Kept for backward compatibility
|
2017-09-07 14:00:29 +02:00
|
|
|
const char CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY[] = "AutoCreateBuildDirectory";
|
2015-02-04 17:54:46 +01:00
|
|
|
const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected";
|
2021-07-13 13:05:36 +02:00
|
|
|
const char CMAKE_INFORMATION_DETECTIONSOURCE[] = "DetectionSource";
|
2019-06-18 11:31:46 +02:00
|
|
|
const char CMAKE_INFORMATION_READERTYPE[] = "ReaderType";
|
2016-09-28 12:24:06 +02:00
|
|
|
|
|
|
|
|
bool CMakeTool::Generator::matches(const QString &n, const QString &ex) const
|
|
|
|
|
{
|
|
|
|
|
return n == name && (ex.isEmpty() || extraGenerators.contains(ex));
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 14:17:12 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2019-06-18 11:31:46 +02:00
|
|
|
const char READER_TYPE_FILEAPI[] = "fileapi";
|
|
|
|
|
|
2022-08-26 10:30:00 +02:00
|
|
|
static std::optional<CMakeTool::ReaderType> readerTypeFromString(const QString &input)
|
2019-06-18 11:31:46 +02:00
|
|
|
{
|
2020-04-22 11:18:01 +02:00
|
|
|
// Do not try to be clever here, just use whatever is in the string!
|
2019-06-18 11:31:46 +02:00
|
|
|
if (input == READER_TYPE_FILEAPI)
|
2020-04-22 11:18:01 +02:00
|
|
|
return CMakeTool::FileApi;
|
2019-06-18 11:31:46 +02:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString readerTypeToString(const CMakeTool::ReaderType &type)
|
|
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case CMakeTool::FileApi:
|
2019-06-21 10:07:59 +02:00
|
|
|
return QString(READER_TYPE_FILEAPI);
|
2020-04-25 21:13:56 +03:00
|
|
|
default:
|
|
|
|
|
return QString();
|
2019-06-18 11:31:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 14:17:12 +02:00
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// CMakeIntrospectionData:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
2019-06-11 11:06:32 +02:00
|
|
|
class FileApi {
|
|
|
|
|
public:
|
|
|
|
|
QString kind;
|
|
|
|
|
std::pair<int, int> version;
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-10 14:17:12 +02:00
|
|
|
class IntrospectionData
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool m_didAttemptToRun = false;
|
2023-09-28 15:48:11 +02:00
|
|
|
bool m_haveCapabilitites = true;
|
|
|
|
|
bool m_haveKeywords = false;
|
2018-07-10 14:17:12 +02:00
|
|
|
|
|
|
|
|
QList<CMakeTool::Generator> m_generators;
|
2023-09-22 22:47:31 +02:00
|
|
|
CMakeKeywords m_keywords;
|
2023-09-28 15:48:11 +02:00
|
|
|
QMutex m_keywordsMutex;
|
2019-06-11 11:06:32 +02:00
|
|
|
QVector<FileApi> m_fileApis;
|
2018-07-10 14:17:12 +02:00
|
|
|
CMakeTool::Version m_version;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
|
2012-09-06 22:38:25 +08:00
|
|
|
///////////////////////////
|
2014-03-12 08:36:36 +01:00
|
|
|
// CMakeTool
|
2012-09-06 22:38:25 +08:00
|
|
|
///////////////////////////
|
2021-05-17 13:11:42 +02:00
|
|
|
CMakeTool::CMakeTool(Detection d, const Id &id)
|
2020-04-22 11:18:01 +02:00
|
|
|
: m_id(id)
|
|
|
|
|
, m_isAutoDetected(d == AutoDetection)
|
|
|
|
|
, m_introspection(std::make_unique<Internal::IntrospectionData>())
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2021-05-17 13:11:42 +02:00
|
|
|
QTC_ASSERT(m_id.isValid(), m_id = Id::fromString(QUuid::createUuid().toString()));
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2023-08-24 16:14:26 +02:00
|
|
|
CMakeTool::CMakeTool(const Store &map, bool fromSdk) :
|
2018-07-10 14:17:12 +02:00
|
|
|
CMakeTool(fromSdk ? CMakeTool::AutoDetection : CMakeTool::ManualDetection,
|
2021-05-17 13:11:42 +02:00
|
|
|
Id::fromSetting(map.value(CMAKE_INFORMATION_ID)))
|
2015-02-04 17:54:46 +01:00
|
|
|
{
|
2016-09-26 16:29:58 +02:00
|
|
|
m_displayName = map.value(CMAKE_INFORMATION_DISPLAYNAME).toString();
|
|
|
|
|
m_isAutoRun = map.value(CMAKE_INFORMATION_AUTORUN, true).toBool();
|
2017-09-07 14:00:29 +02:00
|
|
|
m_autoCreateBuildDirectory = map.value(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, false).toBool();
|
2019-06-18 11:31:46 +02:00
|
|
|
m_readerType = Internal::readerTypeFromString(
|
|
|
|
|
map.value(CMAKE_INFORMATION_READERTYPE).toString());
|
2015-02-04 17:54:46 +01:00
|
|
|
|
|
|
|
|
//loading a CMakeTool from SDK is always autodetection
|
|
|
|
|
if (!fromSdk)
|
2016-09-26 16:29:58 +02:00
|
|
|
m_isAutoDetected = map.value(CMAKE_INFORMATION_AUTODETECTED, false).toBool();
|
2021-07-13 13:05:36 +02:00
|
|
|
m_detectionSource = map.value(CMAKE_INFORMATION_DETECTIONSOURCE).toString();
|
2015-02-04 17:54:46 +01:00
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
setFilePath(FilePath::fromString(map.value(CMAKE_INFORMATION_COMMAND).toString()));
|
2019-10-10 11:30:51 +02:00
|
|
|
|
2023-01-03 12:31:52 +01:00
|
|
|
m_qchFilePath = FilePath::fromSettings(map.value(CMAKE_INFORMATION_QCH_FILE_PATH));
|
2019-10-10 11:30:51 +02:00
|
|
|
|
|
|
|
|
if (m_qchFilePath.isEmpty())
|
|
|
|
|
m_qchFilePath = searchQchFile(m_executable);
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2018-07-10 14:17:12 +02:00
|
|
|
CMakeTool::~CMakeTool() = default;
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
Id CMakeTool::createId()
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2021-05-17 13:11:42 +02:00
|
|
|
return Id::fromString(QUuid::createUuid().toString());
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
void CMakeTool::setFilePath(const FilePath &executable)
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2016-01-22 13:50:58 +01:00
|
|
|
if (m_executable == executable)
|
|
|
|
|
return;
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2019-10-09 16:24:47 +02:00
|
|
|
m_introspection = std::make_unique<Internal::IntrospectionData>();
|
2015-02-24 21:57:00 +01:00
|
|
|
|
2016-01-22 13:50:58 +01:00
|
|
|
m_executable = executable;
|
2015-02-24 21:57:00 +01:00
|
|
|
CMakeToolManager::notifyAboutUpdate(this);
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
FilePath CMakeTool::filePath() const
|
2019-08-12 14:44:29 +02:00
|
|
|
{
|
|
|
|
|
return m_executable;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-05 14:11:33 +02:00
|
|
|
bool CMakeTool::isValid(bool ignoreCache) const
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2020-04-03 11:16:48 +02:00
|
|
|
if (!m_id.isValid() || !m_introspection)
|
2016-01-22 13:50:58 +01:00
|
|
|
return false;
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2018-07-10 14:17:12 +02:00
|
|
|
if (!m_introspection->m_didAttemptToRun)
|
2023-09-05 14:11:33 +02:00
|
|
|
readInformation(ignoreCache);
|
2012-09-06 22:38:25 +08:00
|
|
|
|
2023-09-28 15:48:11 +02:00
|
|
|
return m_introspection->m_haveCapabilitites && !m_introspection->m_fileApis.isEmpty();
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
void CMakeTool::runCMake(Process &cmake, const QStringList &args, int timeoutS) const
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2022-09-30 18:13:32 +02:00
|
|
|
const FilePath executable = cmakeExecutable();
|
2019-11-14 15:50:00 +01:00
|
|
|
cmake.setTimeoutS(timeoutS);
|
2021-05-05 15:23:34 +02:00
|
|
|
cmake.setDisableUnixTerminal();
|
2022-09-30 18:13:32 +02:00
|
|
|
Environment env = executable.deviceEnvironment();
|
2021-05-20 11:57:21 +02:00
|
|
|
env.setupEnglishOutput();
|
2021-04-30 18:26:57 +02:00
|
|
|
cmake.setEnvironment(env);
|
2016-01-22 13:50:58 +01:00
|
|
|
cmake.setTimeOutMessageBoxEnabled(false);
|
2022-09-30 18:13:32 +02:00
|
|
|
cmake.setCommand({executable, args});
|
2021-05-17 12:02:42 +02:00
|
|
|
cmake.runBlocking();
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
2023-08-24 16:14:26 +02:00
|
|
|
Store CMakeTool::toMap() const
|
2015-02-04 17:54:46 +01:00
|
|
|
{
|
2023-08-24 16:14:26 +02:00
|
|
|
Store data;
|
2016-09-26 16:29:58 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_DISPLAYNAME, m_displayName);
|
|
|
|
|
data.insert(CMAKE_INFORMATION_ID, m_id.toSetting());
|
|
|
|
|
data.insert(CMAKE_INFORMATION_COMMAND, m_executable.toString());
|
2019-10-10 11:30:51 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_QCH_FILE_PATH, m_qchFilePath.toString());
|
2016-09-26 16:29:58 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_AUTORUN, m_isAutoRun);
|
2017-09-07 14:00:29 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, m_autoCreateBuildDirectory);
|
2020-04-22 11:18:01 +02:00
|
|
|
if (m_readerType)
|
2019-06-18 11:31:46 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_READERTYPE,
|
|
|
|
|
Internal::readerTypeToString(m_readerType.value()));
|
2016-09-26 16:29:58 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_AUTODETECTED, m_isAutoDetected);
|
2021-07-13 13:05:36 +02:00
|
|
|
data.insert(CMAKE_INFORMATION_DETECTIONSOURCE, m_detectionSource);
|
2015-02-04 17:54:46 +01:00
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
FilePath CMakeTool::cmakeExecutable() const
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2019-08-12 15:24:15 +02:00
|
|
|
return cmakeExecutable(m_executable);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
void CMakeTool::setQchFilePath(const FilePath &path)
|
2019-10-10 11:30:51 +02:00
|
|
|
{
|
|
|
|
|
m_qchFilePath = path;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
FilePath CMakeTool::qchFilePath() const
|
2019-10-10 11:30:51 +02:00
|
|
|
{
|
|
|
|
|
return m_qchFilePath;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
FilePath CMakeTool::cmakeExecutable(const FilePath &path)
|
2019-08-12 15:24:15 +02:00
|
|
|
{
|
2022-03-10 13:05:03 +01:00
|
|
|
if (path.osType() == OsTypeMac) {
|
2019-08-12 15:24:15 +02:00
|
|
|
const QString executableString = path.toString();
|
|
|
|
|
const int appIndex = executableString.lastIndexOf(".app");
|
|
|
|
|
const int appCutIndex = appIndex + 4;
|
|
|
|
|
const bool endsWithApp = appIndex >= 0 && appCutIndex >= executableString.size();
|
|
|
|
|
const bool containsApp = appIndex >= 0 && !endsWithApp
|
|
|
|
|
&& executableString.at(appCutIndex) == '/';
|
|
|
|
|
if (endsWithApp || containsApp) {
|
2021-05-17 13:11:42 +02:00
|
|
|
const FilePath toTest = FilePath::fromString(executableString.left(appCutIndex))
|
|
|
|
|
.pathAppended("Contents/bin/cmake");
|
2019-08-12 15:24:15 +02:00
|
|
|
if (toTest.exists())
|
|
|
|
|
return toTest.canonicalPath();
|
|
|
|
|
}
|
2016-09-14 12:56:32 +02:00
|
|
|
}
|
2020-01-22 14:40:57 +01:00
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
const FilePath resolvedPath = path.canonicalPath();
|
2020-01-22 14:40:57 +01:00
|
|
|
// Evil hack to make snap-packages of CMake work. See QTCREATORBUG-23376
|
2022-03-10 13:05:03 +01:00
|
|
|
if (path.osType() == OsTypeLinux && resolvedPath.fileName() == "snap")
|
2020-01-22 14:40:57 +01:00
|
|
|
return path;
|
|
|
|
|
|
|
|
|
|
return resolvedPath;
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2016-06-27 13:09:14 +02:00
|
|
|
bool CMakeTool::isAutoRun() const
|
|
|
|
|
{
|
|
|
|
|
return m_isAutoRun;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-28 12:24:06 +02:00
|
|
|
QList<CMakeTool::Generator> CMakeTool::supportedGenerators() const
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2020-04-03 11:16:48 +02:00
|
|
|
return isValid() ? m_introspection->m_generators : QList<CMakeTool::Generator>();
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2023-09-17 20:19:04 +02:00
|
|
|
CMakeKeywords CMakeTool::keywords()
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2020-04-03 11:16:48 +02:00
|
|
|
if (!isValid())
|
|
|
|
|
return {};
|
|
|
|
|
|
2023-09-28 15:48:11 +02:00
|
|
|
if (!m_introspection->m_haveKeywords && m_introspection->m_haveCapabilitites) {
|
|
|
|
|
QMutexLocker locker(&m_introspection->m_keywordsMutex);
|
|
|
|
|
if (m_introspection->m_haveKeywords)
|
|
|
|
|
return m_introspection->m_keywords;
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process proc;
|
2021-05-12 14:25:50 +02:00
|
|
|
|
2023-09-22 16:22:49 +02:00
|
|
|
const FilePath findCMakeRoot = TemporaryDirectory::masterDirectoryFilePath()
|
|
|
|
|
/ "find-root.cmake";
|
|
|
|
|
findCMakeRoot.writeFileContents("message(${CMAKE_ROOT})");
|
2021-05-12 14:25:50 +02:00
|
|
|
|
2023-09-22 16:22:49 +02:00
|
|
|
FilePath cmakeRoot;
|
|
|
|
|
runCMake(proc, {"-P", findCMakeRoot.nativePath()}, 5);
|
2022-03-02 04:12:25 +01:00
|
|
|
if (proc.result() == ProcessResult::FinishedWithSuccess) {
|
2023-09-22 16:22:49 +02:00
|
|
|
QStringList output = filtered(proc.allOutput().split('\n'),
|
|
|
|
|
std::not_fn(&QString::isEmpty));
|
|
|
|
|
if (output.size() > 0)
|
|
|
|
|
cmakeRoot = FilePath::fromString(output[0]);
|
2016-01-22 13:50:58 +01:00
|
|
|
}
|
2023-09-17 20:19:04 +02:00
|
|
|
|
2023-09-22 16:22:49 +02:00
|
|
|
const struct
|
|
|
|
|
{
|
|
|
|
|
const QString helpPath;
|
2023-09-22 22:47:31 +02:00
|
|
|
QMap<QString, FilePath> &targetMap;
|
2023-09-22 16:22:49 +02:00
|
|
|
} introspections[] = {
|
|
|
|
|
// Functions
|
2023-09-22 22:47:31 +02:00
|
|
|
{"Help/command", m_introspection->m_keywords.functions},
|
2023-09-22 16:22:49 +02:00
|
|
|
// Properties
|
2023-09-22 22:47:31 +02:00
|
|
|
{"Help/prop_dir", m_introspection->m_keywords.directoryProperties},
|
|
|
|
|
{"Help/prop_sf", m_introspection->m_keywords.sourceProperties},
|
|
|
|
|
{"Help/prop_test", m_introspection->m_keywords.testProperties},
|
|
|
|
|
{"Help/prop_tgt", m_introspection->m_keywords.targetProperties},
|
|
|
|
|
{"Help/prop_gbl", m_introspection->m_keywords.properties},
|
2023-09-22 16:22:49 +02:00
|
|
|
// Variables
|
2023-09-22 22:47:31 +02:00
|
|
|
{"Help/variable", m_introspection->m_keywords.variables},
|
2023-09-22 16:22:49 +02:00
|
|
|
// Policies
|
2023-09-22 22:47:31 +02:00
|
|
|
{"Help/policy", m_introspection->m_keywords.policies},
|
2023-09-22 16:22:49 +02:00
|
|
|
};
|
|
|
|
|
for (auto &i : introspections) {
|
|
|
|
|
const FilePaths files = cmakeRoot.pathAppended(i.helpPath)
|
|
|
|
|
.dirEntries({{"*.rst"}, QDir::Files}, QDir::Name);
|
2023-09-22 22:47:31 +02:00
|
|
|
for (const auto &filePath : files)
|
|
|
|
|
i.targetMap[filePath.completeBaseName()] = filePath;
|
2023-09-22 16:22:49 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 22:47:31 +02:00
|
|
|
for (const auto &map : {m_introspection->m_keywords.directoryProperties,
|
|
|
|
|
m_introspection->m_keywords.sourceProperties,
|
|
|
|
|
m_introspection->m_keywords.testProperties,
|
|
|
|
|
m_introspection->m_keywords.targetProperties}) {
|
|
|
|
|
m_introspection->m_keywords.properties.insert(map);
|
|
|
|
|
}
|
2023-09-22 16:22:49 +02:00
|
|
|
|
|
|
|
|
// Modules
|
|
|
|
|
const FilePaths files
|
|
|
|
|
= cmakeRoot.pathAppended("Help/module").dirEntries({{"*.rst"}, QDir::Files}, QDir::Name);
|
2023-09-22 22:47:31 +02:00
|
|
|
for (const FilePath &filePath : files) {
|
|
|
|
|
const QString fileName = filePath.completeBaseName();
|
2023-09-22 16:22:49 +02:00
|
|
|
if (fileName.startsWith("Find"))
|
2023-09-22 22:47:31 +02:00
|
|
|
m_introspection->m_keywords.findModules[fileName.mid(4)] = filePath;
|
2023-09-22 16:22:49 +02:00
|
|
|
else
|
2023-09-22 22:47:31 +02:00
|
|
|
m_introspection->m_keywords.includeStandardModules[fileName] = filePath;
|
2023-09-22 16:22:49 +02:00
|
|
|
}
|
2023-09-20 22:39:50 +02:00
|
|
|
|
2023-09-22 22:47:31 +02:00
|
|
|
const QStringList moduleFunctions = parseSyntaxHighlightingXml();
|
|
|
|
|
for (const auto &function : moduleFunctions)
|
|
|
|
|
m_introspection->m_keywords.functions[function] = FilePath();
|
2023-09-28 15:48:11 +02:00
|
|
|
|
|
|
|
|
m_introspection->m_haveKeywords = true;
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
2016-01-22 13:50:58 +01:00
|
|
|
|
2023-09-22 22:47:31 +02:00
|
|
|
return m_introspection->m_keywords;
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2023-09-05 14:11:33 +02:00
|
|
|
bool CMakeTool::hasFileApi(bool ignoreCache) const
|
2019-06-05 15:05:29 +02:00
|
|
|
{
|
2023-09-05 14:11:33 +02:00
|
|
|
return isValid(ignoreCache) ? !m_introspection->m_fileApis.isEmpty() : false;
|
2019-06-11 11:06:32 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-28 17:25:29 +02:00
|
|
|
CMakeTool::Version CMakeTool::version() const
|
|
|
|
|
{
|
2022-06-28 16:50:21 +02:00
|
|
|
return isValid() ? m_introspection->m_version : CMakeTool::Version();
|
2016-09-28 17:25:29 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-16 17:49:23 +02:00
|
|
|
QString CMakeTool::versionDisplay() const
|
|
|
|
|
{
|
2022-10-27 14:44:48 +02:00
|
|
|
if (m_executable.isEmpty())
|
|
|
|
|
return {};
|
|
|
|
|
|
2022-06-28 16:50:21 +02:00
|
|
|
if (!isValid())
|
2022-09-29 15:26:31 +02:00
|
|
|
return Tr::tr("Version not parseable");
|
2021-06-16 17:49:23 +02:00
|
|
|
|
|
|
|
|
const Version &version = m_introspection->m_version;
|
|
|
|
|
if (version.fullVersion.isEmpty())
|
|
|
|
|
return QString::fromUtf8(version.fullVersion);
|
|
|
|
|
|
|
|
|
|
return QString("%1.%2.%3").arg(version.major).arg(version.minor).arg(version.patch);
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-22 13:50:58 +01:00
|
|
|
bool CMakeTool::isAutoDetected() const
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2016-01-22 13:50:58 +01:00
|
|
|
return m_isAutoDetected;
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
QString CMakeTool::displayName() const
|
|
|
|
|
{
|
|
|
|
|
return m_displayName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMakeTool::setDisplayName(const QString &displayName)
|
|
|
|
|
{
|
|
|
|
|
m_displayName = displayName;
|
2015-02-24 21:57:00 +01:00
|
|
|
CMakeToolManager::notifyAboutUpdate(this);
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-10 15:47:09 +01:00
|
|
|
void CMakeTool::setPathMapper(const CMakeTool::PathMapper &pathMapper)
|
|
|
|
|
{
|
|
|
|
|
m_pathMapper = pathMapper;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-13 11:36:00 +02:00
|
|
|
CMakeTool::PathMapper CMakeTool::pathMapper() const
|
2015-03-10 15:47:09 +01:00
|
|
|
{
|
|
|
|
|
if (m_pathMapper)
|
2016-10-13 11:36:00 +02:00
|
|
|
return m_pathMapper;
|
2021-05-17 13:11:42 +02:00
|
|
|
return [](const FilePath &fn) { return fn; };
|
2015-03-10 15:47:09 +01:00
|
|
|
}
|
2015-02-04 17:54:46 +01:00
|
|
|
|
2022-08-26 10:30:00 +02:00
|
|
|
std::optional<CMakeTool::ReaderType> CMakeTool::readerType() const
|
2019-06-18 11:31:46 +02:00
|
|
|
{
|
2020-04-22 11:18:01 +02:00
|
|
|
if (m_readerType)
|
|
|
|
|
return m_readerType; // Allow overriding the auto-detected value via .user files
|
|
|
|
|
|
|
|
|
|
// Find best possible reader type:
|
2020-04-03 11:16:48 +02:00
|
|
|
if (hasFileApi())
|
2020-04-22 11:18:01 +02:00
|
|
|
return FileApi;
|
|
|
|
|
return {};
|
2019-06-18 11:31:46 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
FilePath CMakeTool::searchQchFile(const FilePath &executable)
|
2019-10-10 11:30:51 +02:00
|
|
|
{
|
2021-10-07 12:03:56 +02:00
|
|
|
if (executable.isEmpty() || executable.needsDevice()) // do not register docs from devices
|
2019-10-10 11:30:51 +02:00
|
|
|
return {};
|
|
|
|
|
|
2021-05-17 13:11:42 +02:00
|
|
|
FilePath prefixDir = executable.parentDir().parentDir();
|
2019-10-10 11:30:51 +02:00
|
|
|
QDir docDir{prefixDir.pathAppended("doc/cmake").toString()};
|
|
|
|
|
if (!docDir.exists())
|
|
|
|
|
docDir.setPath(prefixDir.pathAppended("share/doc/cmake").toString());
|
|
|
|
|
if (!docDir.exists())
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
const QStringList files = docDir.entryList(QStringList("*.qch"));
|
|
|
|
|
for (const QString &docFile : files) {
|
|
|
|
|
if (docFile.startsWith("cmake", Qt::CaseInsensitive)) {
|
2021-05-17 13:11:42 +02:00
|
|
|
return FilePath::fromString(docDir.absoluteFilePath(docFile));
|
2019-10-10 11:30:51 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-03 16:52:50 +01:00
|
|
|
QString CMakeTool::documentationUrl(const Version &version, bool online)
|
2022-02-03 16:12:41 +01:00
|
|
|
{
|
2022-02-03 16:52:50 +01:00
|
|
|
if (online) {
|
|
|
|
|
QString helpVersion = "latest";
|
|
|
|
|
if (!(version.major == 0 && version.minor == 0))
|
|
|
|
|
helpVersion = QString("v%1.%2").arg(version.major).arg(version.minor);
|
|
|
|
|
|
|
|
|
|
return QString("https://cmake.org/cmake/help/%1").arg(helpVersion);
|
|
|
|
|
}
|
2022-02-03 16:12:41 +01:00
|
|
|
|
|
|
|
|
return QString("qthelp://org.cmake.%1.%2.%3/doc")
|
2022-02-03 16:52:50 +01:00
|
|
|
.arg(version.major)
|
|
|
|
|
.arg(version.minor)
|
|
|
|
|
.arg(version.patch);
|
2022-02-03 16:12:41 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-03 16:52:50 +01:00
|
|
|
void CMakeTool::openCMakeHelpUrl(const CMakeTool *tool, const QString &linkUrl)
|
2022-02-03 16:12:41 +01:00
|
|
|
{
|
2022-02-03 16:52:50 +01:00
|
|
|
bool online = true;
|
|
|
|
|
Version version;
|
|
|
|
|
if (tool && tool->isValid()) {
|
|
|
|
|
online = tool->qchFilePath().isEmpty();
|
|
|
|
|
version = tool->version();
|
|
|
|
|
}
|
2022-02-03 16:12:41 +01:00
|
|
|
|
2022-02-03 16:52:50 +01:00
|
|
|
Core::HelpManager::showHelpUrl(linkUrl.arg(documentationUrl(version, online)));
|
2022-02-03 16:12:41 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-05 14:11:33 +02:00
|
|
|
void CMakeTool::readInformation(bool ignoreCache) const
|
2016-09-28 17:25:29 +02:00
|
|
|
{
|
2020-04-03 11:16:48 +02:00
|
|
|
QTC_ASSERT(m_introspection, return );
|
2023-09-28 15:48:11 +02:00
|
|
|
if (!m_introspection->m_haveCapabilitites && m_introspection->m_didAttemptToRun)
|
2019-11-14 15:50:00 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_introspection->m_didAttemptToRun = true;
|
|
|
|
|
|
2023-09-05 14:11:33 +02:00
|
|
|
fetchFromCapabilities(ignoreCache);
|
2016-09-28 17:25:29 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-17 20:19:04 +02:00
|
|
|
|
2016-01-22 13:50:58 +01:00
|
|
|
static QStringList parseDefinition(const QString &definition)
|
2012-09-06 22:38:25 +08:00
|
|
|
{
|
2016-01-22 13:50:58 +01:00
|
|
|
QStringList result;
|
|
|
|
|
QString word;
|
|
|
|
|
bool ignoreWord = false;
|
|
|
|
|
QVector<QChar> braceStack;
|
|
|
|
|
|
2022-05-18 12:28:04 +02:00
|
|
|
for (const QChar &c : definition) {
|
2016-09-26 16:29:58 +02:00
|
|
|
if (c == '[' || c == '<' || c == '(') {
|
2016-01-22 13:50:58 +01:00
|
|
|
braceStack.append(c);
|
|
|
|
|
ignoreWord = false;
|
2016-09-26 16:29:58 +02:00
|
|
|
} else if (c == ']' || c == '>' || c == ')') {
|
|
|
|
|
if (braceStack.isEmpty() || braceStack.takeLast() == '<')
|
2016-01-22 13:50:58 +01:00
|
|
|
ignoreWord = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 11:31:46 +02:00
|
|
|
if (c == ' ' || c == '[' || c == '<' || c == '(' || c == ']' || c == '>' || c == ')') {
|
2016-01-22 13:50:58 +01:00
|
|
|
if (!ignoreWord && !word.isEmpty()) {
|
2019-06-18 11:31:46 +02:00
|
|
|
if (result.isEmpty()
|
|
|
|
|
|| Utils::allOf(word, [](const QChar &c) { return c.isUpper() || c == '_'; }))
|
2016-01-22 13:50:58 +01:00
|
|
|
result.append(word);
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
2016-01-22 13:50:58 +01:00
|
|
|
word.clear();
|
|
|
|
|
ignoreWord = false;
|
|
|
|
|
} else {
|
|
|
|
|
word.append(c);
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
|
|
|
|
}
|
2016-01-22 13:50:58 +01:00
|
|
|
return result;
|
2013-02-16 22:37:31 +08:00
|
|
|
}
|
|
|
|
|
|
2016-01-22 13:50:58 +01:00
|
|
|
void CMakeTool::parseFunctionDetailsOutput(const QString &output)
|
2013-02-16 22:37:31 +08:00
|
|
|
{
|
2016-01-22 13:50:58 +01:00
|
|
|
bool expectDefinition = false;
|
|
|
|
|
QString currentDefinition;
|
|
|
|
|
|
2016-09-26 16:29:58 +02:00
|
|
|
const QStringList lines = output.split('\n');
|
2016-01-22 13:50:58 +01:00
|
|
|
for (int i = 0; i < lines.count(); ++i) {
|
|
|
|
|
const QString line = lines.at(i);
|
|
|
|
|
|
2016-09-26 16:29:58 +02:00
|
|
|
if (line == "::") {
|
2016-01-22 13:50:58 +01:00
|
|
|
expectDefinition = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (expectDefinition) {
|
2016-09-26 16:29:58 +02:00
|
|
|
if (!line.startsWith(' ') && !line.isEmpty()) {
|
2016-01-22 13:50:58 +01:00
|
|
|
expectDefinition = false;
|
|
|
|
|
QStringList words = parseDefinition(currentDefinition);
|
|
|
|
|
if (!words.isEmpty()) {
|
|
|
|
|
const QString command = words.takeFirst();
|
2023-09-22 22:47:31 +02:00
|
|
|
if (m_introspection->m_keywords.functions.contains(command)) {
|
2022-10-21 14:05:12 +02:00
|
|
|
const QStringList tmp = Utils::sorted(
|
2023-09-22 22:47:31 +02:00
|
|
|
words + m_introspection->m_keywords.functionArgs[command]);
|
|
|
|
|
m_introspection->m_keywords.functionArgs[command] = Utils::filteredUnique(
|
|
|
|
|
tmp);
|
2016-01-22 13:50:58 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-09-22 22:47:31 +02:00
|
|
|
if (!words.isEmpty() && m_introspection->m_keywords.functions.contains(words.at(0)))
|
|
|
|
|
m_introspection->m_keywords.functionArgs[words.at(0)];
|
2016-01-22 13:50:58 +01:00
|
|
|
currentDefinition.clear();
|
|
|
|
|
} else {
|
2016-09-26 16:29:58 +02:00
|
|
|
currentDefinition.append(line.trimmed() + ' ');
|
2013-02-16 22:37:31 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-22 13:50:58 +01:00
|
|
|
QStringList CMakeTool::parseVariableOutput(const QString &output)
|
2013-02-16 22:37:31 +08:00
|
|
|
{
|
2023-09-17 20:19:04 +02:00
|
|
|
const QStringList variableList = Utils::filtered(output.split('\n'),
|
|
|
|
|
std::not_fn(&QString::isEmpty));
|
2016-01-22 13:50:58 +01:00
|
|
|
QStringList result;
|
2022-05-18 12:28:04 +02:00
|
|
|
for (const QString &v : variableList) {
|
2016-09-14 12:28:14 +02:00
|
|
|
if (v.startsWith("CMAKE_COMPILER_IS_GNU<LANG>")) { // This key takes a compiler name :-/
|
2019-06-18 11:31:46 +02:00
|
|
|
result << "CMAKE_COMPILER_IS_GNUCC"
|
|
|
|
|
<< "CMAKE_COMPILER_IS_GNUCXX";
|
2023-09-17 20:19:04 +02:00
|
|
|
} else if (v.contains("<CONFIG>") && v.contains("<LANG>")) {
|
|
|
|
|
const QString tmp = QString(v).replace("<CONFIG>", "%1").replace("<LANG>", "%2");
|
|
|
|
|
result << tmp.arg("DEBUG").arg("C") << tmp.arg("DEBUG").arg("CXX")
|
|
|
|
|
<< tmp.arg("RELEASE").arg("C") << tmp.arg("RELEASE").arg("CXX")
|
|
|
|
|
<< tmp.arg("MINSIZEREL").arg("C") << tmp.arg("MINSIZEREL").arg("CXX")
|
|
|
|
|
<< tmp.arg("RELWITHDEBINFO").arg("C") << tmp.arg("RELWITHDEBINFO").arg("CXX");
|
2016-09-14 12:28:14 +02:00
|
|
|
} else if (v.contains("<CONFIG>")) {
|
2016-09-14 12:26:13 +02:00
|
|
|
const QString tmp = QString(v).replace("<CONFIG>", "%1");
|
2019-06-18 11:31:46 +02:00
|
|
|
result << tmp.arg("DEBUG") << tmp.arg("RELEASE") << tmp.arg("MINSIZEREL")
|
|
|
|
|
<< tmp.arg("RELWITHDEBINFO");
|
2016-09-14 12:26:13 +02:00
|
|
|
} else if (v.contains("<LANG>")) {
|
|
|
|
|
const QString tmp = QString(v).replace("<LANG>", "%1");
|
|
|
|
|
result << tmp.arg("C") << tmp.arg("CXX");
|
2016-09-26 16:29:58 +02:00
|
|
|
} else if (!v.contains('<') && !v.contains('[')) {
|
2016-01-22 13:50:58 +01:00
|
|
|
result << v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2012-09-06 22:38:25 +08:00
|
|
|
}
|
2016-02-12 12:30:55 +01:00
|
|
|
|
2023-09-22 22:47:31 +02:00
|
|
|
QStringList CMakeTool::parseSyntaxHighlightingXml()
|
2023-09-17 20:19:04 +02:00
|
|
|
{
|
2023-09-22 22:47:31 +02:00
|
|
|
QStringList moduleFunctions;
|
2023-09-17 20:19:04 +02:00
|
|
|
|
|
|
|
|
const FilePath cmakeXml = Core::ICore::resourcePath("generic-highlighter/syntax/cmake.xml");
|
|
|
|
|
QXmlStreamReader reader(cmakeXml.fileContents().value_or(QByteArray()));
|
|
|
|
|
|
|
|
|
|
auto readItemList = [](QXmlStreamReader &reader) -> QStringList {
|
|
|
|
|
QStringList arguments;
|
|
|
|
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
|
|
|
if (reader.name() == u"item")
|
|
|
|
|
arguments.append(reader.readElementText());
|
|
|
|
|
else
|
|
|
|
|
reader.skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
return arguments;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
|
|
|
if (reader.name() != u"highlighting")
|
|
|
|
|
continue;
|
|
|
|
|
while (!reader.atEnd() && reader.readNextStartElement()) {
|
|
|
|
|
if (reader.name() == u"list") {
|
|
|
|
|
const auto name = reader.attributes().value("name").toString();
|
|
|
|
|
if (name.endsWith(u"_sargs") || name.endsWith(u"_nargs")) {
|
|
|
|
|
const auto functionName = name.left(name.length() - 6);
|
|
|
|
|
QStringList arguments = readItemList(reader);
|
|
|
|
|
|
2023-09-22 22:47:31 +02:00
|
|
|
if (m_introspection->m_keywords.functionArgs.contains(functionName))
|
|
|
|
|
arguments.append(
|
|
|
|
|
m_introspection->m_keywords.functionArgs.value(functionName));
|
2023-09-17 20:19:04 +02:00
|
|
|
|
2023-09-22 22:47:31 +02:00
|
|
|
m_introspection->m_keywords.functionArgs[functionName] = arguments;
|
2023-09-17 20:19:04 +02:00
|
|
|
|
|
|
|
|
// Functions that are part of CMake modules like ExternalProject_Add
|
|
|
|
|
// which are not reported by cmake --help-list-commands
|
2023-09-22 22:47:31 +02:00
|
|
|
if (!m_introspection->m_keywords.functions.contains(functionName)) {
|
|
|
|
|
moduleFunctions << functionName;
|
2023-09-17 20:19:04 +02:00
|
|
|
}
|
|
|
|
|
} else if (name == u"generator-expressions") {
|
2023-09-22 22:47:31 +02:00
|
|
|
m_introspection->m_keywords.generatorExpressions = toSet(readItemList(reader));
|
2023-09-17 20:19:04 +02:00
|
|
|
} else {
|
|
|
|
|
reader.skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
reader.skipCurrentElement();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Some commands have the same arguments as other commands and the `cmake.xml`
|
|
|
|
|
// but their relationship is weirdly defined in the `cmake.xml` file.
|
|
|
|
|
using ListStringPair = QList<QPair<QString, QString>>;
|
|
|
|
|
const ListStringPair functionPairs = {{"if", "elseif"},
|
|
|
|
|
{"while", "elseif"},
|
|
|
|
|
{"find_path", "find_file"},
|
|
|
|
|
{"find_program", "find_library"},
|
|
|
|
|
{"target_link_libraries", "target_compile_definitions"},
|
|
|
|
|
{"target_link_options", "target_compile_definitions"},
|
|
|
|
|
{"target_link_directories", "target_compile_options"},
|
|
|
|
|
{"set_target_properties", "set_directory_properties"},
|
|
|
|
|
{"set_tests_properties", "set_directory_properties"}};
|
|
|
|
|
for (const auto &pair : std::as_const(functionPairs)) {
|
2023-09-22 22:47:31 +02:00
|
|
|
if (!m_introspection->m_keywords.functionArgs.contains(pair.first))
|
|
|
|
|
m_introspection->m_keywords.functionArgs[pair.first]
|
|
|
|
|
= m_introspection->m_keywords.functionArgs.value(pair.second);
|
2023-09-17 20:19:04 +02:00
|
|
|
}
|
2023-09-19 17:22:19 +02:00
|
|
|
|
|
|
|
|
// Special case for cmake_print_variables, which will print the names and values for variables
|
|
|
|
|
// and needs to be as a known function
|
|
|
|
|
const QString cmakePrintVariables("cmake_print_variables");
|
2023-09-22 22:47:31 +02:00
|
|
|
m_introspection->m_keywords.functionArgs[cmakePrintVariables] = {};
|
|
|
|
|
moduleFunctions << cmakePrintVariables;
|
|
|
|
|
|
|
|
|
|
moduleFunctions.removeDuplicates();
|
|
|
|
|
return moduleFunctions;
|
2023-09-17 20:19:04 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-05 14:11:33 +02:00
|
|
|
void CMakeTool::fetchFromCapabilities(bool ignoreCache) const
|
2016-09-28 15:18:29 +02:00
|
|
|
{
|
2023-09-05 14:11:33 +02:00
|
|
|
expected_str<Utils::Store> cache = PersistentCacheStore::byKey(
|
|
|
|
|
keyFromString("CMake_" + cmakeExecutable().toUserOutput()));
|
|
|
|
|
|
|
|
|
|
if (cache && !ignoreCache) {
|
2023-09-28 15:48:11 +02:00
|
|
|
m_introspection->m_haveCapabilitites = true;
|
2023-09-05 14:11:33 +02:00
|
|
|
parseFromCapabilities(cache->value("CleanedStdOut").toString());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process cmake;
|
2021-05-12 14:25:50 +02:00
|
|
|
runCMake(cmake, {"-E", "capabilities"});
|
2016-09-28 15:18:29 +02:00
|
|
|
|
2022-03-02 04:12:25 +01:00
|
|
|
if (cmake.result() == ProcessResult::FinishedWithSuccess) {
|
2023-09-28 15:48:11 +02:00
|
|
|
m_introspection->m_haveCapabilitites = true;
|
2022-06-17 14:17:14 +02:00
|
|
|
parseFromCapabilities(cmake.cleanedStdOut());
|
2020-04-03 11:16:48 +02:00
|
|
|
} else {
|
2022-04-07 14:04:20 +02:00
|
|
|
qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.allOutput() << cmake.error();
|
2023-09-28 15:48:11 +02:00
|
|
|
m_introspection->m_haveCapabilitites = false;
|
2020-04-03 11:16:48 +02:00
|
|
|
}
|
2023-09-05 14:11:33 +02:00
|
|
|
|
|
|
|
|
Store newData{{"CleanedStdOut", cmake.cleanedStdOut()}};
|
|
|
|
|
const auto result
|
|
|
|
|
= PersistentCacheStore::write(keyFromString("CMake_" + cmakeExecutable().toUserOutput()),
|
|
|
|
|
newData);
|
|
|
|
|
QTC_ASSERT_EXPECTED(result, return);
|
2018-07-10 14:03:55 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-11 11:06:32 +02:00
|
|
|
static int getVersion(const QVariantMap &obj, const QString value)
|
|
|
|
|
{
|
|
|
|
|
bool ok;
|
2019-06-18 14:30:58 +02:00
|
|
|
int result = obj.value(value).toInt(&ok);
|
2019-06-11 11:06:32 +02:00
|
|
|
if (!ok)
|
|
|
|
|
return -1;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 14:03:55 +02:00
|
|
|
void CMakeTool::parseFromCapabilities(const QString &input) const
|
|
|
|
|
{
|
|
|
|
|
auto doc = QJsonDocument::fromJson(input.toUtf8());
|
2016-09-28 15:18:29 +02:00
|
|
|
if (!doc.isObject())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const QVariantMap data = doc.object().toVariantMap();
|
|
|
|
|
const QVariantList generatorList = data.value("generators").toList();
|
|
|
|
|
for (const QVariant &v : generatorList) {
|
|
|
|
|
const QVariantMap gen = v.toMap();
|
2018-07-10 14:17:12 +02:00
|
|
|
m_introspection->m_generators.append(Generator(gen.value("name").toString(),
|
|
|
|
|
gen.value("extraGenerators").toStringList(),
|
|
|
|
|
gen.value("platformSupport").toBool(),
|
|
|
|
|
gen.value("toolsetSupport").toBool()));
|
2016-09-28 12:24:06 +02:00
|
|
|
}
|
2016-09-28 17:25:29 +02:00
|
|
|
|
2023-09-05 14:11:33 +02:00
|
|
|
const QVariantMap fileApis = data.value("fileApi").toMap();
|
|
|
|
|
const QVariantList requests = fileApis.value("requests").toList();
|
|
|
|
|
for (const QVariant &r : requests) {
|
|
|
|
|
const QVariantMap object = r.toMap();
|
|
|
|
|
const QString kind = object.value("kind").toString();
|
|
|
|
|
const QVariantList versionList = object.value("version").toList();
|
|
|
|
|
std::pair<int, int> highestVersion{-1, -1};
|
|
|
|
|
for (const QVariant &v : versionList) {
|
|
|
|
|
const QVariantMap versionObject = v.toMap();
|
|
|
|
|
const std::pair<int, int> version{getVersion(versionObject, "major"),
|
|
|
|
|
getVersion(versionObject, "minor")};
|
|
|
|
|
if (version.first > highestVersion.first
|
|
|
|
|
|| (version.first == highestVersion.first && version.second > highestVersion.second))
|
|
|
|
|
highestVersion = version;
|
2019-06-11 11:06:32 +02:00
|
|
|
}
|
2023-09-05 14:11:33 +02:00
|
|
|
if (!kind.isNull() && highestVersion.first != -1 && highestVersion.second != -1)
|
|
|
|
|
m_introspection->m_fileApis.append({kind, highestVersion});
|
2019-06-11 11:06:32 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-28 17:25:29 +02:00
|
|
|
const QVariantMap versionInfo = data.value("version").toMap();
|
2018-07-10 14:17:12 +02:00
|
|
|
m_introspection->m_version.major = versionInfo.value("major").toInt();
|
|
|
|
|
m_introspection->m_version.minor = versionInfo.value("minor").toInt();
|
|
|
|
|
m_introspection->m_version.patch = versionInfo.value("patch").toInt();
|
|
|
|
|
m_introspection->m_version.fullVersion = versionInfo.value("string").toByteArray();
|
2016-09-28 12:24:06 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-12 12:30:55 +01:00
|
|
|
} // namespace CMakeProjectManager
|