2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 Canonical 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
|
2015-02-04 17:54:46 +01:00
|
|
|
|
|
|
|
|
#include "cmaketoolmanager.h"
|
|
|
|
|
|
2023-08-23 10:16:28 +02:00
|
|
|
#include "cmakekitaspect.h"
|
2022-09-29 15:26:31 +02:00
|
|
|
#include "cmakeprojectmanagertr.h"
|
2022-12-12 20:02:01 +01:00
|
|
|
#include "cmakespecificsettings.h"
|
2018-07-02 13:55:58 +02:00
|
|
|
#include "cmaketoolsettingsaccessor.h"
|
|
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
#include "3rdparty/rstparser/rstparser.h"
|
|
|
|
|
|
2021-05-17 13:49:43 +02:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
|
2019-10-10 11:30:51 +02:00
|
|
|
#include <coreplugin/helpmanager.h>
|
2015-02-04 17:54:46 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2018-06-29 13:39:26 +02:00
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
#include <projectexplorer/buildsystem.h>
|
|
|
|
|
#include <projectexplorer/projecttree.h>
|
|
|
|
|
#include <projectexplorer/target.h>
|
2024-01-30 14:33:19 +01:00
|
|
|
|
2021-07-12 14:23:06 +02:00
|
|
|
#include <utils/environment.h>
|
2018-06-29 15:06:17 +02:00
|
|
|
#include <utils/pointeralgorithm.h>
|
2015-02-04 17:54:46 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
2023-08-30 15:04:29 +02:00
|
|
|
#include <nanotrace/nanotrace.h>
|
|
|
|
|
|
2024-01-31 09:49:56 +01:00
|
|
|
#include <QCryptographicHash>
|
|
|
|
|
#include <QStandardPaths>
|
2024-01-30 14:33:19 +01:00
|
|
|
#include <stack>
|
|
|
|
|
|
2024-01-31 09:49:56 +01:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
#include <qt_windows.h>
|
|
|
|
|
#include <winioctl.h>
|
|
|
|
|
|
|
|
|
|
// taken from qtbase/src/corelib/io/qfilesystemengine_win.cpp
|
|
|
|
|
#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE)
|
|
|
|
|
typedef struct _REPARSE_DATA_BUFFER {
|
|
|
|
|
ULONG ReparseTag;
|
|
|
|
|
USHORT ReparseDataLength;
|
|
|
|
|
USHORT Reserved;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
USHORT SubstituteNameOffset;
|
|
|
|
|
USHORT SubstituteNameLength;
|
|
|
|
|
USHORT PrintNameOffset;
|
|
|
|
|
USHORT PrintNameLength;
|
|
|
|
|
ULONG Flags;
|
|
|
|
|
WCHAR PathBuffer[1];
|
|
|
|
|
} SymbolicLinkReparseBuffer;
|
|
|
|
|
struct {
|
|
|
|
|
USHORT SubstituteNameOffset;
|
|
|
|
|
USHORT SubstituteNameLength;
|
|
|
|
|
USHORT PrintNameOffset;
|
|
|
|
|
USHORT PrintNameLength;
|
|
|
|
|
WCHAR PathBuffer[1];
|
|
|
|
|
} MountPointReparseBuffer;
|
|
|
|
|
struct {
|
|
|
|
|
UCHAR DataBuffer[1];
|
|
|
|
|
} GenericReparseBuffer;
|
|
|
|
|
};
|
|
|
|
|
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
|
|
|
|
# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
|
|
|
|
|
#endif // !defined(REPARSE_DATA_BUFFER_HEADER_SIZE)
|
|
|
|
|
|
|
|
|
|
#ifndef FSCTL_SET_REPARSE_POINT
|
|
|
|
|
#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM,41,METHOD_BUFFERED,FILE_ANY_ACCESS)
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
using namespace Core;
|
2020-06-26 13:59:38 +02:00
|
|
|
using namespace Utils;
|
2015-02-04 17:54:46 +01:00
|
|
|
|
|
|
|
|
namespace CMakeProjectManager {
|
|
|
|
|
|
2024-01-31 09:49:56 +01:00
|
|
|
static Q_LOGGING_CATEGORY(cmakeToolManagerLog, "qtc.cmake.toolmanager", QtWarningMsg);
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
class CMakeToolManagerPrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Id m_defaultCMake;
|
2018-06-29 15:06:17 +02:00
|
|
|
std::vector<std::unique_ptr<CMakeTool>> m_cmakeTools;
|
2018-07-02 13:55:58 +02:00
|
|
|
Internal::CMakeToolSettingsAccessor m_accessor;
|
2024-01-31 09:49:56 +01:00
|
|
|
FilePath m_junctionsDir;
|
|
|
|
|
int m_junctionsHashLength = 32;
|
|
|
|
|
|
|
|
|
|
CMakeToolManagerPrivate();
|
2015-02-04 17:54:46 +01:00
|
|
|
};
|
2018-06-29 13:20:59 +02:00
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
class HtmlHandler : public rst::ContentHandler
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
std::stack<QString> m_tags;
|
|
|
|
|
|
|
|
|
|
QStringList m_p;
|
|
|
|
|
QStringList m_h3;
|
|
|
|
|
QStringList m_cmake_code;
|
|
|
|
|
|
|
|
|
|
QString m_last_directive_type;
|
|
|
|
|
QString m_last_directive_class;
|
|
|
|
|
|
|
|
|
|
void StartBlock(rst::BlockType type) final
|
|
|
|
|
{
|
|
|
|
|
QString tag;
|
|
|
|
|
switch (type) {
|
|
|
|
|
case rst::REFERENCE_LINK:
|
|
|
|
|
// not used, HandleReferenceLink is used instead
|
|
|
|
|
break;
|
|
|
|
|
case rst::H1:
|
|
|
|
|
tag = "h1";
|
|
|
|
|
break;
|
|
|
|
|
case rst::H2:
|
|
|
|
|
tag = "h2";
|
|
|
|
|
break;
|
|
|
|
|
case rst::H3:
|
|
|
|
|
tag = "h3";
|
|
|
|
|
break;
|
|
|
|
|
case rst::H4:
|
|
|
|
|
tag = "h4";
|
|
|
|
|
break;
|
|
|
|
|
case rst::H5:
|
|
|
|
|
tag = "h5";
|
|
|
|
|
break;
|
|
|
|
|
case rst::CODE:
|
|
|
|
|
tag = "code";
|
|
|
|
|
break;
|
|
|
|
|
case rst::PARAGRAPH:
|
|
|
|
|
tag = "p";
|
|
|
|
|
break;
|
|
|
|
|
case rst::LINE_BLOCK:
|
|
|
|
|
tag = "pre";
|
|
|
|
|
break;
|
|
|
|
|
case rst::BLOCK_QUOTE:
|
|
|
|
|
if (m_last_directive_type == "code-block" && m_last_directive_class == "cmake")
|
|
|
|
|
tag = "cmake-code";
|
|
|
|
|
else
|
|
|
|
|
tag = "blockquote";
|
|
|
|
|
break;
|
|
|
|
|
case rst::BULLET_LIST:
|
|
|
|
|
tag = "ul";
|
|
|
|
|
break;
|
|
|
|
|
case rst::LIST_ITEM:
|
|
|
|
|
tag = "li";
|
|
|
|
|
break;
|
|
|
|
|
case rst::LITERAL_BLOCK:
|
|
|
|
|
tag = "pre";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tag == "p")
|
|
|
|
|
m_p.push_back(QString());
|
|
|
|
|
if (tag == "h3")
|
|
|
|
|
m_h3.push_back(QString());
|
|
|
|
|
if (tag == "cmake-code")
|
|
|
|
|
m_cmake_code.push_back(QString());
|
|
|
|
|
|
|
|
|
|
if (tag == "code" && m_tags.top() == "p")
|
|
|
|
|
m_p.last().append("`");
|
|
|
|
|
|
|
|
|
|
m_tags.push(tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EndBlock() final
|
|
|
|
|
{
|
|
|
|
|
// Add a new "p" collector for any `code` markup that comes afterwads
|
|
|
|
|
// since we are insterested only in the first paragraph.
|
|
|
|
|
if (m_tags.top() == "p")
|
|
|
|
|
m_p.push_back(QString());
|
|
|
|
|
|
|
|
|
|
if (m_tags.top() == "code" && !m_p.isEmpty()) {
|
|
|
|
|
m_tags.pop();
|
|
|
|
|
|
|
|
|
|
if (m_tags.size() > 0 && m_tags.top() == "p")
|
|
|
|
|
m_p.last().append("`");
|
|
|
|
|
} else {
|
|
|
|
|
m_tags.pop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HandleText(const char *text, std::size_t size) final
|
|
|
|
|
{
|
|
|
|
|
if (m_last_directive_type.endsWith("replace"))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QString str = QString::fromUtf8(text, size);
|
|
|
|
|
|
|
|
|
|
if (m_tags.top() == "h3")
|
|
|
|
|
m_h3.last().append(str);
|
|
|
|
|
if (m_tags.top() == "p")
|
|
|
|
|
m_p.last().append(str);
|
|
|
|
|
if (m_tags.top() == "cmake-code")
|
|
|
|
|
m_cmake_code.last().append(str);
|
|
|
|
|
if (m_tags.top() == "code" && !m_p.isEmpty())
|
|
|
|
|
m_p.last().append(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HandleDirective(const std::string &type, const std::string &name) final
|
|
|
|
|
{
|
|
|
|
|
m_last_directive_type = QString::fromStdString(type);
|
|
|
|
|
m_last_directive_class = QString::fromStdString(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HandleReferenceLink(const std::string &type, const std::string &text) final
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(type)
|
|
|
|
|
if (!m_p.isEmpty())
|
|
|
|
|
m_p.last().append(QString::fromStdString(text));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
QString content() const
|
|
|
|
|
{
|
|
|
|
|
const QString title = m_h3.isEmpty() ? QString() : m_h3.first();
|
|
|
|
|
const QString description = m_p.isEmpty() ? QString() : m_p.first();
|
|
|
|
|
const QString cmakeCode = m_cmake_code.isEmpty() ? QString() : m_cmake_code.first();
|
|
|
|
|
|
|
|
|
|
return QString("### %1\n\n%2\n\n````\n%3\n````").arg(title, description, cmakeCode);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-29 15:26:31 +02:00
|
|
|
static CMakeToolManagerPrivate *d = nullptr;
|
2024-01-29 14:17:23 +01:00
|
|
|
static CMakeToolManager *m_instance = nullptr;
|
2015-02-24 21:57:00 +01:00
|
|
|
|
2019-03-19 15:36:07 +01:00
|
|
|
CMakeToolManager::CMakeToolManager()
|
2015-02-04 17:54:46 +01:00
|
|
|
{
|
2021-07-12 14:23:06 +02:00
|
|
|
qRegisterMetaType<QString *>();
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
d = new CMakeToolManagerPrivate;
|
|
|
|
|
connect(ICore::instance(), &ICore::saveSettingsRequested,
|
|
|
|
|
this, &CMakeToolManager::saveCMakeTools);
|
2015-02-24 21:57:00 +01:00
|
|
|
|
|
|
|
|
connect(this, &CMakeToolManager::cmakeAdded, this, &CMakeToolManager::cmakeToolsChanged);
|
|
|
|
|
connect(this, &CMakeToolManager::cmakeRemoved, this, &CMakeToolManager::cmakeToolsChanged);
|
|
|
|
|
connect(this, &CMakeToolManager::cmakeUpdated, this, &CMakeToolManager::cmakeToolsChanged);
|
2021-05-17 13:49:43 +02:00
|
|
|
|
|
|
|
|
setObjectName("CMakeToolManager");
|
|
|
|
|
ExtensionSystem::PluginManager::addObject(this);
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CMakeToolManager::~CMakeToolManager()
|
|
|
|
|
{
|
2021-05-17 13:49:43 +02:00
|
|
|
ExtensionSystem::PluginManager::removeObject(this);
|
2015-02-04 17:54:46 +01:00
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 21:57:00 +01:00
|
|
|
CMakeToolManager *CMakeToolManager::instance()
|
|
|
|
|
{
|
|
|
|
|
return m_instance;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
QList<CMakeTool *> CMakeToolManager::cmakeTools()
|
|
|
|
|
{
|
2018-06-29 15:06:17 +02:00
|
|
|
return Utils::toRawPointer<QList>(d->m_cmakeTools);
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
2018-06-29 15:06:17 +02:00
|
|
|
bool CMakeToolManager::registerCMakeTool(std::unique_ptr<CMakeTool> &&tool)
|
2015-02-04 17:54:46 +01:00
|
|
|
{
|
2018-06-29 15:06:17 +02:00
|
|
|
if (!tool || Utils::contains(d->m_cmakeTools, tool.get()))
|
2015-02-04 17:54:46 +01:00
|
|
|
return true;
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
const Utils::Id toolId = tool->id();
|
2018-06-29 13:53:08 +02:00
|
|
|
QTC_ASSERT(toolId.isValid(),return false);
|
2015-02-04 17:54:46 +01:00
|
|
|
|
|
|
|
|
//make sure the same id was not used before
|
2018-06-29 15:06:17 +02:00
|
|
|
QTC_ASSERT(!Utils::contains(d->m_cmakeTools, [toolId](const std::unique_ptr<CMakeTool> &known) {
|
2018-06-29 13:53:08 +02:00
|
|
|
return toolId == known->id();
|
|
|
|
|
}), return false);
|
2015-02-04 17:54:46 +01:00
|
|
|
|
2018-06-29 15:06:17 +02:00
|
|
|
d->m_cmakeTools.emplace_back(std::move(tool));
|
2018-06-29 13:48:37 +02:00
|
|
|
|
2024-01-29 14:17:23 +01:00
|
|
|
emit m_instance->cmakeAdded(toolId);
|
2018-06-29 13:48:37 +02:00
|
|
|
|
2018-06-29 14:02:22 +02:00
|
|
|
ensureDefaultCMakeToolIsValid();
|
2018-06-29 13:48:37 +02:00
|
|
|
|
2019-10-10 11:30:51 +02:00
|
|
|
updateDocumentation();
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMakeToolManager::deregisterCMakeTool(const Id &id)
|
|
|
|
|
{
|
2018-06-29 15:06:17 +02:00
|
|
|
auto toRemove = Utils::take(d->m_cmakeTools, Utils::equal(&CMakeTool::id, id));
|
|
|
|
|
if (toRemove.has_value()) {
|
2018-06-29 14:02:22 +02:00
|
|
|
ensureDefaultCMakeToolIsValid();
|
2015-02-24 21:57:00 +01:00
|
|
|
|
2019-10-10 11:30:51 +02:00
|
|
|
updateDocumentation();
|
|
|
|
|
|
2015-02-24 21:57:00 +01:00
|
|
|
emit m_instance->cmakeRemoved(id);
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
CMakeTool *CMakeToolManager::defaultProjectOrDefaultCMakeTool()
|
|
|
|
|
{
|
2023-10-02 14:25:58 +02:00
|
|
|
CMakeTool *tool = nullptr;
|
2023-09-25 23:08:38 +02:00
|
|
|
|
2023-10-02 14:25:58 +02:00
|
|
|
if (auto bs = ProjectExplorer::ProjectTree::currentBuildSystem())
|
|
|
|
|
tool = CMakeKitAspect::cmakeTool(bs->target()->kit());
|
2023-09-25 23:08:38 +02:00
|
|
|
if (!tool)
|
2023-10-02 14:25:58 +02:00
|
|
|
tool = CMakeToolManager::defaultCMakeTool();
|
2023-09-25 23:08:38 +02:00
|
|
|
|
|
|
|
|
return tool;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
CMakeTool *CMakeToolManager::defaultCMakeTool()
|
|
|
|
|
{
|
2018-06-29 14:02:22 +02:00
|
|
|
return findById(d->m_defaultCMake);
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMakeToolManager::setDefaultCMakeTool(const Id &id)
|
|
|
|
|
{
|
2018-06-29 14:02:22 +02:00
|
|
|
if (d->m_defaultCMake != id && findById(id)) {
|
2015-02-04 17:54:46 +01:00
|
|
|
d->m_defaultCMake = id;
|
2015-02-24 21:57:00 +01:00
|
|
|
emit m_instance->defaultCMakeChanged();
|
2018-06-29 14:02:22 +02:00
|
|
|
return;
|
2015-02-24 21:57:00 +01:00
|
|
|
}
|
2018-06-29 14:02:22 +02:00
|
|
|
|
|
|
|
|
ensureDefaultCMakeToolIsValid();
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
2020-04-17 15:30:05 +02:00
|
|
|
CMakeTool *CMakeToolManager::findByCommand(const Utils::FilePath &command)
|
2015-02-04 17:54:46 +01:00
|
|
|
{
|
|
|
|
|
return Utils::findOrDefault(d->m_cmakeTools, Utils::equal(&CMakeTool::cmakeExecutable, command));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CMakeTool *CMakeToolManager::findById(const Id &id)
|
|
|
|
|
{
|
|
|
|
|
return Utils::findOrDefault(d->m_cmakeTools, Utils::equal(&CMakeTool::id, id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMakeToolManager::restoreCMakeTools()
|
|
|
|
|
{
|
2023-08-30 15:04:29 +02:00
|
|
|
NANOTRACE_SCOPE("CMakeProjectManager", "CMakeToolManager::restoreCMakeTools");
|
2018-07-02 13:55:58 +02:00
|
|
|
Internal::CMakeToolSettingsAccessor::CMakeTools tools
|
|
|
|
|
= d->m_accessor.restoreCMakeTools(ICore::dialogParent());
|
|
|
|
|
d->m_cmakeTools = std::move(tools.cmakeTools);
|
|
|
|
|
setDefaultCMakeTool(tools.defaultToolId);
|
2015-02-04 17:54:46 +01:00
|
|
|
|
2019-10-10 11:30:51 +02:00
|
|
|
updateDocumentation();
|
|
|
|
|
|
2015-03-10 15:47:09 +01:00
|
|
|
emit m_instance->cmakeToolsLoaded();
|
2022-12-12 20:02:01 +01:00
|
|
|
|
|
|
|
|
// Store the default CMake tool "Autorun CMake" value globally
|
2023-05-08 14:28:20 +02:00
|
|
|
// TODO: Remove in Qt Creator 13
|
2023-07-06 17:06:20 +02:00
|
|
|
Internal::CMakeSpecificSettings &s = Internal::settings();
|
|
|
|
|
if (s.autorunCMake() == s.autorunCMake.defaultValue()) {
|
2022-12-12 20:02:01 +01:00
|
|
|
CMakeTool *cmake = defaultCMakeTool();
|
2023-07-06 17:06:20 +02:00
|
|
|
s.autorunCMake.setValue(cmake ? cmake->isAutoRun() : true);
|
|
|
|
|
s.writeSettings();
|
2022-12-12 20:02:01 +01:00
|
|
|
}
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-10 11:30:51 +02:00
|
|
|
void CMakeToolManager::updateDocumentation()
|
|
|
|
|
{
|
|
|
|
|
const QList<CMakeTool *> tools = cmakeTools();
|
|
|
|
|
QStringList docs;
|
|
|
|
|
for (const auto tool : tools) {
|
|
|
|
|
if (!tool->qchFilePath().isEmpty())
|
|
|
|
|
docs.append(tool->qchFilePath().toString());
|
|
|
|
|
}
|
|
|
|
|
Core::HelpManager::registerDocumentation(docs);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-31 09:49:56 +01:00
|
|
|
static void createJunction(const FilePath &from, const FilePath &to)
|
|
|
|
|
{
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
to.createDir();
|
|
|
|
|
const QString toString = to.path();
|
|
|
|
|
|
|
|
|
|
HANDLE handle = ::CreateFile((wchar_t *) toString.utf16(),
|
|
|
|
|
GENERIC_WRITE,
|
|
|
|
|
0,
|
|
|
|
|
nullptr,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
|
|
|
|
nullptr);
|
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
|
|
|
qCDebug(cmakeToolManagerLog())
|
|
|
|
|
<< "Failed to open" << toString << "to create a junction." << ::GetLastError();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString fromString("\\??\\");
|
|
|
|
|
fromString.append(from.absoluteFilePath().nativePath());
|
|
|
|
|
|
|
|
|
|
auto fromStringLength = uint16_t(fromString.length() * sizeof(wchar_t));
|
|
|
|
|
auto toStringLength = uint16_t(toString.length() * sizeof(wchar_t));
|
|
|
|
|
auto reparseDataLength = fromStringLength + toStringLength + 12;
|
|
|
|
|
|
|
|
|
|
std::vector<char> buf(reparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE, 0);
|
|
|
|
|
REPARSE_DATA_BUFFER &reparse = *reinterpret_cast<REPARSE_DATA_BUFFER *>(buf.data());
|
|
|
|
|
|
|
|
|
|
reparse.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
|
|
|
|
reparse.ReparseDataLength = reparseDataLength;
|
|
|
|
|
|
|
|
|
|
reparse.MountPointReparseBuffer.SubstituteNameOffset = 0;
|
|
|
|
|
reparse.MountPointReparseBuffer.SubstituteNameLength = fromStringLength;
|
|
|
|
|
fromString.toWCharArray(reparse.MountPointReparseBuffer.PathBuffer);
|
|
|
|
|
|
|
|
|
|
reparse.MountPointReparseBuffer.PrintNameOffset = fromStringLength + sizeof(UNICODE_NULL);
|
|
|
|
|
reparse.MountPointReparseBuffer.PrintNameLength = toStringLength;
|
|
|
|
|
toString.toWCharArray(reparse.MountPointReparseBuffer.PathBuffer + fromString.length() + 1);
|
|
|
|
|
|
|
|
|
|
DWORD retsize = 0;
|
|
|
|
|
if (!::DeviceIoControl(handle,
|
|
|
|
|
FSCTL_SET_REPARSE_POINT,
|
|
|
|
|
&reparse,
|
|
|
|
|
uint16_t(buf.size()),
|
|
|
|
|
nullptr,
|
|
|
|
|
0,
|
|
|
|
|
&retsize,
|
|
|
|
|
nullptr)) {
|
|
|
|
|
qCDebug(cmakeToolManagerLog()) << "Failed to create junction from" << fromString << "to"
|
|
|
|
|
<< toString << "GetLastError:" << ::GetLastError();
|
|
|
|
|
}
|
|
|
|
|
::CloseHandle(handle);
|
|
|
|
|
#else
|
|
|
|
|
Q_UNUSED(from)
|
|
|
|
|
Q_UNUSED(to)
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
QString CMakeToolManager::toolTipForRstHelpFile(const FilePath &helpFile)
|
2023-09-27 13:01:18 +02:00
|
|
|
{
|
2023-09-25 23:08:38 +02:00
|
|
|
static QHash<FilePath, QString> map;
|
2023-09-28 15:48:11 +02:00
|
|
|
static QMutex mutex;
|
|
|
|
|
QMutexLocker locker(&mutex);
|
|
|
|
|
|
2023-09-27 13:01:18 +02:00
|
|
|
if (map.contains(helpFile))
|
|
|
|
|
return map.value(helpFile);
|
|
|
|
|
|
|
|
|
|
auto content = helpFile.fileContents(1024).value_or(QByteArray());
|
2023-09-25 23:08:38 +02:00
|
|
|
content.replace("\r\n", "\n");
|
2023-09-27 13:01:18 +02:00
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
HtmlHandler handler;
|
|
|
|
|
rst::Parser parser(&handler);
|
|
|
|
|
parser.Parse(content.left(content.lastIndexOf('\n')));
|
2023-09-27 13:01:18 +02:00
|
|
|
|
2023-09-25 23:08:38 +02:00
|
|
|
const QString tooltip = handler.content();
|
|
|
|
|
|
|
|
|
|
map[helpFile] = tooltip;
|
|
|
|
|
return tooltip;
|
|
|
|
|
}
|
2023-09-27 13:01:18 +02:00
|
|
|
|
2024-01-31 09:49:56 +01:00
|
|
|
FilePath CMakeToolManager::mappedFilePath(const FilePath &path)
|
|
|
|
|
{
|
|
|
|
|
if (!HostOsInfo::isWindowsHost())
|
|
|
|
|
return path;
|
|
|
|
|
|
|
|
|
|
if (path.needsDevice())
|
|
|
|
|
return path;
|
|
|
|
|
|
|
|
|
|
Internal::settings();
|
|
|
|
|
if (!Internal::settings().useJunctionsForSourceAndBuildDirectories())
|
|
|
|
|
return path;
|
|
|
|
|
|
|
|
|
|
if (!d->m_junctionsDir.isDir())
|
|
|
|
|
return path;
|
|
|
|
|
|
|
|
|
|
const auto hashPath = QString::fromUtf8(
|
|
|
|
|
QCryptographicHash::hash(path.path().toUtf8(), QCryptographicHash::Md5).toHex(0));
|
|
|
|
|
const auto fullHashPath = d->m_junctionsDir.pathAppended(
|
|
|
|
|
hashPath.left(d->m_junctionsHashLength));
|
|
|
|
|
|
|
|
|
|
if (!fullHashPath.exists())
|
|
|
|
|
createJunction(path, fullHashPath);
|
|
|
|
|
|
|
|
|
|
return fullHashPath.exists() ? fullHashPath : path;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-07 14:04:20 +02:00
|
|
|
QList<Id> CMakeToolManager::autoDetectCMakeForDevice(const FilePaths &searchPaths,
|
2021-07-12 14:23:06 +02:00
|
|
|
const QString &detectionSource,
|
|
|
|
|
QString *logMessage)
|
|
|
|
|
{
|
2022-04-07 14:04:20 +02:00
|
|
|
QList<Id> result;
|
2022-09-29 15:26:31 +02:00
|
|
|
QStringList messages{Tr::tr("Searching CMake binaries...")};
|
2021-12-03 10:21:57 +01:00
|
|
|
for (const FilePath &path : searchPaths) {
|
|
|
|
|
const FilePath cmake = path.pathAppended("cmake").withExecutableSuffix();
|
|
|
|
|
if (cmake.isExecutableFile()) {
|
2022-04-07 14:04:20 +02:00
|
|
|
const Id currentId = registerCMakeByPath(cmake, detectionSource);
|
|
|
|
|
if (currentId.isValid())
|
|
|
|
|
result.push_back(currentId);
|
2022-09-29 15:26:31 +02:00
|
|
|
messages.append(Tr::tr("Found \"%1\"").arg(cmake.toUserOutput()));
|
2021-07-12 14:23:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (logMessage)
|
|
|
|
|
*logMessage = messages.join('\n');
|
2022-04-07 14:04:20 +02:00
|
|
|
|
|
|
|
|
return result;
|
2021-07-12 14:23:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-04-07 14:04:20 +02:00
|
|
|
Id CMakeToolManager::registerCMakeByPath(const FilePath &cmakePath, const QString &detectionSource)
|
2021-05-17 13:49:43 +02:00
|
|
|
{
|
2022-04-07 14:04:20 +02:00
|
|
|
Id id = Id::fromString(cmakePath.toUserOutput());
|
2021-05-17 13:49:43 +02:00
|
|
|
|
|
|
|
|
CMakeTool *cmakeTool = findById(id);
|
|
|
|
|
if (cmakeTool)
|
2022-04-07 14:04:20 +02:00
|
|
|
return cmakeTool->id();
|
2021-05-17 13:49:43 +02:00
|
|
|
|
|
|
|
|
auto newTool = std::make_unique<CMakeTool>(CMakeTool::ManualDetection, id);
|
|
|
|
|
newTool->setFilePath(cmakePath);
|
2021-06-22 14:08:20 +02:00
|
|
|
newTool->setDetectionSource(detectionSource);
|
2021-07-13 13:05:36 +02:00
|
|
|
newTool->setDisplayName(cmakePath.toUserOutput());
|
2022-04-07 14:04:20 +02:00
|
|
|
id = newTool->id();
|
2021-05-17 13:49:43 +02:00
|
|
|
registerCMakeTool(std::move(newTool));
|
2022-04-07 14:04:20 +02:00
|
|
|
|
|
|
|
|
return id;
|
2021-05-17 13:49:43 +02:00
|
|
|
}
|
|
|
|
|
|
2021-07-13 13:05:36 +02:00
|
|
|
void CMakeToolManager::removeDetectedCMake(const QString &detectionSource, QString *logMessage)
|
|
|
|
|
{
|
2022-09-29 15:26:31 +02:00
|
|
|
QStringList logMessages{Tr::tr("Removing CMake entries...")};
|
2021-07-13 13:05:36 +02:00
|
|
|
while (true) {
|
|
|
|
|
auto toRemove = Utils::take(d->m_cmakeTools, Utils::equal(&CMakeTool::detectionSource, detectionSource));
|
|
|
|
|
if (!toRemove.has_value())
|
|
|
|
|
break;
|
2022-09-29 15:26:31 +02:00
|
|
|
logMessages.append(Tr::tr("Removed \"%1\"").arg((*toRemove)->displayName()));
|
2021-07-13 13:05:36 +02:00
|
|
|
emit m_instance->cmakeRemoved((*toRemove)->id());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ensureDefaultCMakeToolIsValid();
|
|
|
|
|
updateDocumentation();
|
|
|
|
|
if (logMessage)
|
|
|
|
|
*logMessage = logMessages.join('\n');
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-15 12:25:23 +02:00
|
|
|
void CMakeToolManager::listDetectedCMake(const QString &detectionSource, QString *logMessage)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(logMessage, return);
|
2022-09-29 15:26:31 +02:00
|
|
|
QStringList logMessages{Tr::tr("CMake:")};
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const auto &tool : std::as_const(d->m_cmakeTools)) {
|
2021-07-15 12:25:23 +02:00
|
|
|
if (tool->detectionSource() == detectionSource)
|
|
|
|
|
logMessages.append(tool->displayName());
|
|
|
|
|
}
|
|
|
|
|
*logMessage = logMessages.join('\n');
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 21:57:00 +01:00
|
|
|
void CMakeToolManager::notifyAboutUpdate(CMakeTool *tool)
|
|
|
|
|
{
|
2018-06-29 15:06:17 +02:00
|
|
|
if (!tool || !Utils::contains(d->m_cmakeTools, tool))
|
2015-02-24 21:57:00 +01:00
|
|
|
return;
|
|
|
|
|
emit m_instance->cmakeUpdated(tool->id());
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-04 17:54:46 +01:00
|
|
|
void CMakeToolManager::saveCMakeTools()
|
|
|
|
|
{
|
2018-07-02 13:55:58 +02:00
|
|
|
d->m_accessor.saveCMakeTools(cmakeTools(), d->m_defaultCMake, ICore::dialogParent());
|
2015-02-04 17:54:46 +01:00
|
|
|
}
|
|
|
|
|
|
2018-06-29 14:02:22 +02:00
|
|
|
void CMakeToolManager::ensureDefaultCMakeToolIsValid()
|
|
|
|
|
{
|
2020-06-26 13:59:38 +02:00
|
|
|
const Utils::Id oldId = d->m_defaultCMake;
|
2018-06-29 15:06:17 +02:00
|
|
|
if (d->m_cmakeTools.size() == 0) {
|
2020-06-26 13:59:38 +02:00
|
|
|
d->m_defaultCMake = Utils::Id();
|
2018-06-29 14:02:22 +02:00
|
|
|
} else {
|
|
|
|
|
if (findById(d->m_defaultCMake))
|
|
|
|
|
return;
|
2023-10-10 09:45:10 +02:00
|
|
|
auto cmakeTool = Utils::findOrDefault(cmakeTools(), [](CMakeTool *tool) {
|
|
|
|
|
return tool->detectionSource().isEmpty() && !tool->cmakeExecutable().needsDevice();
|
|
|
|
|
});
|
2021-12-09 13:08:25 +01:00
|
|
|
if (cmakeTool)
|
|
|
|
|
d->m_defaultCMake = cmakeTool->id();
|
2018-06-29 14:02:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// signaling:
|
|
|
|
|
if (oldId != d->m_defaultCMake)
|
|
|
|
|
emit m_instance->defaultCMakeChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 14:17:23 +01:00
|
|
|
void Internal::setupCMakeToolManager(QObject *guard)
|
|
|
|
|
{
|
|
|
|
|
m_instance = new CMakeToolManager;
|
|
|
|
|
m_instance->setParent(guard);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-31 09:49:56 +01:00
|
|
|
CMakeToolManagerPrivate::CMakeToolManagerPrivate()
|
|
|
|
|
{
|
|
|
|
|
if (HostOsInfo::isWindowsHost()) {
|
|
|
|
|
const QStringList locations = QStandardPaths::standardLocations(
|
|
|
|
|
QStandardPaths::GenericConfigLocation);
|
|
|
|
|
m_junctionsDir = FilePath::fromString(*std::min_element(locations.begin(), locations.end()))
|
|
|
|
|
.pathAppended("QtCreator/Links");
|
|
|
|
|
|
|
|
|
|
if (Utils::qtcEnvironmentVariableIsSet("QTC_CMAKE_JUNCTIONS_DIR")) {
|
|
|
|
|
m_junctionsDir = FilePath::fromUserInput(
|
|
|
|
|
Utils::qtcEnvironmentVariable("QTC_CMAKE_JUNCTIONS_DIR"));
|
|
|
|
|
}
|
|
|
|
|
if (Utils::qtcEnvironmentVariableIsSet("QTC_CMAKE_JUNCTIONS_HASH_LENGTH")) {
|
|
|
|
|
bool ok = false;
|
|
|
|
|
const int hashLength
|
|
|
|
|
= Utils::qtcEnvironmentVariableIntValue("QTC_CMAKE_JUNCTIONS_HASH_LENGTH", &ok);
|
|
|
|
|
if (ok && hashLength >= 4 && hashLength < 32)
|
|
|
|
|
m_junctionsHashLength = hashLength;
|
|
|
|
|
}
|
|
|
|
|
if (!m_junctionsDir.exists())
|
|
|
|
|
m_junctionsDir.createDir();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 15:26:31 +02:00
|
|
|
} // CMakeProjectManager
|