forked from qt-creator/qt-creator
ProjectExplorer: Move BuildSystem owership to BuildConfiguration
... or Target. This patch moves build system from conceptually "one per project" to "one per target (i.e. per project-and-kit)" or "per BuildConfigurations" for targets where the builds differ significantly. Building requires usually items from the kit (Qt version, compiler, ...) so a target-agnostic build is practically almost always wrong. Moving the build system to the target also has the potential to solve issues caused by switching targets while parsing, that used Project::activeTarget() regularly, with potentially different results before and after the switch. This patch might create performance/size regressions when several targets are set up per project as the build system implementation's internal data are duplicated in this case. The idea is to fix that by sharing per-project pieces again in the project implementation once these problems occur. Change-Id: I87f640ce418b93175b5029124eaa55f3b8721dca Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -65,24 +65,29 @@ Q_LOGGING_CATEGORY(cmakeBuildDirManagerLog, "qtc.cmake.builddirmanager", QtWarni
|
||||
// BuildDirManager:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BuildDirManager::BuildDirManager(CMakeProject *project) : m_project(project) { assert(project); }
|
||||
BuildDirManager::BuildDirManager(CMakeBuildSystem *buildSystem)
|
||||
: m_buildSystem(buildSystem)
|
||||
{
|
||||
assert(buildSystem);
|
||||
}
|
||||
|
||||
BuildDirManager::~BuildDirManager() = default;
|
||||
|
||||
Utils::FilePath BuildDirManager::workDirectory(const BuildDirParameters ¶meters) const
|
||||
FilePath BuildDirManager::workDirectory(const BuildDirParameters ¶meters) const
|
||||
{
|
||||
const Utils::FilePath bdir = parameters.buildDirectory;
|
||||
const CMakeTool *cmake = parameters.cmakeTool();
|
||||
if (bdir.exists()) {
|
||||
m_buildDirToTempDir.erase(bdir);
|
||||
return bdir;
|
||||
} else {
|
||||
if (cmake && cmake->autoCreateBuildDirectory()) {
|
||||
if (!QDir().mkpath(bdir.toString()))
|
||||
emitErrorOccured(tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput()));
|
||||
return bdir;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmake && cmake->autoCreateBuildDirectory()) {
|
||||
if (!QDir().mkpath(bdir.toString()))
|
||||
emitErrorOccured(tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput()));
|
||||
return bdir;
|
||||
}
|
||||
|
||||
auto tmpDirIt = m_buildDirToTempDir.find(bdir);
|
||||
if (tmpDirIt == m_buildDirToTempDir.end()) {
|
||||
auto ret = m_buildDirToTempDir.emplace(std::make_pair(bdir, std::make_unique<Utils::TemporaryDirectory>("qtc-cmake-XXXXXXXX")));
|
||||
@@ -290,22 +295,20 @@ void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &par
|
||||
updateReaderType(m_parameters, [this]() { emitReparseRequest(); });
|
||||
}
|
||||
|
||||
CMakeBuildConfiguration *BuildDirManager::buildConfiguration() const
|
||||
CMakeBuildSystem *BuildDirManager::buildSystem() const
|
||||
{
|
||||
if (m_project->activeTarget() && m_project->activeTarget()->activeBuildConfiguration() == m_parameters.buildConfiguration)
|
||||
return m_parameters.buildConfiguration;
|
||||
return nullptr;
|
||||
return m_buildSystem;
|
||||
}
|
||||
|
||||
FilePath BuildDirManager::buildDirectory() const
|
||||
{
|
||||
return buildConfiguration() ? m_parameters.buildDirectory : FilePath();
|
||||
return m_parameters.buildDirectory;
|
||||
}
|
||||
|
||||
void BuildDirManager::becameDirty()
|
||||
{
|
||||
qCDebug(cmakeBuildDirManagerLog) << "BuildDirManager: becameDirty was triggered.";
|
||||
if (isParsing() || !buildConfiguration())
|
||||
if (isParsing() || !buildSystem())
|
||||
return;
|
||||
|
||||
const CMakeTool *tool = m_parameters.cmakeTool();
|
||||
@@ -444,7 +447,7 @@ static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManage
|
||||
target.title = title;
|
||||
target.targetType = UtilityType;
|
||||
target.workingDirectory = bdm->buildDirectory();
|
||||
target.sourceDirectory = bdm->project()->projectDirectory();
|
||||
target.sourceDirectory = bdm->buildSystem()->project()->projectDirectory();
|
||||
|
||||
return target;
|
||||
}
|
||||
@@ -528,13 +531,10 @@ QString BuildDirManager::flagsString(int reparseFlags)
|
||||
|
||||
bool BuildDirManager::checkConfiguration()
|
||||
{
|
||||
CMakeBuildConfiguration *bc = buildConfiguration();
|
||||
QTC_ASSERT(m_parameters.isValid() || !bc, return false);
|
||||
|
||||
if (m_parameters.workDirectory != m_parameters.buildDirectory) // always throw away changes in the tmpdir!
|
||||
return false;
|
||||
|
||||
const CMakeConfig cache = bc->configurationFromCMake();
|
||||
const CMakeConfig cache = m_buildSystem->cmakeBuildConfiguration()->configurationFromCMake();
|
||||
if (cache.isEmpty())
|
||||
return false; // No cache file yet.
|
||||
|
||||
@@ -586,8 +586,8 @@ bool BuildDirManager::checkConfiguration()
|
||||
box->exec();
|
||||
if (box->clickedButton() == applyButton) {
|
||||
m_parameters.configuration = newConfig;
|
||||
QSignalBlocker blocker(bc);
|
||||
bc->setConfigurationForCMake(newConfig);
|
||||
QSignalBlocker blocker(m_buildSystem->buildConfiguration());
|
||||
m_buildSystem->cmakeBuildConfiguration()->setConfigurationForCMake(newConfig);
|
||||
return false;
|
||||
} else if (box->clickedButton() == defaultButton)
|
||||
return true;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "builddirparameters.h"
|
||||
#include "builddirreader.h"
|
||||
#include "cmakebuildsystem.h"
|
||||
#include "cmakebuildtarget.h"
|
||||
#include "cmakeconfigitem.h"
|
||||
|
||||
@@ -46,14 +45,11 @@
|
||||
namespace ProjectExplorer { class FileNode; }
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
class CMakeProject;
|
||||
class CMakeTool;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class CMakeProjectNode;
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeBuildSystem;
|
||||
class CMakeProjectNode;
|
||||
|
||||
class BuildDirManager : public QObject
|
||||
{
|
||||
@@ -71,7 +67,7 @@ public:
|
||||
|
||||
static QString flagsString(int reparseFlags);
|
||||
|
||||
BuildDirManager(CMakeProject *project);
|
||||
explicit BuildDirManager(CMakeBuildSystem *buildSystem);
|
||||
~BuildDirManager() final;
|
||||
|
||||
bool isParsing() const;
|
||||
@@ -81,8 +77,7 @@ public:
|
||||
void setParametersAndRequestParse(const BuildDirParameters ¶meters,
|
||||
const int reparseOptions);
|
||||
// nullptr if the BC is not active anymore!
|
||||
CMakeBuildConfiguration *buildConfiguration() const;
|
||||
CMakeProject *project() const {return m_project; }
|
||||
CMakeBuildSystem *buildSystem() const;
|
||||
Utils::FilePath buildDirectory() const;
|
||||
|
||||
void clearCache();
|
||||
@@ -133,7 +128,7 @@ private:
|
||||
|
||||
BuildDirParameters m_parameters;
|
||||
int m_reparseParameters;
|
||||
CMakeProject *m_project = nullptr;
|
||||
CMakeBuildSystem *m_buildSystem = nullptr;
|
||||
mutable std::unordered_map<Utils::FilePath, std::unique_ptr<Utils::TemporaryDirectory>> m_buildDirToTempDir;
|
||||
mutable std::unique_ptr<BuildDirReader> m_reader;
|
||||
mutable bool m_isHandlingError = false;
|
||||
|
||||
@@ -45,7 +45,7 @@ BuildDirParameters::BuildDirParameters() = default;
|
||||
|
||||
BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
buildConfiguration = bc;
|
||||
initialized = bc != nullptr;
|
||||
|
||||
const Kit *k = bc->target()->kit();
|
||||
|
||||
@@ -82,7 +82,7 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc)
|
||||
generatorArguments = CMakeGeneratorKitAspect::generatorArguments(k);
|
||||
}
|
||||
|
||||
bool BuildDirParameters::isValid() const { return buildConfiguration && cmakeTool(); }
|
||||
bool BuildDirParameters::isValid() const { return initialized && cmakeTool(); }
|
||||
|
||||
CMakeTool *BuildDirParameters::cmakeTool() const
|
||||
{
|
||||
|
||||
@@ -42,14 +42,14 @@ class CMakeBuildConfiguration;
|
||||
class BuildDirParameters {
|
||||
public:
|
||||
BuildDirParameters();
|
||||
BuildDirParameters(CMakeBuildConfiguration *bc);
|
||||
explicit BuildDirParameters(CMakeBuildConfiguration *bc);
|
||||
BuildDirParameters(const BuildDirParameters &other);
|
||||
BuildDirParameters &operator=(const BuildDirParameters &other);
|
||||
|
||||
bool isValid() const;
|
||||
CMakeTool *cmakeTool() const;
|
||||
|
||||
CMakeBuildConfiguration *buildConfiguration = nullptr;
|
||||
bool initialized = false;
|
||||
QString projectName;
|
||||
|
||||
Utils::FilePath sourceDirectory;
|
||||
|
||||
@@ -84,101 +84,17 @@ const char CONFIGURATION_KEY[] = "CMake.Configuration";
|
||||
|
||||
CMakeBuildConfiguration::CMakeBuildConfiguration(Target *parent, Core::Id id)
|
||||
: BuildConfiguration(parent, id)
|
||||
, m_buildDirManager(qobject_cast<CMakeProject *>(parent->project()))
|
||||
{
|
||||
m_buildSystem = new CMakeBuildSystem(this);
|
||||
setBuildDirectory(shadowBuildDirectory(project()->projectFilePath(),
|
||||
target()->kit(),
|
||||
displayName(),
|
||||
BuildConfiguration::Unknown));
|
||||
}
|
||||
|
||||
BuildSystem *bs = qobject_cast<CMakeBuildSystem *>(project()->buildSystem());
|
||||
|
||||
// BuildDirManager:
|
||||
connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this, bs]() {
|
||||
if (isActive())
|
||||
bs->requestParse();
|
||||
});
|
||||
connect(&m_buildDirManager, &BuildDirManager::requestDelayedReparse, this, [this, bs]() {
|
||||
if (isActive())
|
||||
bs->requestDelayedParse();
|
||||
});
|
||||
connect(&m_buildDirManager,
|
||||
&BuildDirManager::dataAvailable,
|
||||
this,
|
||||
&CMakeBuildConfiguration::handleParsingSucceeded);
|
||||
connect(&m_buildDirManager,
|
||||
&BuildDirManager::errorOccured,
|
||||
this,
|
||||
&CMakeBuildConfiguration::handleParsingFailed);
|
||||
connect(&m_buildDirManager, &BuildDirManager::parsingStarted, this, [this]() {
|
||||
clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
|
||||
});
|
||||
|
||||
// Kit changed:
|
||||
connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) {
|
||||
if (k != target()->kit())
|
||||
return; // not for us...
|
||||
// Build configuration has not changed, but Kit settings might have:
|
||||
// reparse and check the configuration, independent of whether the reader has changed
|
||||
m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(this),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
});
|
||||
|
||||
// Became active/inactive:
|
||||
connect(project(), &Project::activeBuildConfigurationChanged, this, [this]() {
|
||||
if (isActive()) {
|
||||
// Build configuration has switched:
|
||||
// * Check configuration if reader changes due to it not existing yet:-)
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(this),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
} else {
|
||||
m_buildDirManager.stopParsingAndClearState();
|
||||
}
|
||||
});
|
||||
|
||||
// BuildConfiguration changed:
|
||||
connect(this, &CMakeBuildConfiguration::environmentChanged, this, [this]() {
|
||||
if (isActive()) {
|
||||
// The environment on our BC has changed:
|
||||
// * Error out if the reader updates, cannot happen since all BCs share a target/kit.
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(this),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
}
|
||||
});
|
||||
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
|
||||
if (isActive()) {
|
||||
// The build directory of our BC has changed:
|
||||
// * Error out if the reader updates, cannot happen since all BCs share a target/kit.
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
// If no configuration exists, then the arguments will get added automatically by
|
||||
// the reader.
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(this),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
}
|
||||
});
|
||||
connect(this, &CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() {
|
||||
if (isActive()) {
|
||||
// The CMake configuration has changed on our BC:
|
||||
// * Error out if the reader updates, cannot happen since all BCs share a target/kit.
|
||||
// * run cmake with configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(this),
|
||||
BuildDirManager::REPARSE_FORCE_CONFIGURATION);
|
||||
}
|
||||
});
|
||||
|
||||
connect(parent->project(), &Project::projectFileIsDirty, this, [this]() {
|
||||
if (isActive()) {
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(this),
|
||||
BuildDirManager::REPARSE_DEFAULT);
|
||||
}
|
||||
});
|
||||
CMakeBuildConfiguration::~CMakeBuildConfiguration()
|
||||
{
|
||||
delete m_buildSystem;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::initialize()
|
||||
@@ -284,82 +200,11 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map)
|
||||
return true;
|
||||
}
|
||||
|
||||
const QList<BuildTargetInfo> CMakeBuildConfiguration::appTargets() const
|
||||
{
|
||||
QList<BuildTargetInfo> appTargetList;
|
||||
const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit())
|
||||
== Android::Constants::ANDROID_DEVICE_TYPE;
|
||||
for (const CMakeBuildTarget &ct : m_buildTargets) {
|
||||
if (ct.targetType == UtilityType)
|
||||
continue;
|
||||
|
||||
if (ct.targetType == ExecutableType || (forAndroid && ct.targetType == DynamicLibraryType)) {
|
||||
BuildTargetInfo bti;
|
||||
bti.displayName = ct.title;
|
||||
bti.targetFilePath = ct.executable;
|
||||
bti.projectFilePath = ct.sourceDirectory.stringAppended("/");
|
||||
bti.workingDirectory = ct.workingDirectory;
|
||||
bti.buildKey = ct.title;
|
||||
|
||||
// Workaround for QTCREATORBUG-19354:
|
||||
bti.runEnvModifier = [this](Environment &env, bool) {
|
||||
if (HostOsInfo::isWindowsHost()) {
|
||||
const Kit *k = target()->kit();
|
||||
if (const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k))
|
||||
env.prependOrSetPath(qt->binPath().toString());
|
||||
}
|
||||
};
|
||||
|
||||
appTargetList.append(bti);
|
||||
}
|
||||
}
|
||||
|
||||
return appTargetList;
|
||||
}
|
||||
|
||||
DeploymentData CMakeBuildConfiguration::deploymentData() const
|
||||
{
|
||||
DeploymentData result;
|
||||
|
||||
QDir sourceDir = target()->project()->projectDirectory().toString();
|
||||
QDir buildDir = buildDirectory().toString();
|
||||
|
||||
QString deploymentPrefix;
|
||||
QString deploymentFilePath = sourceDir.filePath("QtCreatorDeployment.txt");
|
||||
|
||||
bool hasDeploymentFile = QFileInfo::exists(deploymentFilePath);
|
||||
if (!hasDeploymentFile) {
|
||||
deploymentFilePath = buildDir.filePath("QtCreatorDeployment.txt");
|
||||
hasDeploymentFile = QFileInfo::exists(deploymentFilePath);
|
||||
}
|
||||
if (!hasDeploymentFile)
|
||||
return result;
|
||||
|
||||
deploymentPrefix = result.addFilesFromDeploymentFile(deploymentFilePath,
|
||||
sourceDir.absolutePath());
|
||||
for (const CMakeBuildTarget &ct : m_buildTargets) {
|
||||
if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) {
|
||||
if (!ct.executable.isEmpty()
|
||||
&& result.deployableForLocalFile(ct.executable).localFilePath() != ct.executable) {
|
||||
result.addFile(ct.executable.toString(),
|
||||
deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()),
|
||||
DeployableFile::TypeExecutable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList CMakeBuildConfiguration::buildTargetTitles() const
|
||||
{
|
||||
return transform(m_buildTargets, &CMakeBuildTarget::title);
|
||||
}
|
||||
|
||||
const QList<CMakeBuildTarget> &CMakeBuildConfiguration::buildTargets() const
|
||||
{
|
||||
return m_buildTargets;
|
||||
}
|
||||
|
||||
FilePath CMakeBuildConfiguration::shadowBuildDirectory(const FilePath &projectFilePath,
|
||||
const Kit *k,
|
||||
@@ -408,11 +253,6 @@ void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &confi
|
||||
m_configurationFromCMake = config;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::setBuildTargets(const QList<CMakeBuildTarget> &targets)
|
||||
{
|
||||
m_buildTargets = targets;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items)
|
||||
{
|
||||
const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) {
|
||||
@@ -548,64 +388,6 @@ void CMakeBuildConfiguration::setWarning(const QString &message)
|
||||
emit warningOccured(m_warning);
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::handleParsingSucceeded()
|
||||
{
|
||||
if (!isActive()) {
|
||||
m_buildDirManager.stopParsingAndClearState();
|
||||
return;
|
||||
}
|
||||
|
||||
clearError();
|
||||
|
||||
QString errorMessage;
|
||||
{
|
||||
const QList<CMakeBuildTarget> buildTargets = m_buildDirManager.takeBuildTargets(
|
||||
errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
setBuildTargets(buildTargets);
|
||||
}
|
||||
|
||||
{
|
||||
const CMakeConfig cmakeConfig = m_buildDirManager.takeCMakeConfiguration(errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
setConfigurationFromCMake(cmakeConfig);
|
||||
}
|
||||
|
||||
{
|
||||
target()->setApplicationTargets(appTargets());
|
||||
target()->setDeploymentData(deploymentData());
|
||||
}
|
||||
|
||||
static_cast<CMakeBuildSystem *>(project()->buildSystem())->handleParsingSuccess(this);
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::handleParsingFailed(const QString &msg)
|
||||
{
|
||||
setError(msg);
|
||||
|
||||
QString errorMessage;
|
||||
setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration(errorMessage));
|
||||
// ignore errorMessage here, we already got one.
|
||||
|
||||
static_cast<CMakeBuildSystem *>(project()->buildSystem())->handleParsingError(this);
|
||||
}
|
||||
|
||||
std::unique_ptr<CMakeProjectNode> CMakeBuildConfiguration::generateProjectTree(
|
||||
const QList<const FileNode *> &allFiles)
|
||||
{
|
||||
QString errorMessage;
|
||||
auto root = m_buildDirManager.generateProjectTree(allFiles, errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
return root;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::checkAndReportError(QString &errorMessage)
|
||||
{
|
||||
if (!errorMessage.isEmpty()) {
|
||||
setError(errorMessage);
|
||||
errorMessage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
QString CMakeBuildConfiguration::error() const
|
||||
{
|
||||
@@ -775,5 +557,10 @@ CMakeProject *CMakeBuildConfiguration::project() const
|
||||
return qobject_cast<CMakeProject *>(BuildConfiguration::project());
|
||||
}
|
||||
|
||||
BuildSystem *CMakeBuildConfiguration::buildSystem() const
|
||||
{
|
||||
return m_buildSystem;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
@@ -34,13 +34,12 @@
|
||||
#include <projectexplorer/deploymentdata.h>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
class CMakeBuildSystem;
|
||||
class CMakeExtraBuildInfo;
|
||||
class CMakeProject;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class BuildDirManager;
|
||||
class CMakeBuildSystem;
|
||||
class CMakeBuildSettingsWidget;
|
||||
|
||||
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
||||
@@ -49,6 +48,7 @@ class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
||||
|
||||
friend class ProjectExplorer::BuildConfigurationFactory;
|
||||
CMakeBuildConfiguration(ProjectExplorer::Target *parent, Core::Id id);
|
||||
~CMakeBuildConfiguration() final;
|
||||
|
||||
public:
|
||||
void emitBuildTypeChanged();
|
||||
@@ -61,17 +61,14 @@ public:
|
||||
|
||||
CMakeProject *project() const;
|
||||
|
||||
QStringList buildTargetTitles() const;
|
||||
const QList<CMakeBuildTarget> &buildTargets() const;
|
||||
const QList<ProjectExplorer::BuildTargetInfo> appTargets() const;
|
||||
ProjectExplorer::DeploymentData deploymentData() const;
|
||||
|
||||
static Utils::FilePath
|
||||
shadowBuildDirectory(const Utils::FilePath &projectFilePath, const ProjectExplorer::Kit *k,
|
||||
const QString &bcName, BuildConfiguration::BuildType buildType);
|
||||
|
||||
// Context menu action:
|
||||
void buildTarget(const QString &buildTarget);
|
||||
ProjectExplorer::BuildSystem *buildSystem() const final;
|
||||
|
||||
signals:
|
||||
void errorOccured(const QString &message);
|
||||
void warningOccured(const QString &message);
|
||||
@@ -92,7 +89,6 @@ private:
|
||||
enum ForceEnabledChanged { False, True };
|
||||
void clearError(ForceEnabledChanged fec = ForceEnabledChanged::False);
|
||||
|
||||
void setBuildTargets(const QList<CMakeBuildTarget> &targets);
|
||||
void setConfigurationFromCMake(const CMakeConfig &config);
|
||||
void setConfigurationForCMake(const QList<ConfigModel::DataItem> &items);
|
||||
void setConfigurationForCMake(const CMakeConfig &config);
|
||||
@@ -100,27 +96,17 @@ private:
|
||||
void setError(const QString &message);
|
||||
void setWarning(const QString &message);
|
||||
|
||||
void handleParsingSucceeded();
|
||||
void handleParsingFailed(const QString &msg);
|
||||
|
||||
std::unique_ptr<CMakeProjectNode> generateProjectTree(
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles);
|
||||
|
||||
void checkAndReportError(QString &errorMessage);
|
||||
|
||||
Internal::BuildDirManager m_buildDirManager;
|
||||
|
||||
CMakeConfig m_configurationForCMake;
|
||||
CMakeConfig m_initialConfiguration;
|
||||
QString m_error;
|
||||
QString m_warning;
|
||||
|
||||
CMakeConfig m_configurationFromCMake;
|
||||
QList<CMakeBuildTarget> m_buildTargets;
|
||||
CMakeBuildSystem *m_buildSystem = nullptr;
|
||||
|
||||
friend class CMakeBuildSettingsWidget;
|
||||
friend class CMakeProjectManager::CMakeBuildSystem;
|
||||
friend class CMakeProjectManager::CMakeProject;
|
||||
friend class CMakeBuildSystem;
|
||||
friend class CMakeProject;
|
||||
friend class BuildDirManager;
|
||||
};
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QMenu>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
@@ -102,7 +104,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setColumnStretch(1, 10);
|
||||
|
||||
auto project = static_cast<CMakeProject *>(bc->project());
|
||||
auto project = bc->project();
|
||||
|
||||
auto buildDirChooser = new Utils::PathChooser;
|
||||
buildDirChooser->setBaseFileName(project->projectDirectory());
|
||||
@@ -245,21 +247,20 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
|
||||
setError(bc->error());
|
||||
setWarning(bc->warning());
|
||||
|
||||
connect(project, &ProjectExplorer::Project::parsingStarted, this, [this]() {
|
||||
connect(bc->target(), &Target::parsingStarted, this, [this]() {
|
||||
updateButtonState();
|
||||
m_configView->setEnabled(false);
|
||||
m_showProgressTimer.start();
|
||||
});
|
||||
|
||||
if (project->isParsing())
|
||||
if (bc->buildSystem()->isParsing())
|
||||
m_showProgressTimer.start();
|
||||
else {
|
||||
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
|
||||
m_configView->expandAll();
|
||||
}
|
||||
|
||||
connect(project, &ProjectExplorer::Project::parsingFinished,
|
||||
this, [this, buildDirChooser, stretcher]() {
|
||||
connect(bc->target(), &Target::parsingFinished, this, [this, buildDirChooser, stretcher] {
|
||||
m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake());
|
||||
m_configView->expandAll();
|
||||
m_configView->setEnabled(true);
|
||||
@@ -363,7 +364,7 @@ void CMakeBuildSettingsWidget::setWarning(const QString &message)
|
||||
|
||||
void CMakeBuildSettingsWidget::updateButtonState()
|
||||
{
|
||||
const bool isParsing = m_buildConfiguration->project()->isParsing();
|
||||
const bool isParsing = m_buildConfiguration->buildSystem()->isParsing();
|
||||
const bool hasChanges = m_configModel->hasChanges();
|
||||
m_resetButton->setEnabled(hasChanges && !isParsing);
|
||||
m_reconfigureButton->setEnabled((hasChanges || m_configModel->hasCMakeChanges()) && !isParsing);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "cmakebuildstep.h"
|
||||
|
||||
#include "cmakebuildconfiguration.h"
|
||||
#include "cmakebuildsystem.h"
|
||||
#include "cmakekitinformation.h"
|
||||
#include "cmakeparser.h"
|
||||
#include "cmakeprojectconstants.h"
|
||||
@@ -91,7 +92,7 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl) :
|
||||
setLowPriority();
|
||||
|
||||
connect(target(), &Target::kitChanged, this, &CMakeBuildStep::cmakeCommandChanged);
|
||||
connect(project(), &Project::parsingFinished,
|
||||
connect(target(), &Target::parsingFinished,
|
||||
this, &CMakeBuildStep::handleBuildTargetChanges);
|
||||
}
|
||||
|
||||
@@ -221,17 +222,17 @@ void CMakeBuildStep::doRun()
|
||||
QTC_ASSERT(bc, return);
|
||||
|
||||
m_waiting = false;
|
||||
auto p = static_cast<CMakeProject *>(bc->project());
|
||||
if (p->persistCMakeState()) {
|
||||
auto bs = static_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem());
|
||||
if (bs->persistCMakeState()) {
|
||||
emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage);
|
||||
m_waiting = true;
|
||||
} else if (p->mustUpdateCMakeStateBeforeBuild()) {
|
||||
} else if (buildConfiguration()->buildSystem()->isWaitingForParse()) {
|
||||
emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage);
|
||||
m_waiting = true;
|
||||
}
|
||||
|
||||
if (m_waiting) {
|
||||
m_runTrigger = connect(project(), &Project::parsingFinished,
|
||||
m_runTrigger = connect(target(), &Target::parsingFinished,
|
||||
this, [this](bool success) { handleProjectWasParsed(success); });
|
||||
} else {
|
||||
runImpl();
|
||||
@@ -367,7 +368,7 @@ Utils::CommandLine CMakeBuildStep::cmakeCommand(RunConfiguration *rc) const
|
||||
|
||||
QStringList CMakeBuildStep::knownBuildTargets()
|
||||
{
|
||||
auto bc = qobject_cast<CMakeBuildConfiguration *>(buildConfiguration());
|
||||
auto bc = qobject_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem());
|
||||
return bc ? bc->buildTargetTitles() : QStringList();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,18 @@
|
||||
#include "cmakeprojectconstants.h"
|
||||
#include "cmakeprojectnodes.h"
|
||||
|
||||
#include <android/androidconstants.h>
|
||||
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <cpptools/cppprojectupdater.h>
|
||||
#include <cpptools/generatedcodemodelsupport.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
#include <qtsupport/qtcppkitinfo.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/mimetypes/mimetype.h>
|
||||
@@ -48,8 +53,7 @@ using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
using namespace Internal;
|
||||
namespace Internal {
|
||||
|
||||
Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg);
|
||||
|
||||
@@ -57,15 +61,15 @@ Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg);
|
||||
// CMakeBuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
CMakeBuildSystem::CMakeBuildSystem(Project *project)
|
||||
: BuildSystem(project)
|
||||
CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
|
||||
: BuildSystem(bc)
|
||||
, m_buildConfiguration(bc)
|
||||
, m_buildDirManager(this)
|
||||
, m_cppCodeModelUpdater(new CppTools::CppProjectUpdater)
|
||||
{
|
||||
// TreeScanner:
|
||||
connect(&m_treeScanner,
|
||||
&TreeScanner::finished,
|
||||
this,
|
||||
&CMakeBuildSystem::handleTreeScanningFinished);
|
||||
connect(&m_treeScanner, &TreeScanner::finished,
|
||||
this, &CMakeBuildSystem::handleTreeScanningFinished);
|
||||
|
||||
m_treeScanner.setFilter([this](const MimeType &mimeType, const FilePath &fn) {
|
||||
// Mime checks requires more resources, so keep it last in check list
|
||||
@@ -98,6 +102,109 @@ CMakeBuildSystem::CMakeBuildSystem(Project *project)
|
||||
}
|
||||
return type;
|
||||
});
|
||||
|
||||
// BuildDirManager:
|
||||
connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this] {
|
||||
if (m_buildConfiguration->isActive())
|
||||
requestParse();
|
||||
});
|
||||
connect(&m_buildDirManager, &BuildDirManager::requestDelayedReparse, this, [this] {
|
||||
if (m_buildConfiguration->isActive())
|
||||
requestDelayedParse();
|
||||
});
|
||||
|
||||
connect(&m_buildDirManager, &BuildDirManager::dataAvailable,
|
||||
this, &CMakeBuildSystem::handleParsingSucceeded);
|
||||
|
||||
connect(&m_buildDirManager, &BuildDirManager::errorOccured,
|
||||
this, &CMakeBuildSystem::handleParsingFailed);
|
||||
|
||||
connect(&m_buildDirManager, &BuildDirManager::parsingStarted, this, [this]() {
|
||||
m_buildConfiguration->clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
|
||||
});
|
||||
|
||||
// Kit changed:
|
||||
connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) {
|
||||
if (k != target()->kit())
|
||||
return; // not for us...
|
||||
// Build configuration has not changed, but Kit settings might have:
|
||||
// reparse and check the configuration, independent of whether the reader has changed
|
||||
m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
});
|
||||
|
||||
// Became active/inactive:
|
||||
connect(project(), &Project::activeTargetChanged, this, [this](Target *t) {
|
||||
if (t == target()) {
|
||||
// Build configuration has switched:
|
||||
// * Check configuration if reader changes due to it not existing yet:-)
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
} else {
|
||||
m_buildDirManager.stopParsingAndClearState();
|
||||
}
|
||||
});
|
||||
connect(target(), &Target::activeBuildConfigurationChanged, this, [this](BuildConfiguration *bc) {
|
||||
if (m_buildConfiguration->isActive()) {
|
||||
if (m_buildConfiguration == bc) {
|
||||
// Build configuration has switched:
|
||||
// * Check configuration if reader changes due to it not existing yet:-)
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
} else {
|
||||
m_buildDirManager.stopParsingAndClearState();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// BuildConfiguration changed:
|
||||
connect(m_buildConfiguration, &CMakeBuildConfiguration::environmentChanged, this, [this]() {
|
||||
if (m_buildConfiguration->isActive()) {
|
||||
// The environment on our BC has changed:
|
||||
// * Error out if the reader updates, cannot happen since all BCs share a target/kit.
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
}
|
||||
});
|
||||
connect(m_buildConfiguration, &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() {
|
||||
if (m_buildConfiguration->isActive()) {
|
||||
// The build directory of our BC has changed:
|
||||
// * Error out if the reader updates, cannot happen since all BCs share a target/kit.
|
||||
// * run cmake without configuration arguments if the reader stays
|
||||
// If no configuration exists, then the arguments will get added automatically by
|
||||
// the reader.
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
}
|
||||
});
|
||||
connect(m_buildConfiguration, &CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() {
|
||||
if (m_buildConfiguration->isActive()) {
|
||||
// The CMake configuration has changed on our BC:
|
||||
// * Error out if the reader updates, cannot happen since all BCs share a target/kit.
|
||||
// * run cmake with configuration arguments if the reader stays
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_FORCE_CONFIGURATION);
|
||||
}
|
||||
});
|
||||
|
||||
connect(project(), &Project::projectFileIsDirty, this, [this]() {
|
||||
if (m_buildConfiguration->isActive()) {
|
||||
m_buildDirManager
|
||||
.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_DEFAULT);
|
||||
}
|
||||
});
|
||||
|
||||
m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration),
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION);
|
||||
}
|
||||
|
||||
CMakeBuildSystem::~CMakeBuildSystem()
|
||||
@@ -112,36 +219,84 @@ CMakeBuildSystem::~CMakeBuildSystem()
|
||||
qDeleteAll(m_allFiles);
|
||||
}
|
||||
|
||||
bool CMakeBuildSystem::validateParsingContext(const ParsingContext &ctx)
|
||||
void CMakeBuildSystem::triggerParsing()
|
||||
{
|
||||
QTC_ASSERT(!m_currentContext.guard.guardsProject(), return false);
|
||||
return ctx.project && qobject_cast<CMakeBuildConfiguration *>(ctx.buildConfiguration);
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::parseProject(ParsingContext &&ctx)
|
||||
{
|
||||
m_currentContext = std::move(ctx);
|
||||
|
||||
auto bc = qobject_cast<CMakeBuildConfiguration *>(m_currentContext.buildConfiguration);
|
||||
QTC_ASSERT(bc, return );
|
||||
m_currentGuard = guardParsingRun();
|
||||
|
||||
if (m_allFiles.isEmpty())
|
||||
bc->m_buildDirManager.requestFilesystemScan();
|
||||
m_buildDirManager.requestFilesystemScan();
|
||||
|
||||
m_waitingForScan = bc->m_buildDirManager.isFilesystemScanRequested();
|
||||
m_waitingForScan = m_buildDirManager.isFilesystemScanRequested();
|
||||
m_waitingForParse = true;
|
||||
m_combinedScanAndParseResult = true;
|
||||
|
||||
if (m_waitingForScan) {
|
||||
QTC_CHECK(m_treeScanner.isFinished());
|
||||
m_treeScanner.asyncScanForFiles(m_currentContext.project->projectDirectory());
|
||||
m_treeScanner.asyncScanForFiles(projectDirectory());
|
||||
Core::ProgressManager::addTask(m_treeScanner.future(),
|
||||
tr("Scan \"%1\" project tree")
|
||||
.arg(m_currentContext.project->displayName()),
|
||||
.arg(project()->displayName()),
|
||||
"CMake.Scan.Tree");
|
||||
}
|
||||
|
||||
bc->m_buildDirManager.parse();
|
||||
m_buildDirManager.parse();
|
||||
}
|
||||
|
||||
QStringList CMakeBuildSystem::filesGeneratedFrom(const QString &sourceFile) const
|
||||
{
|
||||
QFileInfo fi(sourceFile);
|
||||
FilePath project = projectDirectory();
|
||||
FilePath baseDirectory = FilePath::fromString(fi.absolutePath());
|
||||
|
||||
while (baseDirectory.isChildOf(project)) {
|
||||
const FilePath cmakeListsTxt = baseDirectory.pathAppended("CMakeLists.txt");
|
||||
if (cmakeListsTxt.exists())
|
||||
break;
|
||||
baseDirectory = baseDirectory.parentDir();
|
||||
}
|
||||
|
||||
QDir srcDirRoot = QDir(project.toString());
|
||||
QString relativePath = srcDirRoot.relativeFilePath(baseDirectory.toString());
|
||||
QDir buildDir = QDir(target()->activeBuildConfiguration()->buildDirectory().toString());
|
||||
QString generatedFilePath = buildDir.absoluteFilePath(relativePath);
|
||||
|
||||
if (fi.suffix() == "ui") {
|
||||
generatedFilePath += "/ui_";
|
||||
generatedFilePath += fi.completeBaseName();
|
||||
generatedFilePath += ".h";
|
||||
return {QDir::cleanPath(generatedFilePath)};
|
||||
}
|
||||
if (fi.suffix() == "scxml") {
|
||||
generatedFilePath += "/";
|
||||
generatedFilePath += QDir::cleanPath(fi.completeBaseName());
|
||||
return {generatedFilePath + ".h", generatedFilePath + ".cpp"};
|
||||
}
|
||||
|
||||
// TODO: Other types will be added when adapters for their compilers become available.
|
||||
return {};
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::runCMake()
|
||||
{
|
||||
BuildDirParameters parameters(m_buildConfiguration);
|
||||
m_buildDirManager.setParametersAndRequestParse(parameters,
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION
|
||||
| BuildDirManager::REPARSE_FORCE_CMAKE_RUN
|
||||
| BuildDirManager::REPARSE_URGENT);
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::runCMakeAndScanProjectTree()
|
||||
{
|
||||
BuildDirParameters parameters(m_buildConfiguration);
|
||||
m_buildDirManager.setParametersAndRequestParse(parameters,
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION
|
||||
| BuildDirManager::REPARSE_SCAN);
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::buildCMakeTarget(const QString &buildTarget)
|
||||
{
|
||||
QTC_ASSERT(!buildTarget.isEmpty(), return);
|
||||
m_buildConfiguration->buildTarget(buildTarget);
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleTreeScanningFinished()
|
||||
@@ -156,11 +311,18 @@ void CMakeBuildSystem::handleTreeScanningFinished()
|
||||
combineScanAndParse();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc)
|
||||
bool CMakeBuildSystem::persistCMakeState()
|
||||
{
|
||||
if (bc != m_currentContext.buildConfiguration)
|
||||
return; // Not current information, ignore.
|
||||
return m_buildDirManager.persistCMakeState();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::clearCMakeCache()
|
||||
{
|
||||
m_buildDirManager.clearCache();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleParsingSuccess()
|
||||
{
|
||||
QTC_ASSERT(m_waitingForParse, return );
|
||||
|
||||
m_waitingForParse = false;
|
||||
@@ -168,11 +330,8 @@ void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc)
|
||||
combineScanAndParse();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleParsingError(CMakeBuildConfiguration *bc)
|
||||
void CMakeBuildSystem::handleParsingError()
|
||||
{
|
||||
if (bc != m_currentContext.buildConfiguration)
|
||||
return; // Not current information, ignore.
|
||||
|
||||
QTC_CHECK(m_waitingForParse);
|
||||
|
||||
m_waitingForParse = false;
|
||||
@@ -181,35 +340,51 @@ void CMakeBuildSystem::handleParsingError(CMakeBuildConfiguration *bc)
|
||||
combineScanAndParse();
|
||||
}
|
||||
|
||||
std::unique_ptr<CMakeProjectNode>
|
||||
CMakeBuildSystem::generateProjectTree(const QList<const FileNode *> &allFiles)
|
||||
{
|
||||
QString errorMessage;
|
||||
auto root = m_buildDirManager.generateProjectTree(allFiles, errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
return root;
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::combineScanAndParse()
|
||||
{
|
||||
auto bc = qobject_cast<CMakeBuildConfiguration *>(m_currentContext.buildConfiguration);
|
||||
if (bc && bc->isActive()) {
|
||||
if (m_buildConfiguration->isActive()) {
|
||||
if (m_waitingForParse || m_waitingForScan)
|
||||
return;
|
||||
|
||||
if (m_combinedScanAndParseResult) {
|
||||
updateProjectData(qobject_cast<CMakeProject *>(m_currentContext.project), bc);
|
||||
m_currentContext.guard.markAsSuccess();
|
||||
updateProjectData();
|
||||
m_currentGuard.markAsSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
m_currentContext = BuildSystem::ParsingContext();
|
||||
m_currentGuard = {};
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguration *bc)
|
||||
void CMakeBuildSystem::checkAndReportError(QString &errorMessage)
|
||||
{
|
||||
if (!errorMessage.isEmpty()) {
|
||||
m_buildConfiguration->setError(errorMessage);
|
||||
errorMessage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::updateProjectData()
|
||||
{
|
||||
qCDebug(cmakeBuildSystemLog) << "Updating CMake project data";
|
||||
|
||||
QTC_ASSERT(m_treeScanner.isFinished() && !bc->m_buildDirManager.isParsing(), return );
|
||||
QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return);
|
||||
|
||||
project()->setExtraProjectFiles(bc->m_buildDirManager.takeProjectFilesToWatch());
|
||||
m_buildConfiguration->project()->setExtraProjectFiles(m_buildDirManager.takeProjectFilesToWatch());
|
||||
|
||||
CMakeConfig patchedConfig = bc->configurationFromCMake();
|
||||
CMakeConfig patchedConfig = m_buildConfiguration->configurationFromCMake();
|
||||
{
|
||||
CMakeConfigItem settingFileItem;
|
||||
settingFileItem.key = "ANDROID_DEPLOYMENT_SETTINGS_FILE";
|
||||
settingFileItem.value = bc->buildDirectory()
|
||||
settingFileItem.value = m_buildConfiguration->buildDirectory()
|
||||
.pathAppended("android_deployment_settings.json")
|
||||
.toString()
|
||||
.toUtf8();
|
||||
@@ -218,7 +393,7 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio
|
||||
{
|
||||
QSet<QString> res;
|
||||
QStringList apps;
|
||||
for (const auto &target : bc->buildTargets()) {
|
||||
for (const auto &target : m_buildTargets) {
|
||||
if (target.targetType == CMakeProjectManager::DynamicLibraryType) {
|
||||
res.insert(target.executable.parentDir().toString());
|
||||
apps.push_back(target.executable.toUserOutput());
|
||||
@@ -241,14 +416,15 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio
|
||||
}
|
||||
}
|
||||
|
||||
Project *p = project();
|
||||
{
|
||||
auto newRoot = bc->generateProjectTree(m_allFiles);
|
||||
auto newRoot = generateProjectTree(m_allFiles);
|
||||
if (newRoot) {
|
||||
p->setRootProjectNode(std::move(newRoot));
|
||||
if (p->rootProjectNode())
|
||||
p->setDisplayName(p->rootProjectNode()->displayName());
|
||||
|
||||
for (const CMakeBuildTarget &bt : bc->buildTargets()) {
|
||||
for (const CMakeBuildTarget &bt : m_buildTargets) {
|
||||
const QString buildKey = bt.title;
|
||||
if (ProjectNode *node = p->findNodeForBuildKey(buildKey)) {
|
||||
if (auto targetNode = dynamic_cast<CMakeTargetNode *>(node))
|
||||
@@ -260,7 +436,7 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio
|
||||
|
||||
{
|
||||
qDeleteAll(m_extraCompilers);
|
||||
m_extraCompilers = findExtraCompilers(p);
|
||||
m_extraCompilers = findExtraCompilers();
|
||||
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
|
||||
qCDebug(cmakeBuildSystemLog) << "Extra compilers updated.";
|
||||
}
|
||||
@@ -270,9 +446,9 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio
|
||||
|
||||
{
|
||||
QString errorMessage;
|
||||
RawProjectParts rpps = bc->m_buildDirManager.createRawProjectParts(errorMessage);
|
||||
RawProjectParts rpps = m_buildDirManager.createRawProjectParts(errorMessage);
|
||||
if (!errorMessage.isEmpty())
|
||||
bc->setError(errorMessage);
|
||||
m_buildConfiguration->setError(errorMessage);
|
||||
qCDebug(cmakeBuildSystemLog) << "Raw project parts created." << errorMessage;
|
||||
|
||||
for (RawProjectPart &rpp : rpps) {
|
||||
@@ -284,22 +460,147 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio
|
||||
rpp.setFlagsForC({kitInfo.cToolChain, rpp.flagsForC.commandLineFlags});
|
||||
}
|
||||
|
||||
m_cppCodeModelUpdater->update({p, kitInfo, bc->environment(), rpps});
|
||||
m_cppCodeModelUpdater->update({p, kitInfo, m_buildConfiguration->environment(), rpps});
|
||||
}
|
||||
{
|
||||
updateQmlJSCodeModel(p, bc);
|
||||
updateQmlJSCodeModel();
|
||||
}
|
||||
|
||||
emit p->fileListChanged();
|
||||
|
||||
emit bc->emitBuildTypeChanged();
|
||||
emit m_buildConfiguration->emitBuildTypeChanged();
|
||||
|
||||
bc->m_buildDirManager.resetData();
|
||||
m_buildDirManager.resetData();
|
||||
|
||||
qCDebug(cmakeBuildSystemLog) << "All CMake project data up to date.";
|
||||
}
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMakeProject *p)
|
||||
void CMakeBuildSystem::handleParsingSucceeded()
|
||||
{
|
||||
if (!m_buildConfiguration->isActive()) {
|
||||
m_buildDirManager.stopParsingAndClearState();
|
||||
return;
|
||||
}
|
||||
|
||||
m_buildConfiguration->clearError();
|
||||
|
||||
QString errorMessage;
|
||||
{
|
||||
m_buildTargets = m_buildDirManager.takeBuildTargets(errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
}
|
||||
|
||||
{
|
||||
const CMakeConfig cmakeConfig = m_buildDirManager.takeCMakeConfiguration(errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
m_buildConfiguration->setConfigurationFromCMake(cmakeConfig);
|
||||
}
|
||||
|
||||
setApplicationTargets(appTargets());
|
||||
setDeploymentData(deploymentData());
|
||||
|
||||
handleParsingSuccess();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleParsingFailed(const QString &msg)
|
||||
{
|
||||
m_buildConfiguration->setError(msg);
|
||||
|
||||
QString errorMessage;
|
||||
m_buildConfiguration->setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration(errorMessage));
|
||||
// ignore errorMessage here, we already got one.
|
||||
|
||||
handleParsingError();
|
||||
}
|
||||
|
||||
BuildConfiguration *CMakeBuildSystem::buildConfiguration() const
|
||||
{
|
||||
return m_buildConfiguration;
|
||||
}
|
||||
|
||||
CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const
|
||||
{
|
||||
return m_buildConfiguration;
|
||||
}
|
||||
|
||||
const QList<BuildTargetInfo> CMakeBuildSystem::appTargets() const
|
||||
{
|
||||
QList<BuildTargetInfo> appTargetList;
|
||||
const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit())
|
||||
== Android::Constants::ANDROID_DEVICE_TYPE;
|
||||
for (const CMakeBuildTarget &ct : m_buildTargets) {
|
||||
if (ct.targetType == UtilityType)
|
||||
continue;
|
||||
|
||||
if (ct.targetType == ExecutableType || (forAndroid && ct.targetType == DynamicLibraryType)) {
|
||||
BuildTargetInfo bti;
|
||||
bti.displayName = ct.title;
|
||||
bti.targetFilePath = ct.executable;
|
||||
bti.projectFilePath = ct.sourceDirectory.stringAppended("/");
|
||||
bti.workingDirectory = ct.workingDirectory;
|
||||
bti.buildKey = ct.title;
|
||||
|
||||
// Workaround for QTCREATORBUG-19354:
|
||||
bti.runEnvModifier = [this](Environment &env, bool) {
|
||||
if (HostOsInfo::isWindowsHost()) {
|
||||
const Kit *k = target()->kit();
|
||||
if (const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k))
|
||||
env.prependOrSetPath(qt->binPath().toString());
|
||||
}
|
||||
};
|
||||
|
||||
appTargetList.append(bti);
|
||||
}
|
||||
}
|
||||
|
||||
return appTargetList;
|
||||
}
|
||||
|
||||
QStringList CMakeBuildSystem::buildTargetTitles() const
|
||||
{
|
||||
return transform(m_buildTargets, &CMakeBuildTarget::title);
|
||||
}
|
||||
|
||||
const QList<CMakeBuildTarget> &CMakeBuildSystem::buildTargets() const
|
||||
{
|
||||
return m_buildTargets;
|
||||
}
|
||||
|
||||
DeploymentData CMakeBuildSystem::deploymentData() const
|
||||
{
|
||||
DeploymentData result;
|
||||
|
||||
QDir sourceDir = target()->project()->projectDirectory().toString();
|
||||
QDir buildDir = buildConfiguration()->buildDirectory().toString();
|
||||
|
||||
QString deploymentPrefix;
|
||||
QString deploymentFilePath = sourceDir.filePath("QtCreatorDeployment.txt");
|
||||
|
||||
bool hasDeploymentFile = QFileInfo::exists(deploymentFilePath);
|
||||
if (!hasDeploymentFile) {
|
||||
deploymentFilePath = buildDir.filePath("QtCreatorDeployment.txt");
|
||||
hasDeploymentFile = QFileInfo::exists(deploymentFilePath);
|
||||
}
|
||||
if (!hasDeploymentFile)
|
||||
return result;
|
||||
|
||||
deploymentPrefix = result.addFilesFromDeploymentFile(deploymentFilePath,
|
||||
sourceDir.absolutePath());
|
||||
for (const CMakeBuildTarget &ct : m_buildTargets) {
|
||||
if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) {
|
||||
if (!ct.executable.isEmpty()
|
||||
&& result.deployableForLocalFile(ct.executable).localFilePath() != ct.executable) {
|
||||
result.addFile(ct.executable.toString(),
|
||||
deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()),
|
||||
DeployableFile::TypeExecutable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers()
|
||||
{
|
||||
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: start.";
|
||||
|
||||
@@ -315,6 +616,7 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMa
|
||||
<< fileExtensions;
|
||||
|
||||
// Find all files generated by any of the extra compilers, in a rather crude way.
|
||||
Project *p = project();
|
||||
const FilePathList fileList = p->files([&fileExtensions, p](const Node *n) {
|
||||
if (!p->SourceFiles(n))
|
||||
return false;
|
||||
@@ -336,7 +638,7 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMa
|
||||
});
|
||||
QTC_ASSERT(factory, continue);
|
||||
|
||||
QStringList generated = p->filesGeneratedFrom(file.toString());
|
||||
QStringList generated = filesGeneratedFrom(file.toString());
|
||||
qCDebug(cmakeBuildSystemLog)
|
||||
<< "Finding Extra Compilers: generated files:" << generated;
|
||||
if (generated.isEmpty())
|
||||
@@ -355,19 +657,20 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMa
|
||||
return extraCompilers;
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::updateQmlJSCodeModel(CMakeProject *p, CMakeBuildConfiguration *bc)
|
||||
void CMakeBuildSystem::updateQmlJSCodeModel()
|
||||
{
|
||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
|
||||
if (!modelManager)
|
||||
return;
|
||||
|
||||
Project *p = project();
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager
|
||||
->defaultProjectInfoForProject(p);
|
||||
|
||||
projectInfo.importPaths.clear();
|
||||
|
||||
const CMakeConfig &cm = bc->configurationFromCMake();
|
||||
const CMakeConfig &cm = m_buildConfiguration->configurationFromCMake();
|
||||
const QString cmakeImports = QString::fromUtf8(CMakeConfigItem::valueOf("QML_IMPORT_PATH", cm));
|
||||
|
||||
foreach (const QString &cmakeImport, CMakeConfigItem::cmakeSplitValue(cmakeImports))
|
||||
@@ -376,4 +679,5 @@ void CMakeBuildSystem::updateQmlJSCodeModel(CMakeProject *p, CMakeBuildConfigura
|
||||
modelManager->updateProjectInfo(projectInfo, p);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
@@ -25,8 +25,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "builddirmanager.h"
|
||||
|
||||
#include <projectexplorer/buildsystem.h>
|
||||
|
||||
namespace ProjectExplorer { class ExtraCompiler; }
|
||||
|
||||
namespace CppTools {
|
||||
class CppProjectUpdater;
|
||||
} // namespace CppTools
|
||||
@@ -37,7 +41,6 @@ class CMakeProject;
|
||||
|
||||
namespace Internal {
|
||||
class CMakeBuildConfiguration;
|
||||
} // namespace Internal
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CMakeBuildSystem:
|
||||
@@ -48,12 +51,10 @@ class CMakeBuildSystem : public ProjectExplorer::BuildSystem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CMakeBuildSystem(ProjectExplorer::Project *project);
|
||||
explicit CMakeBuildSystem(CMakeBuildConfiguration *bc);
|
||||
~CMakeBuildSystem() final;
|
||||
|
||||
protected:
|
||||
bool validateParsingContext(const ParsingContext &ctx) final;
|
||||
void parseProject(ParsingContext &&ctx) final;
|
||||
void triggerParsing() final;
|
||||
|
||||
bool supportsAction(ProjectExplorer::Node *context,
|
||||
ProjectExplorer::ProjectAction action,
|
||||
@@ -62,20 +63,49 @@ protected:
|
||||
bool addFiles(ProjectExplorer::Node *context,
|
||||
const QStringList &filePaths, QStringList *) final;
|
||||
|
||||
private:
|
||||
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
|
||||
|
||||
void runCMake();
|
||||
void runCMakeAndScanProjectTree();
|
||||
|
||||
// Context menu actions:
|
||||
void buildCMakeTarget(const QString &buildTarget);
|
||||
// Treescanner states:
|
||||
void handleTreeScanningFinished();
|
||||
|
||||
bool persistCMakeState();
|
||||
void clearCMakeCache();
|
||||
|
||||
// Parser states:
|
||||
void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc);
|
||||
void handleParsingError(Internal::CMakeBuildConfiguration *bc);
|
||||
void handleParsingSuccess();
|
||||
void handleParsingError();
|
||||
|
||||
ProjectExplorer::BuildConfiguration *buildConfiguration() const;
|
||||
CMakeBuildConfiguration *cmakeBuildConfiguration() const;
|
||||
|
||||
const QList<ProjectExplorer::BuildTargetInfo> appTargets() const;
|
||||
QStringList buildTargetTitles() const;
|
||||
const QList<CMakeBuildTarget> &buildTargets() const;
|
||||
ProjectExplorer::DeploymentData deploymentData() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<CMakeProjectNode> generateProjectTree(
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles);
|
||||
|
||||
// Combining Treescanner and Parser states:
|
||||
void combineScanAndParse();
|
||||
|
||||
void updateProjectData(CMakeProject *p, Internal::CMakeBuildConfiguration *bc);
|
||||
QList<ProjectExplorer::ExtraCompiler *> findExtraCompilers(CMakeProject *p);
|
||||
void updateQmlJSCodeModel(CMakeProject *p, Internal::CMakeBuildConfiguration *bc);
|
||||
void checkAndReportError(QString &errorMessage);
|
||||
|
||||
void updateProjectData();
|
||||
QList<ProjectExplorer::ExtraCompiler *> findExtraCompilers();
|
||||
void updateQmlJSCodeModel();
|
||||
|
||||
void handleParsingSucceeded();
|
||||
void handleParsingFailed(const QString &msg);
|
||||
|
||||
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
|
||||
BuildDirManager m_buildDirManager;
|
||||
|
||||
ProjectExplorer::TreeScanner m_treeScanner;
|
||||
QHash<QString, bool> m_mimeBinaryCache;
|
||||
@@ -85,12 +115,12 @@ private:
|
||||
bool m_waitingForParse = false;
|
||||
bool m_combinedScanAndParseResult = false;
|
||||
|
||||
ParsingContext m_currentContext;
|
||||
ParseGuard m_currentGuard;
|
||||
|
||||
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
|
||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||
|
||||
friend class Internal::CMakeBuildConfiguration; // For handleParsing* callbacks
|
||||
QList<CMakeBuildTarget> m_buildTargets;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
@@ -66,12 +66,11 @@ void CMakeTargetLocatorFilter::prepareSearch(const QString &entry)
|
||||
auto cmakeProject = qobject_cast<const CMakeProject *>(p);
|
||||
if (!cmakeProject || !cmakeProject->activeTarget())
|
||||
continue;
|
||||
auto bc = qobject_cast<CMakeBuildConfiguration *>(
|
||||
cmakeProject->activeTarget()->activeBuildConfiguration());
|
||||
if (!bc)
|
||||
auto bs = qobject_cast<CMakeBuildSystem *>(cmakeProject->activeTarget()->buildSystem());
|
||||
if (!bs)
|
||||
continue;
|
||||
|
||||
const QList<CMakeBuildTarget> buildTargets = bc->buildTargets();
|
||||
const QList<CMakeBuildTarget> buildTargets = bs->buildTargets();
|
||||
for (const CMakeBuildTarget &target : buildTargets) {
|
||||
const int index = target.title.indexOf(entry);
|
||||
if (index >= 0) {
|
||||
|
||||
@@ -68,11 +68,6 @@ namespace CMakeProjectManager {
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
static CMakeBuildConfiguration *activeBc(const CMakeProject *p)
|
||||
{
|
||||
return qobject_cast<CMakeBuildConfiguration *>(p->activeTarget() ? p->activeTarget()->activeBuildConfiguration() : nullptr);
|
||||
}
|
||||
|
||||
// QtCreator CMake Generator wishlist:
|
||||
// Which make targets we need to build to get all executables
|
||||
// What is the actual compiler executable
|
||||
@@ -90,8 +85,6 @@ CMakeProject::CMakeProject(const FilePath &fileName)
|
||||
setCanBuildProducts();
|
||||
setKnowsAllBuildExecutables(false);
|
||||
setHasMakeInstallEquivalent(true);
|
||||
|
||||
setBuildSystemCreator([](Project *p) { return new CMakeBuildSystem(p); });
|
||||
}
|
||||
|
||||
CMakeProject::~CMakeProject() = default;
|
||||
@@ -108,38 +101,6 @@ Tasks CMakeProject::projectIssues(const Kit *k) const
|
||||
return result;
|
||||
}
|
||||
|
||||
void CMakeProject::runCMake()
|
||||
{
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
if (isParsing() || !bc)
|
||||
return;
|
||||
|
||||
BuildDirParameters parameters(bc);
|
||||
bc->m_buildDirManager.setParametersAndRequestParse(parameters,
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION
|
||||
| BuildDirManager::REPARSE_FORCE_CMAKE_RUN
|
||||
| BuildDirManager::REPARSE_URGENT);
|
||||
}
|
||||
|
||||
void CMakeProject::runCMakeAndScanProjectTree()
|
||||
{
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
if (isParsing() || !bc)
|
||||
return;
|
||||
|
||||
BuildDirParameters parameters(bc);
|
||||
bc->m_buildDirManager.setParametersAndRequestParse(parameters,
|
||||
BuildDirManager::REPARSE_CHECK_CONFIGURATION
|
||||
| BuildDirManager::REPARSE_SCAN);
|
||||
}
|
||||
|
||||
void CMakeProject::buildCMakeTarget(const QString &buildTarget)
|
||||
{
|
||||
QTC_ASSERT(!buildTarget.isEmpty(), return);
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
if (bc)
|
||||
bc->buildTarget(buildTarget);
|
||||
}
|
||||
|
||||
ProjectImporter *CMakeProject::projectImporter() const
|
||||
{
|
||||
@@ -148,19 +109,6 @@ ProjectImporter *CMakeProject::projectImporter() const
|
||||
return m_projectImporter.get();
|
||||
}
|
||||
|
||||
bool CMakeProject::persistCMakeState()
|
||||
{
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
return bc ? bc->m_buildDirManager.persistCMakeState() : false;
|
||||
}
|
||||
|
||||
void CMakeProject::clearCMakeCache()
|
||||
{
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
if (bc)
|
||||
bc->m_buildDirManager.clearCache();
|
||||
}
|
||||
|
||||
bool CMakeProject::setupTarget(Target *t)
|
||||
{
|
||||
t->updateDefaultBuildConfigurations();
|
||||
@@ -170,42 +118,6 @@ bool CMakeProject::setupTarget(Target *t)
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList CMakeProject::filesGeneratedFrom(const QString &sourceFile) const
|
||||
{
|
||||
if (!activeTarget())
|
||||
return QStringList();
|
||||
QFileInfo fi(sourceFile);
|
||||
FilePath project = projectDirectory();
|
||||
FilePath baseDirectory = FilePath::fromString(fi.absolutePath());
|
||||
|
||||
while (baseDirectory.isChildOf(project)) {
|
||||
const FilePath cmakeListsTxt = baseDirectory.pathAppended("CMakeLists.txt");
|
||||
if (cmakeListsTxt.exists())
|
||||
break;
|
||||
baseDirectory = baseDirectory.parentDir();
|
||||
}
|
||||
|
||||
QDir srcDirRoot = QDir(project.toString());
|
||||
QString relativePath = srcDirRoot.relativeFilePath(baseDirectory.toString());
|
||||
QDir buildDir = QDir(activeTarget()->activeBuildConfiguration()->buildDirectory().toString());
|
||||
QString generatedFilePath = buildDir.absoluteFilePath(relativePath);
|
||||
|
||||
if (fi.suffix() == "ui") {
|
||||
generatedFilePath += "/ui_";
|
||||
generatedFilePath += fi.completeBaseName();
|
||||
generatedFilePath += ".h";
|
||||
return QStringList(QDir::cleanPath(generatedFilePath));
|
||||
} else if (fi.suffix() == "scxml") {
|
||||
generatedFilePath += "/";
|
||||
generatedFilePath += QDir::cleanPath(fi.completeBaseName());
|
||||
return QStringList({generatedFilePath + ".h",
|
||||
generatedFilePath + ".cpp"});
|
||||
} else {
|
||||
// TODO: Other types will be added when adapters for their compilers become available.
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
ProjectExplorer::DeploymentKnowledge CMakeProject::deploymentKnowledge() const
|
||||
{
|
||||
return !files([](const ProjectExplorer::Node *n) {
|
||||
@@ -232,9 +144,4 @@ MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target,
|
||||
return cmd;
|
||||
}
|
||||
|
||||
bool CMakeProject::mustUpdateCMakeStateBeforeBuild() const
|
||||
{
|
||||
return buildSystem()->isWaitingForParse();
|
||||
}
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
||||
@@ -49,24 +49,12 @@ public:
|
||||
|
||||
ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
|
||||
|
||||
void runCMake();
|
||||
void runCMakeAndScanProjectTree();
|
||||
|
||||
// Context menu actions:
|
||||
void buildCMakeTarget(const QString &buildTarget);
|
||||
|
||||
ProjectExplorer::ProjectImporter *projectImporter() const final;
|
||||
|
||||
bool persistCMakeState();
|
||||
void clearCMakeCache();
|
||||
bool mustUpdateCMakeStateBeforeBuild() const;
|
||||
|
||||
protected:
|
||||
bool setupTarget(ProjectExplorer::Target *t) final;
|
||||
|
||||
private:
|
||||
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
|
||||
|
||||
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
|
||||
ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target,
|
||||
const QString &installRoot) override;
|
||||
|
||||
@@ -78,7 +78,7 @@ CMakeManager::CMakeManager() :
|
||||
command->setAttribute(Core::Command::CA_Hide);
|
||||
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
|
||||
connect(m_runCMakeAction, &QAction::triggered, [this]() {
|
||||
runCMake(SessionManager::startupProject());
|
||||
runCMake(SessionManager::startupBuildSystem());
|
||||
});
|
||||
|
||||
command = Core::ActionManager::registerAction(m_clearCMakeCacheAction,
|
||||
@@ -86,7 +86,7 @@ CMakeManager::CMakeManager() :
|
||||
command->setAttribute(Core::Command::CA_Hide);
|
||||
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
|
||||
connect(m_clearCMakeCacheAction, &QAction::triggered, [this]() {
|
||||
clearCMakeCache(SessionManager::startupProject());
|
||||
clearCMakeCache(SessionManager::startupBuildSystem());
|
||||
});
|
||||
|
||||
command = Core::ActionManager::registerAction(m_runCMakeActionContextMenu,
|
||||
@@ -95,7 +95,7 @@ CMakeManager::CMakeManager() :
|
||||
mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
|
||||
msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
|
||||
connect(m_runCMakeActionContextMenu, &QAction::triggered, [this]() {
|
||||
runCMake(ProjectTree::currentProject());
|
||||
runCMake(ProjectTree::currentBuildSystem());
|
||||
});
|
||||
|
||||
m_buildFileContextMenu = new QAction(tr("Build"), this);
|
||||
@@ -111,7 +111,7 @@ CMakeManager::CMakeManager() :
|
||||
command->setAttribute(Core::Command::CA_Hide);
|
||||
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY);
|
||||
connect(m_rescanProjectAction, &QAction::triggered, [this]() {
|
||||
rescanProject(ProjectTree::currentProject());
|
||||
rescanProject(ProjectTree::currentBuildSystem());
|
||||
});
|
||||
|
||||
m_buildFileAction = new Utils::ParameterAction(tr("Build File"), tr("Build File \"%1\""),
|
||||
@@ -146,34 +146,29 @@ void CMakeManager::updateCmakeActions()
|
||||
enableBuildFileMenus(ProjectTree::currentNode());
|
||||
}
|
||||
|
||||
void CMakeManager::clearCMakeCache(Project *project)
|
||||
void CMakeManager::clearCMakeCache(BuildSystem *buildSystem)
|
||||
{
|
||||
auto cmakeProject = qobject_cast<CMakeProject *>(project);
|
||||
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
|
||||
return;
|
||||
auto cmakeBuildSystem = dynamic_cast<CMakeBuildSystem *>(buildSystem);
|
||||
QTC_ASSERT(cmakeBuildSystem, return);
|
||||
|
||||
cmakeProject->clearCMakeCache();
|
||||
cmakeBuildSystem->clearCMakeCache();
|
||||
}
|
||||
|
||||
void CMakeManager::runCMake(Project *project)
|
||||
void CMakeManager::runCMake(BuildSystem *buildSystem)
|
||||
{
|
||||
auto cmakeProject = qobject_cast<CMakeProject *>(project);
|
||||
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
|
||||
return;
|
||||
auto cmakeBuildSystem = dynamic_cast<CMakeBuildSystem *>(buildSystem);
|
||||
QTC_ASSERT(cmakeBuildSystem, return);
|
||||
|
||||
if (!ProjectExplorerPlugin::saveModifiedFiles())
|
||||
return;
|
||||
|
||||
cmakeProject->runCMake();
|
||||
if (ProjectExplorerPlugin::saveModifiedFiles())
|
||||
cmakeBuildSystem->runCMake();
|
||||
}
|
||||
|
||||
void CMakeManager::rescanProject(Project *project)
|
||||
void CMakeManager::rescanProject(BuildSystem *buildSystem)
|
||||
{
|
||||
auto cmakeProject = qobject_cast<CMakeProject *>(project);
|
||||
if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration())
|
||||
return;
|
||||
auto cmakeBuildSystem = dynamic_cast<CMakeBuildSystem *>(buildSystem);
|
||||
QTC_ASSERT(cmakeBuildSystem, return);
|
||||
|
||||
cmakeProject->runCMakeAndScanProjectTree();// by my experience: every rescan run requires cmake run too
|
||||
cmakeBuildSystem->runCMakeAndScanProjectTree();// by my experience: every rescan run requires cmake run too
|
||||
}
|
||||
|
||||
void CMakeManager::updateBuildFileAction()
|
||||
@@ -235,14 +230,15 @@ void CMakeManager::buildFile(Node *node)
|
||||
CMakeTargetNode *targetNode = dynamic_cast<CMakeTargetNode *>(fileNode->parentProjectNode());
|
||||
if (!targetNode)
|
||||
return;
|
||||
auto cmakeProject = static_cast<CMakeProject *>(project);
|
||||
Target *target = cmakeProject->activeTarget();
|
||||
Target *target = project->activeTarget();
|
||||
QTC_ASSERT(target, return);
|
||||
const QString generator = CMakeGeneratorKitAspect::generator(target->kit());
|
||||
const QString relativeSource = fileNode->filePath().relativeChildPath(targetNode->filePath()).toString();
|
||||
const QString objExtension = Utils::HostOsInfo::isWindowsHost() ? QString(".obj") : QString(".o");
|
||||
Utils::FilePath targetBase;
|
||||
BuildConfiguration *bc = target->activeBuildConfiguration();
|
||||
QTC_ASSERT(bc, return);
|
||||
if (generator == "Ninja") {
|
||||
BuildConfiguration *bc = target->activeBuildConfiguration();
|
||||
const Utils::FilePath relativeBuildDir = targetNode->buildDirectory().relativeChildPath(
|
||||
bc->buildDirectory());
|
||||
targetBase = relativeBuildDir
|
||||
@@ -253,7 +249,9 @@ void CMakeManager::buildFile(Node *node)
|
||||
.arg(generator));
|
||||
return;
|
||||
}
|
||||
cmakeProject->buildCMakeTarget(targetBase.pathAppended(relativeSource).toString() + objExtension);
|
||||
|
||||
static_cast<CMakeBuildSystem *>(bc->buildSystem())
|
||||
->buildCMakeTarget(targetBase.pathAppended(relativeSource).toString() + objExtension);
|
||||
}
|
||||
|
||||
void CMakeManager::buildFileContextMenu()
|
||||
|
||||
@@ -45,9 +45,9 @@ public:
|
||||
|
||||
private:
|
||||
void updateCmakeActions();
|
||||
void clearCMakeCache(ProjectExplorer::Project *project);
|
||||
void runCMake(ProjectExplorer::Project *project);
|
||||
void rescanProject(ProjectExplorer::Project *project);
|
||||
void clearCMakeCache(ProjectExplorer::BuildSystem *buildSystem);
|
||||
void runCMake(ProjectExplorer::BuildSystem *buildSystem);
|
||||
void rescanProject(ProjectExplorer::BuildSystem *buildSystem);
|
||||
void buildFileContextMenu();
|
||||
void buildFile(ProjectExplorer::Node *node = nullptr);
|
||||
void updateBuildFileAction();
|
||||
|
||||
@@ -265,7 +265,10 @@ Utils::optional<Utils::FilePath> CMakeTargetNode::visibleAfterAddFileAction() co
|
||||
|
||||
void CMakeTargetNode::build()
|
||||
{
|
||||
static_cast<CMakeProject *>(getProject())->buildCMakeTarget(displayName());
|
||||
Project *p = getProject();
|
||||
Target *t = p ? p->activeTarget() : nullptr;
|
||||
if (t)
|
||||
static_cast<CMakeBuildSystem *>(t->buildSystem())->buildCMakeTarget(displayName());
|
||||
}
|
||||
|
||||
void CMakeTargetNode::setTargetInformation(const QList<Utils::FilePath> &artifacts,
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <projectexplorer/projecttree.h>
|
||||
#include <projectexplorer/runcontrol.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <texteditor/snippets/snippetprovider.h>
|
||||
|
||||
@@ -70,8 +71,6 @@ public:
|
||||
ParameterAction::AlwaysEnabled/*handled manually*/
|
||||
};
|
||||
|
||||
QMetaObject::Connection m_actionConnect;
|
||||
|
||||
CMakeSettingsPage settingsPage;
|
||||
CMakeSpecificSettingsPage specificSettings{CMakeProjectPlugin::projectTypeSpecificSettings()};
|
||||
|
||||
@@ -129,6 +128,13 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
|
||||
connect(ProjectTree::instance(), &ProjectTree::currentNodeChanged,
|
||||
this, &CMakeProjectPlugin::updateContextActions);
|
||||
|
||||
connect(&d->buildTargetContextAction, &ParameterAction::triggered, this, [] {
|
||||
if (auto bs = qobject_cast<CMakeBuildSystem *>(ProjectTree::currentBuildSystem())) {
|
||||
auto targetNode = dynamic_cast<const CMakeTargetNode *>(ProjectTree::currentNode());
|
||||
bs->buildCMakeTarget(targetNode ? targetNode->displayName() : QString());
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -140,24 +146,13 @@ void CMakeProjectPlugin::extensionsInitialized()
|
||||
|
||||
void CMakeProjectPlugin::updateContextActions()
|
||||
{
|
||||
Project *project = ProjectTree::currentProject();
|
||||
const Node *node = ProjectTree::currentNode();
|
||||
auto targetNode = dynamic_cast<const CMakeTargetNode *>(node);
|
||||
// as targetNode can be deleted while the menu is open, we keep only the
|
||||
auto targetNode = dynamic_cast<const CMakeTargetNode *>(ProjectTree::currentNode());
|
||||
const QString targetDisplayName = targetNode ? targetNode->displayName() : QString();
|
||||
auto cmProject = dynamic_cast<CMakeProject *>(project);
|
||||
|
||||
// Build Target:
|
||||
disconnect(d->m_actionConnect);
|
||||
d->buildTargetContextAction.setParameter(targetDisplayName);
|
||||
d->buildTargetContextAction.setEnabled(targetNode);
|
||||
d->buildTargetContextAction.setVisible(targetNode);
|
||||
if (cmProject && targetNode) {
|
||||
d->m_actionConnect = connect(&d->buildTargetContextAction, &ParameterAction::triggered,
|
||||
cmProject, [cmProject, targetDisplayName]() {
|
||||
cmProject->buildCMakeTarget(targetDisplayName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // Internal
|
||||
|
||||
Reference in New Issue
Block a user