forked from qt-creator/qt-creator
CMake: Move code from CMakeProject into CMakeBuildSystem
Introduce BuildSystem to implement functionality common to all build systems out there. This includes things like delaying the parsing by 1s. The actual CMake specific code is then moved into a derived class CMakeBuildSystem. Change-Id: I84f4344430f19a44e16534db294382c436169ed5 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -10,6 +10,7 @@ add_qtc_plugin(CMakeProjectManager
|
||||
cmakeautocompleter.cpp cmakeautocompleter.h
|
||||
cmakebuildconfiguration.cpp cmakebuildconfiguration.h
|
||||
cmakebuildsettingswidget.cpp cmakebuildsettingswidget.h
|
||||
cmakebuildsystem.cpp cmakebuildsystem.h
|
||||
cmakebuildstep.cpp cmakebuildstep.h
|
||||
cmakebuildtarget.h
|
||||
cmakecbpparser.cpp cmakecbpparser.h
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "builddirparameters.h"
|
||||
#include "builddirreader.h"
|
||||
#include "cmakebuildsystem.h"
|
||||
#include "cmakebuildtarget.h"
|
||||
#include "cmakeconfigitem.h"
|
||||
|
||||
@@ -87,16 +88,21 @@ public:
|
||||
CMakeConfig takeCMakeConfiguration(QString &errorMessage) const;
|
||||
|
||||
static CMakeConfig parseCMakeConfiguration(const Utils::FilePath &cacheFile,
|
||||
QString *errorMessage);
|
||||
QString *errorMessage);
|
||||
|
||||
enum ReparseParameters {
|
||||
REPARSE_DEFAULT = 0, // use defaults
|
||||
REPARSE_URGENT = 1, // Do not wait for more requests, start ASAP
|
||||
REPARSE_FORCE_CMAKE_RUN = 2, // Force cmake to run
|
||||
REPARSE_FORCE_CONFIGURATION = 4, // Force configuration arguments to cmake
|
||||
REPARSE_CHECK_CONFIGURATION = 8, // Check and warn if on-disk config and QtC config differ
|
||||
REPARSE_SCAN = 16,
|
||||
REPARSE_IGNORE = 32, // Do not reparse:-)
|
||||
REPARSE_DEFAULT = BuildSystem::PARAM_DEFAULT, // use defaults
|
||||
REPARSE_URGENT = BuildSystem::PARAM_URGENT, // Do not wait for more requests, start ASAP
|
||||
REPARSE_IGNORE = BuildSystem::PARAM_IGNORE,
|
||||
|
||||
REPARSE_FORCE_CMAKE_RUN = (1
|
||||
<< (BuildSystem::PARAM_CUSTOM_OFFSET + 0)), // Force cmake to run
|
||||
REPARSE_FORCE_CONFIGURATION = (1 << (BuildSystem::PARAM_CUSTOM_OFFSET
|
||||
+ 1)), // Force configuration arguments to cmake
|
||||
REPARSE_CHECK_CONFIGURATION
|
||||
= (1 << (BuildSystem::PARAM_CUSTOM_OFFSET
|
||||
+ 2)), // Check and warn if on-disk config and QtC config differ
|
||||
REPARSE_SCAN = (1 << (BuildSystem::PARAM_CUSTOM_OFFSET + 3)), // Run filesystem scan
|
||||
};
|
||||
|
||||
static QString flagsString(int reparseFlags);
|
||||
|
@@ -91,25 +91,24 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *parent, Core::Id id)
|
||||
BuildConfiguration::Unknown));
|
||||
connect(project(), &Project::parsingFinished, this, &BuildConfiguration::enabledChanged);
|
||||
|
||||
BuildSystem *bs = qobject_cast<CMakeBuildSystem *>(project()->buildSystem());
|
||||
|
||||
// BuildDirManager:
|
||||
connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this](int options) {
|
||||
connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this, bs](int options) {
|
||||
if (isActive()) {
|
||||
qCDebug(cmakeBuildConfigurationLog)
|
||||
<< "Passing on reparse request with flags" << BuildDirManager::flagsString(options);
|
||||
project()->requestReparse(options);
|
||||
bs->requestParse(options);
|
||||
}
|
||||
});
|
||||
connect(&m_buildDirManager,
|
||||
&BuildDirManager::dataAvailable,
|
||||
this,
|
||||
&CMakeBuildConfiguration::handleParsingSucceeded);
|
||||
connect(&m_buildDirManager, &BuildDirManager::errorOccured, this, [this](const QString &msg) {
|
||||
setError(msg);
|
||||
QString errorMessage;
|
||||
setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration(errorMessage));
|
||||
// ignore errorMessage here, we already got one.
|
||||
project()->handleParsingError(this);
|
||||
});
|
||||
connect(&m_buildDirManager,
|
||||
&BuildDirManager::errorOccured,
|
||||
this,
|
||||
&CMakeBuildConfiguration::handleParsingFailed);
|
||||
connect(&m_buildDirManager, &BuildDirManager::parsingStarted, this, [this]() {
|
||||
clearError(CMakeBuildConfiguration::ForceEnabledChanged::True);
|
||||
});
|
||||
@@ -538,7 +537,18 @@ void CMakeBuildConfiguration::handleParsingSucceeded()
|
||||
target()->setDeploymentData(deploymentData());
|
||||
}
|
||||
|
||||
project()->handleParsingSuccess(this);
|
||||
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(
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <projectexplorer/deploymentdata.h>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
class CMakeBuildSystem;
|
||||
class CMakeExtraBuildInfo;
|
||||
class CMakeProject;
|
||||
|
||||
@@ -106,6 +107,7 @@ private:
|
||||
void setWarning(const QString &message);
|
||||
|
||||
void handleParsingSucceeded();
|
||||
void handleParsingFailed(const QString &msg);
|
||||
|
||||
std::unique_ptr<CMakeProjectNode> generateProjectTree(
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles);
|
||||
@@ -123,6 +125,7 @@ private:
|
||||
QList<CMakeBuildTarget> m_buildTargets;
|
||||
|
||||
friend class CMakeBuildSettingsWidget;
|
||||
friend class CMakeProjectManager::CMakeBuildSystem;
|
||||
friend class CMakeProjectManager::CMakeProject;
|
||||
friend class BuildDirManager;
|
||||
};
|
||||
|
483
src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
Normal file
483
src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
Normal file
@@ -0,0 +1,483 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "cmakebuildsystem.h"
|
||||
|
||||
#include "cmakebuildconfiguration.h"
|
||||
#include "cmakeproject.h"
|
||||
#include "cmakeprojectconstants.h"
|
||||
#include "cmakeprojectnodes.h"
|
||||
|
||||
#if 0
|
||||
#include "cmakebuildstep.h"
|
||||
#include "cmakekitinformation.h"
|
||||
#include "cmakeprojectmanager.h"
|
||||
#include "cmakeprojectnodes.h"
|
||||
|
||||
#include <cpptools/cpprawprojectpart.h>
|
||||
#include <cpptools/cpptoolsconstants.h>
|
||||
|
||||
#include <cpptools/projectinfo.h>
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/buildtargetinfo.h>
|
||||
#include <projectexplorer/deploymentdata.h>
|
||||
#include <projectexplorer/headerpath.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qtsupport/baseqtversion.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
#include <utils/stringutils.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QSet>
|
||||
#endif
|
||||
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <cpptools/cppprojectupdater.h>
|
||||
#include <cpptools/generatedcodemodelsupport.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qtsupport/qtcppkitinfo.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/mimetypes/mimetype.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace {
|
||||
|
||||
CMakeProjectManager::Internal::CMakeBuildConfiguration *activeBc(Project *p)
|
||||
{
|
||||
if (!p)
|
||||
return nullptr;
|
||||
|
||||
return qobject_cast<CMakeProjectManager::Internal::CMakeBuildConfiguration *>(
|
||||
p->activeTarget() ? p->activeTarget()->activeBuildConfiguration() : nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BuildSystem::BuildSystem(Project *project)
|
||||
: m_project(project)
|
||||
{
|
||||
QTC_CHECK(project);
|
||||
|
||||
// Timer:
|
||||
m_delayedParsingTimer.setSingleShot(true);
|
||||
|
||||
connect(&m_delayedParsingTimer, &QTimer::timeout, this, &BuildSystem::triggerParsing);
|
||||
}
|
||||
|
||||
BuildSystem::~BuildSystem() = default;
|
||||
|
||||
Project *BuildSystem::project() const
|
||||
{
|
||||
return m_project;
|
||||
}
|
||||
|
||||
bool BuildSystem::isWaitingForParse() const
|
||||
{
|
||||
return m_delayedParsingTimer.isActive();
|
||||
}
|
||||
|
||||
void BuildSystem::requestParse(int reparseParameters)
|
||||
{
|
||||
QTC_ASSERT(!(reparseParameters & PARAM_ERROR), return );
|
||||
if (reparseParameters & PARAM_IGNORE)
|
||||
return;
|
||||
|
||||
m_delayedParsingTimer.setInterval((reparseParameters & PARAM_URGENT) ? 0 : 1000);
|
||||
m_delayedParsingTimer.start();
|
||||
m_delayedParsingParameters = m_delayedParsingParameters | reparseParameters;
|
||||
}
|
||||
|
||||
void BuildSystem::triggerParsing()
|
||||
{
|
||||
int parameters = m_delayedParsingParameters;
|
||||
m_delayedParsingParameters = BuildSystem::PARAM_DEFAULT;
|
||||
|
||||
QTC_CHECK(!m_project->isParsing());
|
||||
QTC_ASSERT((parameters & BuildSystem::PARAM_ERROR) == 0, return );
|
||||
if (parameters & BuildSystem::PARAM_IGNORE)
|
||||
return;
|
||||
|
||||
// Clear buildsystem specific parameters before passing them on!
|
||||
parameters = parameters
|
||||
& ~(BuildSystem::PARAM_ERROR | BuildSystem::PARAM_IGNORE
|
||||
| BuildSystem::PARAM_URGENT);
|
||||
|
||||
{
|
||||
ParsingContext ctx(m_project->guardParsingRun(), parameters, m_project, activeBc(m_project));
|
||||
if (validateParsingContext(ctx))
|
||||
parseProject(std::move(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CMakeBuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
CMakeBuildSystem::CMakeBuildSystem(CMakeProject *p)
|
||||
: BuildSystem(p)
|
||||
, m_cppCodeModelUpdater(new CppTools::CppProjectUpdater)
|
||||
{
|
||||
// TreeScanner:
|
||||
connect(&m_treeScanner,
|
||||
&TreeScanner::finished,
|
||||
this,
|
||||
&CMakeBuildSystem::handleTreeScanningFinished);
|
||||
|
||||
m_treeScanner.setFilter([this, p](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
|
||||
// Mime checks requires more resources, so keep it last in check list
|
||||
auto isIgnored = fn.toString().startsWith(p->projectFilePath().toString() + ".user")
|
||||
|| TreeScanner::isWellKnownBinary(mimeType, fn);
|
||||
|
||||
// Cache mime check result for speed up
|
||||
if (!isIgnored) {
|
||||
auto it = m_mimeBinaryCache.find(mimeType.name());
|
||||
if (it != m_mimeBinaryCache.end()) {
|
||||
isIgnored = *it;
|
||||
} else {
|
||||
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
|
||||
m_mimeBinaryCache[mimeType.name()] = isIgnored;
|
||||
}
|
||||
}
|
||||
|
||||
return isIgnored;
|
||||
});
|
||||
|
||||
m_treeScanner.setTypeFactory([](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
|
||||
auto type = TreeScanner::genericFileType(mimeType, fn);
|
||||
if (type == FileType::Unknown) {
|
||||
if (mimeType.isValid()) {
|
||||
const QString mt = mimeType.name();
|
||||
if (mt == CMakeProjectManager::Constants::CMAKEPROJECTMIMETYPE
|
||||
|| mt == CMakeProjectManager::Constants::CMAKEMIMETYPE)
|
||||
type = FileType::Project;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
CMakeBuildSystem::~CMakeBuildSystem()
|
||||
{
|
||||
if (!m_treeScanner.isFinished()) {
|
||||
auto future = m_treeScanner.future();
|
||||
future.cancel();
|
||||
future.waitForFinished();
|
||||
}
|
||||
delete m_cppCodeModelUpdater;
|
||||
qDeleteAll(m_extraCompilers);
|
||||
qDeleteAll(m_allFiles);
|
||||
}
|
||||
|
||||
bool CMakeBuildSystem::validateParsingContext(const ParsingContext &ctx)
|
||||
{
|
||||
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);
|
||||
|
||||
int parameters = m_currentContext.parameters;
|
||||
|
||||
if (m_allFiles.isEmpty())
|
||||
parameters |= BuildDirManager::REPARSE_SCAN;
|
||||
|
||||
m_waitingForScan = parameters & BuildDirManager::REPARSE_SCAN;
|
||||
m_waitingForParse = true;
|
||||
m_combinedScanAndParseResult = true;
|
||||
|
||||
if (m_waitingForScan) {
|
||||
QTC_CHECK(m_treeScanner.isFinished());
|
||||
m_treeScanner.asyncScanForFiles(m_currentContext.project->projectDirectory());
|
||||
Core::ProgressManager::addTask(m_treeScanner.future(),
|
||||
tr("Scan \"%1\" project tree")
|
||||
.arg(m_currentContext.project->displayName()),
|
||||
"CMake.Scan.Tree");
|
||||
}
|
||||
|
||||
bc->m_buildDirManager.parse(parameters);
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleTreeScanningFinished()
|
||||
{
|
||||
QTC_CHECK(m_waitingForScan);
|
||||
|
||||
qDeleteAll(m_allFiles);
|
||||
m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; });
|
||||
|
||||
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
|
||||
m_waitingForScan = false;
|
||||
|
||||
combineScanAndParse();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
if (bc != m_currentContext.buildConfiguration)
|
||||
return; // Not current information, ignore.
|
||||
|
||||
QTC_ASSERT(m_waitingForParse, return );
|
||||
|
||||
m_waitingForParse = false;
|
||||
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
|
||||
|
||||
combineScanAndParse();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::handleParsingError(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
if (bc != m_currentContext.buildConfiguration)
|
||||
return; // Not current information, ignore.
|
||||
|
||||
QTC_CHECK(m_waitingForParse);
|
||||
|
||||
m_waitingForParse = false;
|
||||
m_combinedScanAndParseResult = false;
|
||||
|
||||
combineScanAndParse();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::combineScanAndParse()
|
||||
{
|
||||
auto bc = qobject_cast<CMakeBuildConfiguration *>(m_currentContext.buildConfiguration);
|
||||
if (bc && bc->isActive()) {
|
||||
if (m_waitingForParse || m_waitingForScan)
|
||||
return;
|
||||
|
||||
if (m_combinedScanAndParseResult) {
|
||||
updateProjectData(qobject_cast<CMakeProject *>(m_currentContext.project), bc);
|
||||
}
|
||||
}
|
||||
|
||||
m_currentContext = BuildSystem::ParsingContext();
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguration *bc)
|
||||
{
|
||||
qCDebug(cmakeBuildSystemLog) << "Updating CMake project data";
|
||||
|
||||
QTC_ASSERT(m_treeScanner.isFinished() && !bc->m_buildDirManager.isParsing(), return );
|
||||
|
||||
CMakeConfig patchedConfig = bc->configurationFromCMake();
|
||||
{
|
||||
CMakeConfigItem settingFileItem;
|
||||
settingFileItem.key = "ANDROID_DEPLOYMENT_SETTINGS_FILE";
|
||||
settingFileItem.value = bc->buildDirectory()
|
||||
.pathAppended("android_deployment_settings.json")
|
||||
.toString()
|
||||
.toUtf8();
|
||||
patchedConfig.append(settingFileItem);
|
||||
}
|
||||
{
|
||||
QSet<QString> res;
|
||||
QStringList apps;
|
||||
for (const auto &target : bc->buildTargets()) {
|
||||
if (target.targetType == CMakeProjectManager::DynamicLibraryType) {
|
||||
res.insert(target.executable.parentDir().toString());
|
||||
apps.push_back(target.executable.toUserOutput());
|
||||
}
|
||||
// ### shall we add also the ExecutableType ?
|
||||
}
|
||||
{
|
||||
CMakeConfigItem paths;
|
||||
paths.key = "ANDROID_SO_LIBS_PATHS";
|
||||
paths.values = Utils::toList(res);
|
||||
patchedConfig.append(paths);
|
||||
}
|
||||
|
||||
apps.sort();
|
||||
{
|
||||
CMakeConfigItem appsPaths;
|
||||
appsPaths.key = "TARGETS_BUILD_PATH";
|
||||
appsPaths.values = apps;
|
||||
patchedConfig.append(appsPaths);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto newRoot = bc->generateProjectTree(m_allFiles);
|
||||
if (newRoot) {
|
||||
p->setRootProjectNode(std::move(newRoot));
|
||||
if (p->rootProjectNode())
|
||||
p->setDisplayName(p->rootProjectNode()->displayName());
|
||||
|
||||
for (const CMakeBuildTarget &bt : bc->buildTargets()) {
|
||||
const QString buildKey = bt.title;
|
||||
if (ProjectNode *node = p->findNodeForBuildKey(buildKey)) {
|
||||
if (auto targetNode = dynamic_cast<CMakeTargetNode *>(node))
|
||||
targetNode->setConfig(patchedConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
qDeleteAll(m_extraCompilers);
|
||||
m_extraCompilers = findExtraCompilers(p);
|
||||
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
|
||||
qCDebug(cmakeBuildSystemLog) << "Extra compilers updated.";
|
||||
}
|
||||
|
||||
QtSupport::CppKitInfo kitInfo(p);
|
||||
QTC_ASSERT(kitInfo.isValid(), return );
|
||||
|
||||
{
|
||||
QString errorMessage;
|
||||
CppTools::RawProjectParts rpps = bc->m_buildDirManager.createRawProjectParts(errorMessage);
|
||||
if (!errorMessage.isEmpty())
|
||||
bc->setError(errorMessage);
|
||||
qCDebug(cmakeBuildSystemLog) << "Raw project parts created." << errorMessage;
|
||||
|
||||
for (CppTools::RawProjectPart &rpp : rpps) {
|
||||
rpp.setQtVersion(
|
||||
kitInfo.projectPartQtVersion); // TODO: Check if project actually uses Qt.
|
||||
if (kitInfo.cxxToolChain)
|
||||
rpp.setFlagsForCxx({kitInfo.cxxToolChain, rpp.flagsForCxx.commandLineFlags});
|
||||
if (kitInfo.cToolChain)
|
||||
rpp.setFlagsForC({kitInfo.cToolChain, rpp.flagsForC.commandLineFlags});
|
||||
}
|
||||
|
||||
m_cppCodeModelUpdater->update({p, kitInfo, bc->environment(), rpps});
|
||||
}
|
||||
{
|
||||
updateQmlJSCodeModel(p, bc);
|
||||
}
|
||||
|
||||
emit p->fileListChanged();
|
||||
|
||||
emit bc->emitBuildTypeChanged();
|
||||
|
||||
bc->m_buildDirManager.resetData();
|
||||
|
||||
qCDebug(cmakeBuildSystemLog) << "All CMake project data up to date.";
|
||||
}
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMakeProject *p)
|
||||
{
|
||||
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: start.";
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> extraCompilers;
|
||||
const QList<ExtraCompilerFactory *> factories = ExtraCompilerFactory::extraCompilerFactories();
|
||||
|
||||
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: Got factories.";
|
||||
|
||||
const QSet<QString> fileExtensions = Utils::transform<QSet>(factories,
|
||||
&ExtraCompilerFactory::sourceTag);
|
||||
|
||||
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: Got file extensions:"
|
||||
<< fileExtensions;
|
||||
|
||||
// Find all files generated by any of the extra compilers, in a rather crude way.
|
||||
const FilePathList fileList = p->files([&fileExtensions, p](const Node *n) {
|
||||
if (!p->SourceFiles(n))
|
||||
return false;
|
||||
const QString fp = n->filePath().toString();
|
||||
const int pos = fp.lastIndexOf('.');
|
||||
return pos >= 0 && fileExtensions.contains(fp.mid(pos + 1));
|
||||
});
|
||||
|
||||
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: Got list of files to check.";
|
||||
|
||||
// Generate the necessary information:
|
||||
for (const FilePath &file : fileList) {
|
||||
qCDebug(cmakeBuildSystemLog)
|
||||
<< "Finding Extra Compilers: Processing" << file.toUserOutput();
|
||||
ExtraCompilerFactory *factory = Utils::findOrDefault(factories,
|
||||
[&file](const ExtraCompilerFactory *f) {
|
||||
return file.endsWith(
|
||||
'.' + f->sourceTag());
|
||||
});
|
||||
QTC_ASSERT(factory, continue);
|
||||
|
||||
QStringList generated = p->filesGeneratedFrom(file.toString());
|
||||
qCDebug(cmakeBuildSystemLog)
|
||||
<< "Finding Extra Compilers: generated files:" << generated;
|
||||
if (generated.isEmpty())
|
||||
continue;
|
||||
|
||||
const FilePathList fileNames = transform(generated, [](const QString &s) {
|
||||
return FilePath::fromString(s);
|
||||
});
|
||||
extraCompilers.append(factory->create(p, file, fileNames));
|
||||
qCDebug(cmakeBuildSystemLog)
|
||||
<< "Finding Extra Compilers: done with" << file.toUserOutput();
|
||||
}
|
||||
|
||||
qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: done.";
|
||||
|
||||
return extraCompilers;
|
||||
}
|
||||
|
||||
void CMakeBuildSystem::updateQmlJSCodeModel(CMakeProject *p, CMakeBuildConfiguration *bc)
|
||||
{
|
||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
|
||||
if (!modelManager)
|
||||
return;
|
||||
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager
|
||||
->defaultProjectInfoForProject(p);
|
||||
|
||||
projectInfo.importPaths.clear();
|
||||
|
||||
const CMakeConfig &cm = bc->configurationFromCMake();
|
||||
const QString cmakeImports = QString::fromUtf8(CMakeConfigItem::valueOf("QML_IMPORT_PATH", cm));
|
||||
|
||||
foreach (const QString &cmakeImport, CMakeConfigItem::cmakeSplitValue(cmakeImports))
|
||||
projectInfo.importPaths.maybeInsert(FilePath::fromString(cmakeImport), QmlJS::Dialect::Qml);
|
||||
|
||||
modelManager->updateProjectInfo(projectInfo, p);
|
||||
}
|
||||
|
||||
} // namespace CMakeProjectManager
|
174
src/plugins/cmakeprojectmanager/cmakebuildsystem.h
Normal file
174
src/plugins/cmakeprojectmanager/cmakebuildsystem.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/treescanner.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace CppTools {
|
||||
class CppProjectUpdater;
|
||||
} // namespace CppTools
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class BuildConfiguration;
|
||||
class ExtraCompiler;
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
class CMakeProject;
|
||||
|
||||
namespace Internal {
|
||||
class CMakeBuildConfiguration;
|
||||
} // namespace Internal
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class BuildSystem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
const static int PARAM_CUSTOM_OFFSET = 3;
|
||||
enum Parameters : int {
|
||||
PARAM_DEFAULT = 0, // use defaults
|
||||
|
||||
PARAM_IGNORE = (1 << (PARAM_CUSTOM_OFFSET - 3)), // Ignore this request without raising a fuss
|
||||
PARAM_ERROR = (1 << (PARAM_CUSTOM_OFFSET - 2)), // Ignore this request and warn
|
||||
|
||||
PARAM_URGENT = (1 << (PARAM_CUSTOM_OFFSET - 1)), // Do not wait for more requests, start ASAP
|
||||
};
|
||||
|
||||
explicit BuildSystem(ProjectExplorer::Project *project);
|
||||
~BuildSystem() override;
|
||||
|
||||
BuildSystem(const BuildSystem &other) = delete;
|
||||
|
||||
ProjectExplorer::Project *project() const;
|
||||
|
||||
bool isWaitingForParse() const;
|
||||
void requestParse(int reparseParameters); // request a (delayed!) parser run.
|
||||
|
||||
protected:
|
||||
class ParsingContext
|
||||
{
|
||||
public:
|
||||
ParsingContext() = default;
|
||||
|
||||
ParsingContext(const ParsingContext &other) = delete;
|
||||
ParsingContext &operator=(const ParsingContext &other) = delete;
|
||||
ParsingContext(ParsingContext &&other) = default;
|
||||
ParsingContext &operator=(ParsingContext &&other) = default;
|
||||
|
||||
ProjectExplorer::Project::ParseGuard guard;
|
||||
|
||||
int parameters = PARAM_DEFAULT;
|
||||
ProjectExplorer::Project *project = nullptr;
|
||||
ProjectExplorer::BuildConfiguration *buildConfiguration = nullptr;
|
||||
|
||||
private:
|
||||
ParsingContext(ProjectExplorer::Project::ParseGuard &&g,
|
||||
int params,
|
||||
ProjectExplorer::Project *p,
|
||||
ProjectExplorer::BuildConfiguration *bc)
|
||||
: guard(std::move(g))
|
||||
, parameters(params)
|
||||
, project(p)
|
||||
, buildConfiguration(bc)
|
||||
{}
|
||||
|
||||
friend class BuildSystem;
|
||||
};
|
||||
|
||||
virtual bool validateParsingContext(const ParsingContext &ctx)
|
||||
{
|
||||
Q_UNUSED(ctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void parseProject(ParsingContext &&ctx) = 0; // actual code to parse project
|
||||
|
||||
private:
|
||||
void triggerParsing();
|
||||
|
||||
ProjectExplorer::Project *m_project;
|
||||
|
||||
QTimer m_delayedParsingTimer;
|
||||
int m_delayedParsingParameters = PARAM_DEFAULT;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CMakeBuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class CMakeBuildSystem : public BuildSystem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CMakeBuildSystem(CMakeProject *project);
|
||||
~CMakeBuildSystem() final;
|
||||
|
||||
protected:
|
||||
bool validateParsingContext(const ParsingContext &ctx) final;
|
||||
void parseProject(ParsingContext &&ctx) final;
|
||||
|
||||
private:
|
||||
// Treescanner states:
|
||||
void handleTreeScanningFinished();
|
||||
|
||||
// Parser states:
|
||||
void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc);
|
||||
void handleParsingError(Internal::CMakeBuildConfiguration *bc);
|
||||
|
||||
// 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);
|
||||
|
||||
ProjectExplorer::TreeScanner m_treeScanner;
|
||||
QHash<QString, bool> m_mimeBinaryCache;
|
||||
QList<const ProjectExplorer::FileNode *> m_allFiles;
|
||||
|
||||
bool m_waitingForScan = false;
|
||||
bool m_waitingForParse = false;
|
||||
bool m_combinedScanAndParseResult = false;
|
||||
|
||||
ParsingContext m_currentContext;
|
||||
|
||||
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
|
||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||
|
||||
friend class Internal::CMakeBuildConfiguration; // For handleParsing* callbacks
|
||||
};
|
||||
|
||||
} // namespace CMakeProjectManager
|
@@ -67,27 +67,6 @@ using namespace Utils;
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
Q_LOGGING_CATEGORY(cmakeProjectLog, "qtc.cmake.project", QtWarningMsg);
|
||||
|
||||
class TraceTimer
|
||||
{
|
||||
public:
|
||||
TraceTimer(const QString &msg)
|
||||
: m_message(msg)
|
||||
{
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
~TraceTimer()
|
||||
{
|
||||
qCInfo(cmakeProjectLog) << QString("%1 (%2ms)").arg(m_message).arg(m_timer.elapsed());
|
||||
}
|
||||
|
||||
private:
|
||||
QElapsedTimer m_timer;
|
||||
QString m_message;
|
||||
};
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
static CMakeBuildConfiguration *activeBc(const CMakeProject *p)
|
||||
@@ -105,200 +84,18 @@ static CMakeBuildConfiguration *activeBc(const CMakeProject *p)
|
||||
*/
|
||||
CMakeProject::CMakeProject(const FilePath &fileName)
|
||||
: Project(Constants::CMAKEMIMETYPE, fileName)
|
||||
, m_cppCodeModelUpdater(new CppTools::CppProjectUpdater)
|
||||
{
|
||||
m_buildsystem = std::make_unique<CMakeBuildSystem>(this);
|
||||
|
||||
setId(CMakeProjectManager::Constants::CMAKEPROJECT_ID);
|
||||
setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
|
||||
setDisplayName(projectDirectory().fileName());
|
||||
setCanBuildProducts();
|
||||
setKnowsAllBuildExecutables(false);
|
||||
setHasMakeInstallEquivalent(true);
|
||||
|
||||
// Timer:
|
||||
m_delayedParsingTimer.setSingleShot(true);
|
||||
|
||||
connect(&m_delayedParsingTimer, &QTimer::timeout,
|
||||
this, [this]() { startParsing(m_delayedParsingParameters); });
|
||||
|
||||
// TreeScanner:
|
||||
connect(&m_treeScanner, &TreeScanner::finished, this, &CMakeProject::handleTreeScanningFinished);
|
||||
|
||||
m_treeScanner.setFilter([this](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
|
||||
// Mime checks requires more resources, so keep it last in check list
|
||||
auto isIgnored =
|
||||
fn.toString().startsWith(projectFilePath().toString() + ".user") ||
|
||||
TreeScanner::isWellKnownBinary(mimeType, fn);
|
||||
|
||||
// Cache mime check result for speed up
|
||||
if (!isIgnored) {
|
||||
auto it = m_mimeBinaryCache.find(mimeType.name());
|
||||
if (it != m_mimeBinaryCache.end()) {
|
||||
isIgnored = *it;
|
||||
} else {
|
||||
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
|
||||
m_mimeBinaryCache[mimeType.name()] = isIgnored;
|
||||
}
|
||||
}
|
||||
|
||||
return isIgnored;
|
||||
});
|
||||
|
||||
m_treeScanner.setTypeFactory([](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
|
||||
auto type = TreeScanner::genericFileType(mimeType, fn);
|
||||
if (type == FileType::Unknown) {
|
||||
if (mimeType.isValid()) {
|
||||
const QString mt = mimeType.name();
|
||||
if (mt == CMakeProjectManager::Constants::CMAKEPROJECTMIMETYPE
|
||||
|| mt == CMakeProjectManager::Constants::CMAKEMIMETYPE)
|
||||
type = FileType::Project;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
CMakeProject::~CMakeProject()
|
||||
{
|
||||
if (!m_treeScanner.isFinished()) {
|
||||
auto future = m_treeScanner.future();
|
||||
future.cancel();
|
||||
future.waitForFinished();
|
||||
}
|
||||
delete m_cppCodeModelUpdater;
|
||||
qDeleteAll(m_extraCompilers);
|
||||
qDeleteAll(m_allFiles);
|
||||
}
|
||||
|
||||
void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
TraceTimer updateProjectTotalTimer(Q_FUNC_INFO);
|
||||
qCDebug(cmakeProjectLog) << "Updating CMake project data";
|
||||
const CMakeBuildConfiguration *aBc = activeBc(this);
|
||||
QString errorMessage;
|
||||
|
||||
QTC_ASSERT(bc, return);
|
||||
QTC_ASSERT(bc == aBc, return);
|
||||
QTC_ASSERT(m_treeScanner.isFinished() && !bc->m_buildDirManager.isParsing(), return );
|
||||
|
||||
CMakeConfig patchedConfig = bc->configurationFromCMake();
|
||||
{
|
||||
CMakeConfigItem settingFileItem;
|
||||
settingFileItem.key = "ANDROID_DEPLOYMENT_SETTINGS_FILE";
|
||||
settingFileItem.value = bc->buildDirectory()
|
||||
.pathAppended("android_deployment_settings.json")
|
||||
.toString()
|
||||
.toUtf8();
|
||||
patchedConfig.append(settingFileItem);
|
||||
}
|
||||
{
|
||||
TraceTimer appsTimer(" application data");
|
||||
QSet<QString> res;
|
||||
QStringList apps;
|
||||
for (const auto &target : bc->buildTargets()) {
|
||||
if (target.targetType == CMakeProjectManager::DynamicLibraryType) {
|
||||
res.insert(target.executable.parentDir().toString());
|
||||
apps.push_back(target.executable.toUserOutput());
|
||||
}
|
||||
// ### shall we add also the ExecutableType ?
|
||||
}
|
||||
{
|
||||
CMakeConfigItem paths;
|
||||
paths.key = "ANDROID_SO_LIBS_PATHS";
|
||||
paths.values = Utils::toList(res);
|
||||
patchedConfig.append(paths);
|
||||
}
|
||||
|
||||
apps.sort();
|
||||
{
|
||||
CMakeConfigItem appsPaths;
|
||||
appsPaths.key = "TARGETS_BUILD_PATH";
|
||||
appsPaths.values = apps;
|
||||
patchedConfig.append(appsPaths);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TraceTimer projectTreeTimer(" project tree");
|
||||
auto newRoot = bc->generateProjectTree(m_allFiles);
|
||||
if (newRoot) {
|
||||
setRootProjectNode(std::move(newRoot));
|
||||
if (rootProjectNode())
|
||||
setDisplayName(rootProjectNode()->displayName());
|
||||
|
||||
for (const CMakeBuildTarget &bt : bc->buildTargets()) {
|
||||
const QString buildKey = bt.title;
|
||||
if (ProjectNode *node = findNodeForBuildKey(buildKey)) {
|
||||
if (auto targetNode = dynamic_cast<CMakeTargetNode *>(node))
|
||||
targetNode->setConfig(patchedConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TraceTimer projectTreeTimer(" extra compilers");
|
||||
qDeleteAll(m_extraCompilers);
|
||||
m_extraCompilers = findExtraCompilers();
|
||||
CppTools::GeneratedCodeModelSupport::update(m_extraCompilers);
|
||||
qCDebug(cmakeProjectLog) << "Extra compilers updated.";
|
||||
}
|
||||
|
||||
QtSupport::CppKitInfo kitInfo(this);
|
||||
QTC_ASSERT(kitInfo.isValid(), return);
|
||||
|
||||
{
|
||||
TraceTimer cxxCodemodelTimer(" cxx codemodel");
|
||||
CppTools::RawProjectParts rpps = bc->m_buildDirManager.createRawProjectParts(errorMessage);
|
||||
checkAndReportError(errorMessage);
|
||||
qCDebug(cmakeProjectLog) << "Raw project parts created.";
|
||||
|
||||
for (CppTools::RawProjectPart &rpp : rpps) {
|
||||
rpp.setQtVersion(
|
||||
kitInfo.projectPartQtVersion); // TODO: Check if project actually uses Qt.
|
||||
if (kitInfo.cxxToolChain)
|
||||
rpp.setFlagsForCxx({kitInfo.cxxToolChain, rpp.flagsForCxx.commandLineFlags});
|
||||
if (kitInfo.cToolChain)
|
||||
rpp.setFlagsForC({kitInfo.cToolChain, rpp.flagsForC.commandLineFlags});
|
||||
}
|
||||
|
||||
m_cppCodeModelUpdater->update({this, kitInfo, activeBuildEnvironment(), rpps});
|
||||
}
|
||||
{
|
||||
TraceTimer qmlCodemodelTimer(" qml codemodel");
|
||||
updateQmlJSCodeModel(bc);
|
||||
}
|
||||
|
||||
emit fileListChanged();
|
||||
|
||||
emit bc->emitBuildTypeChanged();
|
||||
|
||||
bc->m_buildDirManager.resetData(); // Clear remaining data
|
||||
|
||||
qCDebug(cmakeProjectLog) << "All CMake project data up to date.";
|
||||
}
|
||||
|
||||
void CMakeProject::updateQmlJSCodeModel(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
QTC_ASSERT(bc, return );
|
||||
|
||||
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
|
||||
if (!modelManager)
|
||||
return;
|
||||
|
||||
QmlJS::ModelManagerInterface::ProjectInfo projectInfo =
|
||||
modelManager->defaultProjectInfoForProject(this);
|
||||
|
||||
projectInfo.importPaths.clear();
|
||||
|
||||
const CMakeConfig &cm = bc->configurationFromCMake();
|
||||
const QString cmakeImports = QString::fromUtf8(CMakeConfigItem::valueOf("QML_IMPORT_PATH", cm));
|
||||
|
||||
foreach (const QString &cmakeImport, CMakeConfigItem::cmakeSplitValue(cmakeImports))
|
||||
projectInfo.importPaths.maybeInsert(FilePath::fromString(cmakeImport), QmlJS::Dialect::Qml);
|
||||
|
||||
modelManager->updateProjectInfo(projectInfo, this);
|
||||
}
|
||||
CMakeProject::~CMakeProject() = default;
|
||||
|
||||
Tasks CMakeProject::projectIssues(const Kit *k) const
|
||||
{
|
||||
@@ -330,7 +127,6 @@ void CMakeProject::runCMakeAndScanProjectTree()
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
if (isParsing() || !bc)
|
||||
return;
|
||||
QTC_ASSERT(m_treeScanner.isFinished(), return);
|
||||
|
||||
BuildDirParameters parameters(bc);
|
||||
bc->m_buildDirManager.setParametersAndRequestParse(parameters,
|
||||
@@ -366,33 +162,6 @@ void CMakeProject::clearCMakeCache()
|
||||
bc->m_buildDirManager.clearCache();
|
||||
}
|
||||
|
||||
void CMakeProject::startParsing(int reparseParameters)
|
||||
{
|
||||
m_delayedParsingParameters = BuildDirManager::REPARSE_DEFAULT;
|
||||
|
||||
if (reparseParameters & BuildDirManager::REPARSE_IGNORE)
|
||||
return;
|
||||
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
QTC_ASSERT(bc, return );
|
||||
|
||||
m_parseGuard = std::move(guardParsingRun());
|
||||
|
||||
m_waitingForScan = reparseParameters & BuildDirManager::REPARSE_SCAN;
|
||||
m_waitingForParse = true;
|
||||
m_combinedScanAndParseResult = true;
|
||||
|
||||
if (m_waitingForScan) {
|
||||
QTC_CHECK(m_treeScanner.isFinished());
|
||||
m_treeScanner.asyncScanForFiles(projectDirectory());
|
||||
Core::ProgressManager::addTask(m_treeScanner.future(),
|
||||
tr("Scan \"%1\" project tree").arg(displayName()),
|
||||
"CMake.Scan.Tree");
|
||||
}
|
||||
|
||||
bc->m_buildDirManager.parse(reparseParameters);
|
||||
}
|
||||
|
||||
bool CMakeProject::setupTarget(Target *t)
|
||||
{
|
||||
t->updateDefaultBuildConfigurations();
|
||||
@@ -402,80 +171,6 @@ bool CMakeProject::setupTarget(Target *t)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMakeProject::reportError(const QString &errorMessage) const
|
||||
{
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
if (bc)
|
||||
bc->setError(errorMessage);
|
||||
}
|
||||
|
||||
void CMakeProject::requestReparse(int reparseParameters)
|
||||
{
|
||||
if (reparseParameters & BuildDirManager::REPARSE_IGNORE)
|
||||
return;
|
||||
|
||||
m_delayedParsingTimer.setInterval((reparseParameters & BuildDirManager::REPARSE_URGENT) ? 0
|
||||
: 1000);
|
||||
m_delayedParsingTimer.start();
|
||||
m_delayedParsingParameters = m_delayedParsingParameters | reparseParameters;
|
||||
if (m_allFiles.isEmpty())
|
||||
m_delayedParsingParameters |= BuildDirManager::REPARSE_SCAN;
|
||||
}
|
||||
|
||||
void CMakeProject::handleTreeScanningFinished()
|
||||
{
|
||||
QTC_CHECK(m_waitingForScan);
|
||||
|
||||
qDeleteAll(m_allFiles);
|
||||
m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; });
|
||||
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
QTC_ASSERT(bc, return);
|
||||
|
||||
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
|
||||
m_waitingForScan = false;
|
||||
|
||||
combineScanAndParse(bc);
|
||||
}
|
||||
|
||||
void CMakeProject::handleParsingSuccess(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
QTC_ASSERT(m_waitingForParse, return);
|
||||
|
||||
m_waitingForParse = false;
|
||||
m_combinedScanAndParseResult = m_combinedScanAndParseResult && true;
|
||||
|
||||
combineScanAndParse(bc);
|
||||
}
|
||||
|
||||
void CMakeProject::handleParsingError(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
QTC_CHECK(m_waitingForParse);
|
||||
|
||||
m_waitingForParse = false;
|
||||
m_combinedScanAndParseResult = false;
|
||||
|
||||
combineScanAndParse(bc);
|
||||
}
|
||||
|
||||
void CMakeProject::combineScanAndParse(CMakeBuildConfiguration *bc)
|
||||
{
|
||||
QTC_ASSERT(bc && bc->isActive(), return);
|
||||
|
||||
if (m_waitingForParse || m_waitingForScan)
|
||||
return;
|
||||
|
||||
if (m_combinedScanAndParseResult) {
|
||||
m_parseGuard.markAsSuccess();
|
||||
updateProjectData(bc);
|
||||
}
|
||||
|
||||
{
|
||||
TraceTimer parsingDoneTimer(" parsing finished signal");
|
||||
m_parseGuard = {};
|
||||
}
|
||||
}
|
||||
|
||||
QStringList CMakeProject::filesGeneratedFrom(const QString &sourceFile) const
|
||||
{
|
||||
if (!activeTarget())
|
||||
@@ -538,69 +233,9 @@ MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target,
|
||||
return cmd;
|
||||
}
|
||||
|
||||
bool CMakeProject::mustUpdateCMakeStateBeforeBuild()
|
||||
bool CMakeProject::mustUpdateCMakeStateBeforeBuild() const
|
||||
{
|
||||
return m_delayedParsingTimer.isActive();
|
||||
}
|
||||
|
||||
void CMakeProject::checkAndReportError(QString &errorMessage) const
|
||||
{
|
||||
if (!errorMessage.isEmpty()) {
|
||||
reportError(errorMessage);
|
||||
errorMessage.clear();
|
||||
}
|
||||
}
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> CMakeProject::findExtraCompilers() const
|
||||
{
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: start.";
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> extraCompilers;
|
||||
const QList<ExtraCompilerFactory *> factories = ExtraCompilerFactory::extraCompilerFactories();
|
||||
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: Got factories.";
|
||||
|
||||
const QSet<QString> fileExtensions = Utils::transform<QSet>(factories,
|
||||
&ExtraCompilerFactory::sourceTag);
|
||||
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: Got file extensions:" << fileExtensions;
|
||||
|
||||
// Find all files generated by any of the extra compilers, in a rather crude way.
|
||||
const FilePathList fileList = files([&fileExtensions](const Node *n) {
|
||||
if (!SourceFiles(n))
|
||||
return false;
|
||||
const QString fp = n->filePath().toString();
|
||||
const int pos = fp.lastIndexOf('.');
|
||||
return pos >= 0 && fileExtensions.contains(fp.mid(pos + 1));
|
||||
});
|
||||
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: Got list of files to check.";
|
||||
|
||||
// Generate the necessary information:
|
||||
for (const FilePath &file : fileList) {
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: Processing" << file.toUserOutput();
|
||||
ExtraCompilerFactory *factory = Utils::findOrDefault(factories,
|
||||
[&file](const ExtraCompilerFactory *f) {
|
||||
return file.endsWith(
|
||||
'.' + f->sourceTag());
|
||||
});
|
||||
QTC_ASSERT(factory, continue);
|
||||
|
||||
QStringList generated = filesGeneratedFrom(file.toString());
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: generated files:" << generated;
|
||||
if (generated.isEmpty())
|
||||
continue;
|
||||
|
||||
const FilePathList fileNames
|
||||
= transform(generated,
|
||||
[](const QString &s) { return FilePath::fromString(s); });
|
||||
extraCompilers.append(factory->create(this, file, fileNames));
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: done with" << file.toUserOutput();
|
||||
}
|
||||
|
||||
qCDebug(cmakeProjectLog) << "Finding Extra Compilers: done.";
|
||||
|
||||
return extraCompilers;
|
||||
return buildSystem()->isWaitingForParse();
|
||||
}
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "cmake_global.h"
|
||||
|
||||
#include "builddirmanager.h"
|
||||
#include "cmakebuildsystem.h"
|
||||
#include "cmakebuildtarget.h"
|
||||
#include "cmakeprojectimporter.h"
|
||||
|
||||
@@ -49,6 +50,8 @@ namespace ProjectExplorer { class FileNode; }
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
class BuildSystem;
|
||||
|
||||
namespace Internal {
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeBuildSettingsWidget;
|
||||
@@ -63,6 +66,8 @@ public:
|
||||
explicit CMakeProject(const Utils::FilePath &filename);
|
||||
~CMakeProject() final;
|
||||
|
||||
BuildSystem *buildSystem() const { return m_buildsystem.get(); }
|
||||
|
||||
ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
|
||||
|
||||
void runCMake();
|
||||
@@ -75,53 +80,26 @@ public:
|
||||
|
||||
bool persistCMakeState();
|
||||
void clearCMakeCache();
|
||||
bool mustUpdateCMakeStateBeforeBuild();
|
||||
|
||||
void checkAndReportError(QString &errorMessage) const;
|
||||
void reportError(const QString &errorMessage) const;
|
||||
|
||||
void requestReparse(int reparseParameters);
|
||||
bool mustUpdateCMakeStateBeforeBuild() const;
|
||||
|
||||
protected:
|
||||
bool setupTarget(ProjectExplorer::Target *t) final;
|
||||
|
||||
private:
|
||||
void startParsing(int reparseParameters);
|
||||
|
||||
void handleTreeScanningFinished();
|
||||
void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc);
|
||||
void handleParsingError(Internal::CMakeBuildConfiguration *bc);
|
||||
void combineScanAndParse(Internal::CMakeBuildConfiguration *bc);
|
||||
void updateProjectData(Internal::CMakeBuildConfiguration *bc);
|
||||
void updateQmlJSCodeModel(Internal::CMakeBuildConfiguration *bc);
|
||||
|
||||
QList<ProjectExplorer::ExtraCompiler *> findExtraCompilers() const;
|
||||
QStringList filesGeneratedFrom(const QString &sourceFile) const final;
|
||||
|
||||
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
|
||||
ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target,
|
||||
const QString &installRoot) override;
|
||||
|
||||
CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr;
|
||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||
|
||||
ProjectExplorer::TreeScanner m_treeScanner;
|
||||
|
||||
bool m_waitingForScan = false;
|
||||
bool m_waitingForParse = false;
|
||||
bool m_combinedScanAndParseResult = false;
|
||||
|
||||
QHash<QString, bool> m_mimeBinaryCache;
|
||||
QList<const ProjectExplorer::FileNode *> m_allFiles;
|
||||
mutable std::unique_ptr<Internal::CMakeProjectImporter> m_projectImporter;
|
||||
|
||||
QTimer m_delayedParsingTimer;
|
||||
int m_delayedParsingParameters = 0;
|
||||
std::unique_ptr<CMakeBuildSystem> m_buildsystem;
|
||||
|
||||
ParseGuard m_parseGuard;
|
||||
// friend class Internal::CMakeBuildConfiguration;
|
||||
// friend class Internal::CMakeBuildSettingsWidget;
|
||||
|
||||
friend class Internal::CMakeBuildConfiguration;
|
||||
friend class Internal::CMakeBuildSettingsWidget;
|
||||
friend class CMakeBuildSystem;
|
||||
};
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
@@ -5,6 +5,7 @@ HEADERS = builddirmanager.h \
|
||||
builddirparameters.h \
|
||||
builddirreader.h \
|
||||
cmakebuildstep.h \
|
||||
cmakebuildsystem.h \
|
||||
cmakebuildtarget.h \
|
||||
cmakeconfigitem.h \
|
||||
cmakeprocess.h \
|
||||
@@ -45,6 +46,7 @@ SOURCES = builddirmanager.cpp \
|
||||
builddirparameters.cpp \
|
||||
builddirreader.cpp \
|
||||
cmakebuildstep.cpp \
|
||||
cmakebuildsystem.cpp \
|
||||
cmakeconfigitem.cpp \
|
||||
cmakeprocess.cpp \
|
||||
cmakeproject.cpp \
|
||||
|
@@ -32,6 +32,8 @@ QtcPlugin {
|
||||
"cmakebuildsettingswidget.h",
|
||||
"cmakebuildstep.cpp",
|
||||
"cmakebuildstep.h",
|
||||
"cmakebuildsystem.cpp",
|
||||
"cmakebuildsystem.h",
|
||||
"cmakebuildtarget.h",
|
||||
"cmakecbpparser.cpp",
|
||||
"cmakecbpparser.h",
|
||||
|
@@ -249,6 +249,9 @@ public:
|
||||
friend class Project;
|
||||
};
|
||||
|
||||
// FIXME: Make this private and the BuildSystem a friend
|
||||
ParseGuard guardParsingRun() { return ParseGuard(this); }
|
||||
|
||||
signals:
|
||||
void displayNameChanged();
|
||||
void fileListChanged();
|
||||
@@ -280,8 +283,6 @@ signals:
|
||||
void rootProjectDirectoryChanged();
|
||||
|
||||
protected:
|
||||
ParseGuard guardParsingRun() { return ParseGuard(this); }
|
||||
|
||||
virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage);
|
||||
void createTargetFromMap(const QVariantMap &map, int index);
|
||||
virtual bool setupTarget(Target *t);
|
||||
@@ -323,6 +324,7 @@ private:
|
||||
|
||||
void handleSubTreeChanged(FolderNode *node);
|
||||
void setActiveTarget(Target *target);
|
||||
|
||||
ProjectPrivate *d;
|
||||
|
||||
friend class ContainerNode;
|
||||
|
Reference in New Issue
Block a user