forked from qt-creator/qt-creator
docker: Correctly initialize Kit during autodetection
* Added returning the Id after detecting CMake so it can be set in the autodetected kit * Trying to keep autodetect from adding the same Qt installation twice if qmake is linked in /bin and /usr/bin * Added FIXME for RunControlPrivate::runConfiguration as it is used after free in rare cases * Fixed IosCompilerDetector to not just run if a device is set * Fixed QnxCompilerDetector to not just run if a device is set * Fixed auto-detected debuggers not being set as auto-detected, as they now can be removed from the device screen Change-Id: Ia7772c454d70e147e4326efacc4a6a888fa26782 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -87,8 +87,6 @@ static Id defaultCMakeToolId()
|
||||
return defaultTool ? defaultTool->id() : Id();
|
||||
}
|
||||
|
||||
const char TOOL_ID[] = "CMakeProjectManager.CMakeKitInformation";
|
||||
|
||||
class CMakeKitAspectWidget final : public KitAspectWidget
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::CMakeKitAspect)
|
||||
@@ -218,7 +216,7 @@ private:
|
||||
CMakeKitAspect::CMakeKitAspect()
|
||||
{
|
||||
setObjectName(QLatin1String("CMakeKitAspect"));
|
||||
setId(TOOL_ID);
|
||||
setId(Constants::TOOL_ID);
|
||||
setDisplayName(tr("CMake Tool"));
|
||||
setDescription(tr("The CMake Tool to use when building a project with CMake.<br>"
|
||||
"This setting is ignored when using other build systems."));
|
||||
@@ -235,14 +233,14 @@ CMakeKitAspect::CMakeKitAspect()
|
||||
|
||||
Id CMakeKitAspect::id()
|
||||
{
|
||||
return TOOL_ID;
|
||||
return Constants::TOOL_ID;
|
||||
}
|
||||
|
||||
Id CMakeKitAspect::cmakeToolId(const Kit *k)
|
||||
{
|
||||
if (!k)
|
||||
return {};
|
||||
return Id::fromSetting(k->value(TOOL_ID));
|
||||
return Id::fromSetting(k->value(Constants::TOOL_ID));
|
||||
}
|
||||
|
||||
CMakeTool *CMakeKitAspect::cmakeTool(const Kit *k)
|
||||
@@ -255,7 +253,7 @@ void CMakeKitAspect::setCMakeTool(Kit *k, const Id id)
|
||||
const Id toSet = id.isValid() ? id : defaultCMakeToolId();
|
||||
QTC_ASSERT(!id.isValid() || CMakeToolManager::findById(toSet), return);
|
||||
if (k)
|
||||
k->setValue(TOOL_ID, toSet.toSetting());
|
||||
k->setValue(Constants::TOOL_ID, toSet.toSetting());
|
||||
}
|
||||
|
||||
Tasks CMakeKitAspect::validate(const Kit *k) const
|
||||
|
||||
@@ -65,5 +65,9 @@ const char CMAKE_BUILD_STEP_ID[] = "CMakeProjectManager.MakeStep";
|
||||
// Features
|
||||
const char CMAKE_FEATURE_ID[] = "CMakeProjectManager.Wizard.FeatureCMake";
|
||||
|
||||
// Tool
|
||||
const char TOOL_ID[] = "CMakeProjectManager.CMakeKitInformation";
|
||||
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLoggingCategory>
|
||||
#include <QRegularExpression>
|
||||
#include <QSet>
|
||||
#include <QUuid>
|
||||
@@ -47,6 +48,9 @@ using namespace Utils;
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
static Q_LOGGING_CATEGORY(cmakeToolLog, "qtc.cmake.tool", QtWarningMsg);
|
||||
|
||||
|
||||
const char CMAKE_INFORMATION_ID[] = "Id";
|
||||
const char CMAKE_INFORMATION_COMMAND[] = "Binary";
|
||||
const char CMAKE_INFORMATION_DISPLAYNAME[] = "DisplayName";
|
||||
@@ -521,6 +525,7 @@ void CMakeTool::fetchFromCapabilities() const
|
||||
m_introspection->m_didRun = true;
|
||||
parseFromCapabilities(cmake.stdOut());
|
||||
} else {
|
||||
qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.allOutput() << cmake.error();
|
||||
m_introspection->m_didRun = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,36 +180,44 @@ void CMakeToolManager::updateDocumentation()
|
||||
Core::HelpManager::registerDocumentation(docs);
|
||||
}
|
||||
|
||||
void CMakeToolManager::autoDetectCMakeForDevice(const FilePaths &searchPaths,
|
||||
QList<Id> CMakeToolManager::autoDetectCMakeForDevice(const FilePaths &searchPaths,
|
||||
const QString &detectionSource,
|
||||
QString *logMessage)
|
||||
{
|
||||
QList<Id> result;
|
||||
QStringList messages{tr("Searching CMake binaries...")};
|
||||
for (const FilePath &path : searchPaths) {
|
||||
const FilePath cmake = path.pathAppended("cmake").withExecutableSuffix();
|
||||
if (cmake.isExecutableFile()) {
|
||||
registerCMakeByPath(cmake, detectionSource);
|
||||
const Id currentId = registerCMakeByPath(cmake, detectionSource);
|
||||
if (currentId.isValid())
|
||||
result.push_back(currentId);
|
||||
messages.append(tr("Found \"%1\"").arg(cmake.toUserOutput()));
|
||||
}
|
||||
}
|
||||
if (logMessage)
|
||||
*logMessage = messages.join('\n');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void CMakeToolManager::registerCMakeByPath(const FilePath &cmakePath, const QString &detectionSource)
|
||||
Id CMakeToolManager::registerCMakeByPath(const FilePath &cmakePath, const QString &detectionSource)
|
||||
{
|
||||
const Id id = Id::fromString(cmakePath.toUserOutput());
|
||||
Id id = Id::fromString(cmakePath.toUserOutput());
|
||||
|
||||
CMakeTool *cmakeTool = findById(id);
|
||||
if (cmakeTool)
|
||||
return;
|
||||
return cmakeTool->id();
|
||||
|
||||
auto newTool = std::make_unique<CMakeTool>(CMakeTool::ManualDetection, id);
|
||||
newTool->setFilePath(cmakePath);
|
||||
newTool->setDetectionSource(detectionSource);
|
||||
newTool->setDisplayName(cmakePath.toUserOutput());
|
||||
id = newTool->id();
|
||||
registerCMakeTool(std::move(newTool));
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void CMakeToolManager::removeDetectedCMake(const QString &detectionSource, QString *logMessage)
|
||||
|
||||
@@ -63,10 +63,10 @@ public:
|
||||
static void updateDocumentation();
|
||||
|
||||
public slots:
|
||||
void autoDetectCMakeForDevice(const Utils::FilePaths &searchPaths,
|
||||
QList<Utils::Id> autoDetectCMakeForDevice(const Utils::FilePaths &searchPaths,
|
||||
const QString &detectionSource,
|
||||
QString *logMessage);
|
||||
void registerCMakeByPath(const Utils::FilePath &cmakePath,
|
||||
Utils::Id registerCMakeByPath(const Utils::FilePath &cmakePath,
|
||||
const QString &detectionSource);
|
||||
void removeDetectedCMake(const QString &detectionSource, QString *logMessage);
|
||||
void listDetectedCMake(const QString &detectionSource, QString *logMessage);
|
||||
|
||||
@@ -796,9 +796,7 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers(const FilePaths &s
|
||||
DebuggerItem item;
|
||||
item.createId();
|
||||
item.setDetectionSource(detectionSource);
|
||||
// Intentionally set items with non-empty source as manual for now to
|
||||
// give the user a chance to remove them. FIXME: Think of a better way.
|
||||
item.setAutoDetected(detectionSource.isEmpty());
|
||||
item.setAutoDetected(true);
|
||||
item.setCommand(command);
|
||||
item.reinitializeFromFile();
|
||||
if (item.engineType() == NoEngineType)
|
||||
@@ -937,7 +935,8 @@ void DebuggerItemManagerPrivate::readDebuggers(const FilePath &fileName, bool is
|
||||
.arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput());
|
||||
continue;
|
||||
}
|
||||
if (!item.command().isExecutableFile()) {
|
||||
// FIXME: During startup, devices are not yet available, so we cannot check if the file still exists.
|
||||
if (!item.command().needsDevice() && !item.command().isExecutableFile()) {
|
||||
qWarning() << QString("DebuggerItem \"%1\" (%2) read from \"%3\" dropped since the command is not executable.")
|
||||
.arg(item.command().toUserOutput(), item.id().toString(), fileName.toUserOutput());
|
||||
continue;
|
||||
|
||||
@@ -74,21 +74,31 @@ bool DockerApi::canConnect()
|
||||
return result;
|
||||
}
|
||||
|
||||
void DockerApi::checkCanConnect()
|
||||
void DockerApi::checkCanConnect(bool async)
|
||||
{
|
||||
std::unique_lock lk(m_daemonCheckGuard, std::try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
return;
|
||||
if (async) {
|
||||
std::unique_lock lk(m_daemonCheckGuard, std::try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
return;
|
||||
|
||||
m_dockerDaemonAvailable = nullopt;
|
||||
dockerDaemonAvailableChanged();
|
||||
|
||||
auto future = Utils::runAsync([lk = std::move(lk), this] {
|
||||
m_dockerDaemonAvailable = canConnect();
|
||||
m_dockerDaemonAvailable = nullopt;
|
||||
dockerDaemonAvailableChanged();
|
||||
});
|
||||
|
||||
Core::ProgressManager::addTask(future, tr("Checking docker daemon"), "DockerPlugin");
|
||||
auto future = Utils::runAsync([lk = std::move(lk), this] {
|
||||
m_dockerDaemonAvailable = canConnect();
|
||||
dockerDaemonAvailableChanged();
|
||||
});
|
||||
|
||||
Core::ProgressManager::addTask(future, tr("Checking docker daemon"), "DockerPlugin");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock lk(m_daemonCheckGuard);
|
||||
bool isAvailable = canConnect();
|
||||
if (!m_dockerDaemonAvailable.has_value() || isAvailable != m_dockerDaemonAvailable) {
|
||||
m_dockerDaemonAvailable = isAvailable;
|
||||
dockerDaemonAvailableChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DockerApi::recheckDockerDaemon()
|
||||
@@ -97,17 +107,17 @@ void DockerApi::recheckDockerDaemon()
|
||||
s_instance->checkCanConnect();
|
||||
}
|
||||
|
||||
Utils::optional<bool> DockerApi::dockerDaemonAvailable()
|
||||
Utils::optional<bool> DockerApi::dockerDaemonAvailable(bool async)
|
||||
{
|
||||
if (!m_dockerDaemonAvailable.has_value())
|
||||
checkCanConnect();
|
||||
checkCanConnect(async);
|
||||
return m_dockerDaemonAvailable;
|
||||
}
|
||||
|
||||
Utils::optional<bool> DockerApi::isDockerDaemonAvailable()
|
||||
Utils::optional<bool> DockerApi::isDockerDaemonAvailable(bool async)
|
||||
{
|
||||
QTC_ASSERT(s_instance, return nullopt);
|
||||
return s_instance->dockerDaemonAvailable();
|
||||
return s_instance->dockerDaemonAvailable(async);
|
||||
}
|
||||
|
||||
FilePath DockerApi::findDockerClient()
|
||||
|
||||
@@ -45,15 +45,15 @@ public:
|
||||
static DockerApi *instance();
|
||||
|
||||
bool canConnect();
|
||||
void checkCanConnect();
|
||||
void checkCanConnect(bool async = true);
|
||||
static void recheckDockerDaemon();
|
||||
|
||||
signals:
|
||||
void dockerDaemonAvailableChanged();
|
||||
|
||||
public:
|
||||
Utils::optional<bool> dockerDaemonAvailable();
|
||||
static Utils::optional<bool> isDockerDaemonAvailable();
|
||||
Utils::optional<bool> dockerDaemonAvailable(bool async = true);
|
||||
static Utils::optional<bool> isDockerDaemonAvailable(bool async = true);
|
||||
|
||||
private:
|
||||
Utils::FilePath findDockerClient();
|
||||
|
||||
@@ -317,7 +317,7 @@ void DockerDevice::updateContainerAccess() const
|
||||
|
||||
void DockerDevicePrivate::stopCurrentContainer()
|
||||
{
|
||||
if (m_container.isEmpty() || !DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||
if (m_container.isEmpty() || !DockerApi::isDockerDaemonAvailable(false).value_or(false))
|
||||
return;
|
||||
|
||||
if (m_shell) {
|
||||
@@ -439,7 +439,7 @@ void DockerDevicePrivate::updateContainerAccess()
|
||||
if (!m_container.isEmpty())
|
||||
return;
|
||||
|
||||
if (DockerApi::isDockerDaemonAvailable().value_or(true) == false)
|
||||
if (DockerApi::isDockerDaemonAvailable(false).value_or(false) == false)
|
||||
return;
|
||||
|
||||
if (m_shell)
|
||||
@@ -897,7 +897,7 @@ bool DockerDevice::writeFileContents(const FilePath &filePath, const QByteArray
|
||||
void DockerDevice::runProcess(QtcProcess &process) const
|
||||
{
|
||||
updateContainerAccess();
|
||||
if (!DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||
if (!DockerApi::isDockerDaemonAvailable(false).value_or(false))
|
||||
return;
|
||||
if (d->m_container.isEmpty()) {
|
||||
LOG("No container set to run " << process.commandLine().toUserOutput());
|
||||
@@ -977,7 +977,7 @@ void DockerDevicePrivate::fetchSystemEnviroment()
|
||||
|
||||
bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
||||
{
|
||||
if (!DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||
if (!DockerApi::isDockerDaemonAvailable(false).value_or(false))
|
||||
return false;
|
||||
CommandLine dcmd{"docker", {"exec", m_container}};
|
||||
dcmd.addCommandLineAsArgs(cmd);
|
||||
@@ -995,7 +995,7 @@ bool DockerDevicePrivate::runInContainer(const CommandLine &cmd) const
|
||||
|
||||
bool DockerDevicePrivate::runInShell(const CommandLine &cmd) const
|
||||
{
|
||||
if (!QTC_GUARD(DockerApi::isDockerDaemonAvailable().value_or(false))) {
|
||||
if (!QTC_GUARD(DockerApi::isDockerDaemonAvailable(false).value_or(false))) {
|
||||
LOG("No daemon. Could not run " << cmd.toUserOutput());
|
||||
return false;
|
||||
}
|
||||
@@ -1021,7 +1021,7 @@ static QByteArray randomHex()
|
||||
|
||||
QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) const
|
||||
{
|
||||
if (!DockerApi::isDockerDaemonAvailable().value_or(false))
|
||||
if (!DockerApi::isDockerDaemonAvailable(false).value_or(false))
|
||||
return {};
|
||||
QTC_ASSERT(m_shell && m_shell->isRunning(), return {});
|
||||
QMutexLocker l(&m_shellMutex);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include "dockerconstants.h"
|
||||
|
||||
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <projectexplorer/toolchain.h>
|
||||
@@ -39,6 +41,7 @@
|
||||
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
@@ -69,7 +72,7 @@ public:
|
||||
private:
|
||||
QtVersions autoDetectQtVersions() const;
|
||||
QList<ToolChain *> autoDetectToolChains();
|
||||
void autoDetectCMake();
|
||||
QList<Id> autoDetectCMake();
|
||||
void autoDetectDebugger();
|
||||
|
||||
KitDetector *q;
|
||||
@@ -213,12 +216,21 @@ QtVersions KitDetectorPrivate::autoDetectQtVersions() const
|
||||
|
||||
const auto handleQmake = [this, &qtVersions, &error](const FilePath &qmake) {
|
||||
if (QtVersion *qtVersion = QtVersionFactory::createQtVersionFromQMakePath(qmake,
|
||||
false,
|
||||
m_sharedId,
|
||||
&error)) {
|
||||
qtVersions.append(qtVersion);
|
||||
QtVersionManager::addVersion(qtVersion);
|
||||
emit q->logOutput(tr("Found \"%1\"").arg(qtVersion->qmakeFilePath().toUserOutput()));
|
||||
false,
|
||||
m_sharedId,
|
||||
&error)) {
|
||||
if (qtVersion->isValid()) {
|
||||
if (!Utils::anyOf(qtVersions,
|
||||
[qtVersion](QtVersion* other) {
|
||||
return qtVersion->mkspecPath() == other->mkspecPath();
|
||||
})) {
|
||||
|
||||
qtVersions.append(qtVersion);
|
||||
QtVersionManager::addVersion(qtVersion);
|
||||
emit q->logOutput(
|
||||
tr("Found \"%1\"").arg(qtVersion->qmakeFilePath().toUserOutput()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -265,20 +277,24 @@ Toolchains KitDetectorPrivate::autoDetectToolChains()
|
||||
return allNewToolChains;
|
||||
}
|
||||
|
||||
void KitDetectorPrivate::autoDetectCMake()
|
||||
QList<Id> KitDetectorPrivate::autoDetectCMake()
|
||||
{
|
||||
QList<Id> result;
|
||||
QObject *cmakeManager = ExtensionSystem::PluginManager::getObjectByName("CMakeToolManager");
|
||||
if (!cmakeManager)
|
||||
return;
|
||||
return {};
|
||||
|
||||
QString logMessage;
|
||||
const bool res = QMetaObject::invokeMethod(cmakeManager,
|
||||
"autoDetectCMakeForDevice",
|
||||
Q_RETURN_ARG(QList<Utils::Id>, result),
|
||||
Q_ARG(Utils::FilePaths, m_searchPaths),
|
||||
Q_ARG(QString, m_sharedId),
|
||||
Q_ARG(QString *, &logMessage));
|
||||
QTC_CHECK(res);
|
||||
emit q->logOutput('\n' + logMessage);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void KitDetectorPrivate::autoDetectDebugger()
|
||||
@@ -308,16 +324,21 @@ void KitDetectorPrivate::autoDetect()
|
||||
const Toolchains toolchains = autoDetectToolChains();
|
||||
const QtVersions qtVersions = autoDetectQtVersions();
|
||||
|
||||
autoDetectCMake();
|
||||
const QList<Id> cmakeIds = autoDetectCMake();
|
||||
const Id cmakeId = cmakeIds.empty() ? Id() : cmakeIds.first();
|
||||
autoDetectDebugger();
|
||||
|
||||
const auto initializeKit = [this, toolchains, qtVersions](Kit *k) {
|
||||
const auto initializeKit = [this, toolchains, qtVersions, cmakeId](Kit *k) {
|
||||
k->setAutoDetected(false);
|
||||
k->setAutoDetectionSource(m_sharedId);
|
||||
k->setUnexpandedDisplayName("%{Device:Name}");
|
||||
|
||||
if (cmakeId.isValid())
|
||||
k->setValue(CMakeProjectManager::Constants::TOOL_ID, cmakeId.toSetting());
|
||||
|
||||
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DOCKER_DEVICE_TYPE);
|
||||
DeviceKitAspect::setDevice(k, m_device);
|
||||
BuildDeviceKitAspect::setDevice(k, m_device);
|
||||
|
||||
QtVersion *qt = nullptr;
|
||||
if (!qtVersions.isEmpty()) {
|
||||
@@ -332,10 +353,14 @@ void KitDetectorPrivate::autoDetect()
|
||||
for (ToolChain *toolChain : toolchainsToSet)
|
||||
ToolChainKitAspect::setToolChain(k, toolChain);
|
||||
|
||||
if (cmakeId.isValid())
|
||||
k->setSticky(CMakeProjectManager::Constants::TOOL_ID, true);
|
||||
|
||||
k->setSticky(ToolChainKitAspect::id(), true);
|
||||
k->setSticky(QtSupport::QtKitAspect::id(), true);
|
||||
k->setSticky(DeviceKitAspect::id(), true);
|
||||
k->setSticky(DeviceTypeKitAspect::id(), true);
|
||||
k->setSticky(BuildDeviceKitAspect::id(), true);
|
||||
};
|
||||
|
||||
Kit *kit = KitManager::registerKit(initializeKit);
|
||||
|
||||
@@ -590,6 +590,9 @@ IosToolChainFactory::IosToolChainFactory()
|
||||
|
||||
Toolchains IosToolChainFactory::autoDetect(const ToolchainDetector &detector) const
|
||||
{
|
||||
if (detector.device)
|
||||
return {};
|
||||
|
||||
QList<ClangToolChain *> existingClangToolChains = clangToolChains(detector.alreadyKnown);
|
||||
const QList<XcodePlatform> platforms = XcodeProbe::detectPlatforms().values();
|
||||
Toolchains toolChains;
|
||||
|
||||
@@ -211,8 +211,11 @@ Toolchains ToolChainSettingsAccessor::restoreToolChains(QWidget *parent) const
|
||||
const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);
|
||||
|
||||
// Process ops:
|
||||
for (ToolChain *tc : ops.toDemote)
|
||||
tc->setDetection(ToolChain::ManualDetection);
|
||||
for (ToolChain *tc : ops.toDemote) {
|
||||
// FIXME: We currently only demote local toolchains, as they are not redetected.
|
||||
if (tc->detectionSource().isEmpty())
|
||||
tc->setDetection(ToolChain::ManualDetection);
|
||||
}
|
||||
|
||||
qDeleteAll(ops.toDelete);
|
||||
|
||||
|
||||
@@ -221,6 +221,10 @@ QnxToolChainFactory::QnxToolChainFactory()
|
||||
|
||||
Toolchains QnxToolChainFactory::autoDetect(const ToolchainDetector &detector) const
|
||||
{
|
||||
// FIXME: Support detecting toolchains on remote devices
|
||||
if (detector.device)
|
||||
return {};
|
||||
|
||||
Toolchains tcs;
|
||||
const auto configurations = QnxConfigurationManager::instance()->configurations();
|
||||
for (QnxConfiguration *configuration : configurations)
|
||||
|
||||
Reference in New Issue
Block a user