forked from qt-creator/qt-creator
CMake: Project tree for server mode data
Change-Id: Ief884a76c1b4211501dd6515b17b6e88a8e881e5 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -298,9 +298,10 @@ void BuildDirManager::resetData()
|
|||||||
m_reader->resetData();
|
m_reader->resetData();
|
||||||
|
|
||||||
m_cmakeCache.clear();
|
m_cmakeCache.clear();
|
||||||
|
QTC_ASSERT(!m_futureInterface || m_futureInterface->isFinished(), return);
|
||||||
m_futureInterface.reset();
|
m_futureInterface.reset();
|
||||||
|
|
||||||
m_reader.reset(nullptr);
|
m_reader.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildDirManager::updateCMakeStateBeforeBuild()
|
bool BuildDirManager::updateCMakeStateBeforeBuild()
|
||||||
@@ -323,7 +324,7 @@ bool BuildDirManager::persistCMakeState()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildDirManager::generateProjectTree(CMakeProjectNode *root)
|
void BuildDirManager::generateProjectTree(CMakeListsNode *root)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_reader, return);
|
QTC_ASSERT(m_reader, return);
|
||||||
QTC_ASSERT(m_futureInterface, return);
|
QTC_ASSERT(m_futureInterface, return);
|
||||||
|
@@ -72,7 +72,7 @@ public:
|
|||||||
bool updateCMakeStateBeforeBuild();
|
bool updateCMakeStateBeforeBuild();
|
||||||
bool persistCMakeState();
|
bool persistCMakeState();
|
||||||
|
|
||||||
void generateProjectTree(CMakeProjectNode *root);
|
void generateProjectTree(CMakeListsNode *root);
|
||||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||||
|
|
||||||
QList<CMakeBuildTarget> buildTargets() const;
|
QList<CMakeBuildTarget> buildTargets() const;
|
||||||
|
@@ -49,6 +49,7 @@ namespace CMakeProjectManager {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class CMakeBuildConfiguration;
|
class CMakeBuildConfiguration;
|
||||||
|
class CMakeListsNode;
|
||||||
|
|
||||||
class BuildDirReader : public QObject
|
class BuildDirReader : public QObject
|
||||||
{
|
{
|
||||||
@@ -100,7 +101,7 @@ public:
|
|||||||
|
|
||||||
virtual CMakeConfig parsedConfiguration() const = 0;
|
virtual CMakeConfig parsedConfiguration() const = 0;
|
||||||
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
|
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
|
||||||
virtual void generateProjectTree(CMakeProjectNode *root,
|
virtual void generateProjectTree(CMakeListsNode *root,
|
||||||
const QList<ProjectExplorer::FileNode *> &allFiles) = 0;
|
const QList<ProjectExplorer::FileNode *> &allFiles) = 0;
|
||||||
virtual QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) = 0;
|
virtual QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) = 0;
|
||||||
|
|
||||||
|
@@ -202,7 +202,7 @@ QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
|
|||||||
return m_buildDirManager->buildTargets();
|
return m_buildDirManager->buildTargets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeBuildConfiguration::generateProjectTree(CMakeProjectNode *root) const
|
void CMakeBuildConfiguration::generateProjectTree(CMakeListsNode *root) const
|
||||||
{
|
{
|
||||||
if (!m_buildDirManager || m_buildDirManager->isParsing())
|
if (!m_buildDirManager || m_buildDirManager->isParsing())
|
||||||
return;
|
return;
|
||||||
|
@@ -46,6 +46,7 @@ namespace Internal {
|
|||||||
class BuildDirManager;
|
class BuildDirManager;
|
||||||
class CMakeBuildConfigurationFactory;
|
class CMakeBuildConfigurationFactory;
|
||||||
class CMakeBuildSettingsWidget;
|
class CMakeBuildSettingsWidget;
|
||||||
|
class CMakeListsNode;
|
||||||
|
|
||||||
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
||||||
{
|
{
|
||||||
@@ -84,7 +85,7 @@ public:
|
|||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
QList<CMakeBuildTarget> buildTargets() const;
|
QList<CMakeBuildTarget> buildTargets() const;
|
||||||
void generateProjectTree(CMakeProjectNode *root) const;
|
void generateProjectTree(CMakeListsNode *root) const;
|
||||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||||
|
|
||||||
static Utils::FileName
|
static Utils::FileName
|
||||||
|
@@ -78,7 +78,7 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName)
|
|||||||
setDocument(new TextEditor::TextDocument);
|
setDocument(new TextEditor::TextDocument);
|
||||||
document()->setFilePath(fileName);
|
document()->setFilePath(fileName);
|
||||||
|
|
||||||
setRootProjectNode(new CMakeProjectNode(FileName::fromString(fileName.toFileInfo().absolutePath())));
|
setRootProjectNode(new CMakeListsNode(fileName));
|
||||||
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
|
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
|
||||||
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
|
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ void CMakeProject::updateProjectData()
|
|||||||
return;
|
return;
|
||||||
Kit *k = t->kit();
|
Kit *k = t->kit();
|
||||||
|
|
||||||
cmakeBc->generateProjectTree(static_cast<CMakeProjectNode *>(rootProjectNode()));
|
cmakeBc->generateProjectTree(static_cast<CMakeListsNode *>(rootProjectNode()));
|
||||||
|
|
||||||
updateApplicationAndDeploymentTargets();
|
updateApplicationAndDeploymentTargets();
|
||||||
updateTargetRunConfigurations(t);
|
updateTargetRunConfigurations(t);
|
||||||
|
@@ -41,9 +41,8 @@ QT_END_NAMESPACE
|
|||||||
namespace CMakeProjectManager {
|
namespace CMakeProjectManager {
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class CMakeBuildSettingsWidget;
|
|
||||||
class CMakeBuildConfiguration;
|
class CMakeBuildConfiguration;
|
||||||
class CMakeProjectNode;
|
class CMakeBuildSettingsWidget;
|
||||||
class CMakeManager;
|
class CMakeManager;
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
@@ -76,8 +75,7 @@ public:
|
|||||||
class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project
|
class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
// for changeBuildDirectory
|
|
||||||
friend class Internal::CMakeBuildSettingsWidget;
|
|
||||||
public:
|
public:
|
||||||
CMakeProject(Internal::CMakeManager *manager, const Utils::FileName &filename);
|
CMakeProject(Internal::CMakeManager *manager, const Utils::FileName &filename);
|
||||||
~CMakeProject() final;
|
~CMakeProject() final;
|
||||||
@@ -128,6 +126,7 @@ private:
|
|||||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||||
|
|
||||||
friend class Internal::CMakeBuildConfiguration;
|
friend class Internal::CMakeBuildConfiguration;
|
||||||
|
friend class Internal::CMakeBuildSettingsWidget;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
@@ -25,22 +25,122 @@
|
|||||||
|
|
||||||
#include "cmakeprojectnodes.h"
|
#include "cmakeprojectnodes.h"
|
||||||
|
|
||||||
|
#include "cmakeprojectconstants.h"
|
||||||
|
|
||||||
|
#include <coreplugin/fileiconprovider.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
using namespace CMakeProjectManager;
|
using namespace CMakeProjectManager;
|
||||||
using namespace CMakeProjectManager::Internal;
|
using namespace CMakeProjectManager::Internal;
|
||||||
|
|
||||||
CMakeProjectNode::CMakeProjectNode(const Utils::FileName &dirName)
|
CMakeInputsNode::CMakeInputsNode(const Utils::FileName &cmakeLists) :
|
||||||
: ProjectExplorer::ProjectNode(dirName)
|
ProjectExplorer::ProjectNode(CMakeInputsNode::inputsPathFromCMakeListsPath(cmakeLists))
|
||||||
{
|
{
|
||||||
|
setPriority(Node::DefaultPriority - 10); // Bottom most!
|
||||||
|
setDisplayName(QCoreApplication::translate("CMakeFilesProjectNode", "CMake Modules"));
|
||||||
|
setIcon(QIcon(":/projectexplorer/images/session.png")); // TODO: Use a better icon!
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMakeProjectNode::showInSimpleTree() const
|
Utils::FileName CMakeInputsNode::inputsPathFromCMakeListsPath(const Utils::FileName &cmakeLists)
|
||||||
{
|
{
|
||||||
// TODO
|
Utils::FileName result = cmakeLists;
|
||||||
return true;
|
result.appendPath("cmakeInputs"); // cmakeLists is a file, so this can not exist on disk
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ProjectExplorer::ProjectAction> CMakeProjectNode::supportedActions(Node *node) const
|
bool CMakeInputsNode::showInSimpleTree() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ProjectExplorer::ProjectAction> CMakeInputsNode::supportedActions(ProjectExplorer::Node *node) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(node);
|
Q_UNUSED(node);
|
||||||
return QList<ProjectExplorer::ProjectAction>();
|
return QList<ProjectExplorer::ProjectAction>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CMakeListsNode::CMakeListsNode(const Utils::FileName &cmakeListPath) :
|
||||||
|
ProjectExplorer::ProjectNode(cmakeListPath)
|
||||||
|
{
|
||||||
|
static QIcon folderIcon;
|
||||||
|
if (folderIcon.isNull()) {
|
||||||
|
const QIcon overlayIcon(Constants::FILEOVERLAY_CMAKE);
|
||||||
|
QPixmap dirPixmap = qApp->style()->standardIcon(QStyle::SP_DirIcon).pixmap(QSize(16, 16));
|
||||||
|
|
||||||
|
folderIcon.addPixmap(Core::FileIconProvider::overlayIcon(dirPixmap, overlayIcon));
|
||||||
|
}
|
||||||
|
setIcon(folderIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CMakeListsNode::showInSimpleTree() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ProjectExplorer::ProjectAction> CMakeListsNode::supportedActions(ProjectExplorer::Node *node) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(node);
|
||||||
|
return QList<ProjectExplorer::ProjectAction>();
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeProjectNode::CMakeProjectNode(const Utils::FileName &directory) :
|
||||||
|
ProjectExplorer::ProjectNode(directory)
|
||||||
|
{
|
||||||
|
setPriority(Node::DefaultProjectPriority + 1000);
|
||||||
|
setIcon(QIcon(":/projectexplorer/images/projectexplorer.png")); // TODO: Use proper icon!
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CMakeProjectNode::showInSimpleTree() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CMakeProjectNode::tooltip() const
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ProjectExplorer::ProjectAction> CMakeProjectNode::supportedActions(ProjectExplorer::Node *node) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(node);
|
||||||
|
return QList<ProjectExplorer::ProjectAction>();
|
||||||
|
}
|
||||||
|
|
||||||
|
CMakeTargetNode::CMakeTargetNode(const Utils::FileName &directory) :
|
||||||
|
ProjectExplorer::ProjectNode(directory)
|
||||||
|
{
|
||||||
|
setPriority(Node::DefaultProjectPriority + 900);
|
||||||
|
setIcon(QIcon(":/projectexplorer/images/build.png")); // TODO: Use proper icon!
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CMakeTargetNode::showInSimpleTree() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CMakeTargetNode::tooltip() const
|
||||||
|
{
|
||||||
|
return m_tooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ProjectExplorer::ProjectAction> CMakeTargetNode::supportedActions(ProjectExplorer::Node *node) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(node);
|
||||||
|
return QList<ProjectExplorer::ProjectAction>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMakeTargetNode::setTargetInformation(const QList<Utils::FileName> &artifacts,
|
||||||
|
const QString &type)
|
||||||
|
{
|
||||||
|
m_tooltip = QCoreApplication::translate("CMakeTargetNode", "Target type: ") + type + "<br>";
|
||||||
|
if (artifacts.count() == 0) {
|
||||||
|
m_tooltip += QCoreApplication::translate("CMakeTargetNode", "No build artifacts");
|
||||||
|
} else {
|
||||||
|
const QStringList tmp = Utils::transform(artifacts, &Utils::FileName::toUserOutput);
|
||||||
|
m_tooltip += QCoreApplication::translate("CMakeTargetNode", "Build artifacts:<br>")
|
||||||
|
+ tmp.join("<br>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -32,12 +32,49 @@ class CMakeProject;
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class CMakeInputsNode : public ProjectExplorer::ProjectNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMakeInputsNode(const Utils::FileName &cmakeLists);
|
||||||
|
|
||||||
|
static Utils::FileName inputsPathFromCMakeListsPath(const Utils::FileName &cmakeLists);
|
||||||
|
|
||||||
|
bool showInSimpleTree() const final;
|
||||||
|
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CMakeListsNode : public ProjectExplorer::ProjectNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMakeListsNode(const Utils::FileName &cmakeListPath);
|
||||||
|
|
||||||
|
bool showInSimpleTree() const final;
|
||||||
|
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
|
||||||
|
};
|
||||||
|
|
||||||
class CMakeProjectNode : public ProjectExplorer::ProjectNode
|
class CMakeProjectNode : public ProjectExplorer::ProjectNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMakeProjectNode(const Utils::FileName &dirName);
|
CMakeProjectNode(const Utils::FileName &directory);
|
||||||
bool showInSimpleTree() const override;
|
|
||||||
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
|
bool showInSimpleTree() const final;
|
||||||
|
QString tooltip() const final;
|
||||||
|
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CMakeTargetNode : public ProjectExplorer::ProjectNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMakeTargetNode(const Utils::FileName &directory);
|
||||||
|
|
||||||
|
void setTargetInformation(const QList<Utils::FileName> &artifacts, const QString &type);
|
||||||
|
|
||||||
|
bool showInSimpleTree() const final;
|
||||||
|
QString tooltip() const final;
|
||||||
|
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_tooltip;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -211,24 +211,90 @@ CMakeConfig ServerModeReader::parsedConfiguration() const
|
|||||||
return m_cmakeCache;
|
return m_cmakeCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerModeReader::generateProjectTree(CMakeProjectNode *root, const QList<FileNode *> &allFiles)
|
FolderNode *setupCMakeVFolder(FolderNode *base, const Utils::FileName &basePath, int priority,
|
||||||
|
const QString &displayName, QList<FileNode *> &files)
|
||||||
{
|
{
|
||||||
Q_UNUSED(allFiles);
|
FolderNode *folder
|
||||||
QSet<Utils::FileName> knownFiles;
|
= findOrDefault(base->folderNodes(), [basePath](const FolderNode *fn) {
|
||||||
for (auto it = m_cmakeInputsFileNodes.constBegin(); it != m_cmakeInputsFileNodes.constEnd(); ++it)
|
return fn->filePath() == basePath;
|
||||||
knownFiles.insert((*it)->filePath());
|
});
|
||||||
|
if (files.isEmpty()) {
|
||||||
QList<FileNode *> fileGroupNodes = m_cmakeInputsFileNodes;
|
return folder;
|
||||||
m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore!
|
} else {
|
||||||
foreach (const FileGroup *fg, m_fileGroups) {
|
if (!folder) {
|
||||||
for (const FileName &s : fg->sources) {
|
folder = new VirtualFolderNode(basePath, priority);
|
||||||
const int oldCount = knownFiles.count();
|
folder->setDisplayName(displayName);
|
||||||
knownFiles.insert(s);
|
base->addFolderNodes({ folder });
|
||||||
if (oldCount != knownFiles.count())
|
|
||||||
fileGroupNodes.append(new FileNode(s, FileType::Source, fg->isGenerated));
|
|
||||||
}
|
}
|
||||||
|
folder->buildTree(files);
|
||||||
}
|
}
|
||||||
root->buildTree(fileGroupNodes);
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProjectNode *updateCMakeInputs(CMakeListsNode *root,
|
||||||
|
const Utils::FileName &sourceDir,
|
||||||
|
const Utils::FileName &buildDir,
|
||||||
|
QList<FileNode *> &sourceInputs,
|
||||||
|
QList<FileNode *> &buildInputs,
|
||||||
|
QList<FileNode *> &rootInputs)
|
||||||
|
{
|
||||||
|
ProjectNode *cmakeVFolder
|
||||||
|
= root->projectNode(CMakeInputsNode::inputsPathFromCMakeListsPath(root->filePath()));
|
||||||
|
if (!cmakeVFolder) {
|
||||||
|
cmakeVFolder = new CMakeInputsNode(root->filePath());
|
||||||
|
root->addProjectNodes({ cmakeVFolder });
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<FolderNode *> foldersToDelete;
|
||||||
|
foldersToDelete.append(setupCMakeVFolder(cmakeVFolder, sourceDir, 1000,
|
||||||
|
QCoreApplication::translate("CMakeProjectManager::Internal", "Source Directory"),
|
||||||
|
sourceInputs));
|
||||||
|
foldersToDelete.append(setupCMakeVFolder(cmakeVFolder, buildDir, 100,
|
||||||
|
QCoreApplication::translate("CMakeProjectManager::Internal", "Build Directory"),
|
||||||
|
buildInputs));
|
||||||
|
foldersToDelete.append(setupCMakeVFolder(cmakeVFolder, Utils::FileName(), 10,
|
||||||
|
QCoreApplication::translate("CMakeProjectManager::Internal", "Other Locations"),
|
||||||
|
rootInputs));
|
||||||
|
|
||||||
|
// Clean out unused nodes in "CMake Files":
|
||||||
|
const QList<FolderNode *> tmp = filtered(foldersToDelete, [](const FolderNode *fn) { return fn; });
|
||||||
|
cmakeVFolder->removeFolderNodes(tmp);
|
||||||
|
|
||||||
|
return cmakeVFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerModeReader::generateProjectTree(CMakeListsNode *root, const QList<FileNode *> &allFiles)
|
||||||
|
{
|
||||||
|
// Split up cmake inputs into useful chunks:
|
||||||
|
QList<FileNode *> cmakeFilesSource;
|
||||||
|
QList<FileNode *> cmakeFilesBuild;
|
||||||
|
QList<FileNode *> cmakeFilesOther;
|
||||||
|
QList<FileNode *> cmakeLists;
|
||||||
|
foreach (FileNode *fn, m_cmakeInputsFileNodes) {
|
||||||
|
const FileName path = fn->filePath();
|
||||||
|
if (path.fileName().compare("CMakeLists.txt", HostOsInfo::fileNameCaseSensitivity()) == 0)
|
||||||
|
cmakeLists.append(fn);
|
||||||
|
else if (path.isChildOf(m_parameters.sourceDirectory))
|
||||||
|
cmakeFilesSource.append(fn);
|
||||||
|
else if (path.isChildOf(m_parameters.buildDirectory))
|
||||||
|
cmakeFilesBuild.append(fn);
|
||||||
|
else
|
||||||
|
cmakeFilesOther.append(fn);
|
||||||
|
}
|
||||||
|
m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore!
|
||||||
|
|
||||||
|
if (!m_projects.isEmpty())
|
||||||
|
root->setDisplayName(m_projects.at(0)->name);
|
||||||
|
|
||||||
|
QSet<Node *> usedNodes;
|
||||||
|
usedNodes.insert(updateCMakeInputs(root, m_parameters.sourceDirectory, m_parameters.buildDirectory,
|
||||||
|
cmakeFilesSource, cmakeFilesBuild, cmakeFilesOther));
|
||||||
|
|
||||||
|
usedNodes.unite(updateCMakeLists(root, cmakeLists));
|
||||||
|
usedNodes.unite(updateProjects(root, m_projects, allFiles));
|
||||||
|
|
||||||
|
// Trim out unused nodes:
|
||||||
|
root->trim(usedNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<Core::Id> ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
QSet<Core::Id> ServerModeReader::updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder)
|
||||||
@@ -448,5 +514,231 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
|
|||||||
m_cmakeCache = config;
|
m_cmakeCache = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSet<Node *> ServerModeReader::updateCMakeLists(CMakeListsNode *root,
|
||||||
|
const QList<FileNode *> &cmakeLists)
|
||||||
|
{
|
||||||
|
QSet<Node *> usedNodes;
|
||||||
|
|
||||||
|
const QDir baseDir = QDir(root->filePath().parentDir().toString());
|
||||||
|
|
||||||
|
QHash<QString, FileNode *> nodeHash;
|
||||||
|
for (FileNode *cm : cmakeLists) {
|
||||||
|
const QString relPath = baseDir.relativeFilePath(cm->filePath().parentDir().toString());
|
||||||
|
QTC_CHECK(!nodeHash.contains(relPath));
|
||||||
|
nodeHash[(relPath == ".") ? QString() : relPath ] = cm;
|
||||||
|
}
|
||||||
|
QStringList tmp = nodeHash.keys();
|
||||||
|
Utils::sort(tmp, [](const QString &a, const QString &b) { return a.count() < b.count(); });
|
||||||
|
const QStringList keys = tmp;
|
||||||
|
|
||||||
|
QHash<QString, CMakeListsNode *> knownNodes;
|
||||||
|
knownNodes[QString()] = root;
|
||||||
|
|
||||||
|
for (const QString &k : keys) {
|
||||||
|
FileNode *fn = nodeHash[k];
|
||||||
|
CMakeListsNode *parentNode = nullptr;
|
||||||
|
QString prefix = k;
|
||||||
|
forever {
|
||||||
|
if (knownNodes.contains(prefix)) {
|
||||||
|
parentNode = knownNodes.value(prefix);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const int pos = prefix.lastIndexOf('/');
|
||||||
|
prefix = (pos < 0) ? QString() : prefix.left(prefix.lastIndexOf('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find or create CMakeListsNode:
|
||||||
|
CMakeListsNode *cmln = nullptr;
|
||||||
|
if (parentNode->filePath() == fn->filePath())
|
||||||
|
cmln = parentNode; // Top level!
|
||||||
|
else
|
||||||
|
cmln = static_cast<CMakeListsNode *>(parentNode->projectNode(fn->filePath()));
|
||||||
|
if (!cmln) {
|
||||||
|
cmln = new CMakeListsNode(fn->filePath());
|
||||||
|
parentNode->addProjectNodes({ cmln });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find or create CMakeLists.txt filenode below CMakeListsNode:
|
||||||
|
FileNode *cmFn = cmln->fileNode(fn->filePath());
|
||||||
|
if (!cmFn) {
|
||||||
|
cmFn = fn;
|
||||||
|
cmln->addFileNodes({ cmFn });
|
||||||
|
}
|
||||||
|
usedNodes.insert(cmFn); // register existing CMakeLists.txt filenode
|
||||||
|
|
||||||
|
// Update displayName of CMakeListsNode:
|
||||||
|
const QString dn = prefix.isEmpty() ? k : k.mid(prefix.count() + 1);
|
||||||
|
if (!dn.isEmpty())
|
||||||
|
cmln->setDisplayName(dn); // Set partial path as display name
|
||||||
|
|
||||||
|
knownNodes.insert(k, cmln);
|
||||||
|
}
|
||||||
|
|
||||||
|
return usedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMakeListsNode *findCMakeNode(CMakeListsNode *root, const Utils::FileName &dir)
|
||||||
|
{
|
||||||
|
Utils::FileName stepDir = dir;
|
||||||
|
|
||||||
|
CMakeListsNode *base = root;
|
||||||
|
forever {
|
||||||
|
Utils::FileName stepLists = stepDir;
|
||||||
|
stepLists.appendPath("CMakeLists.txt");
|
||||||
|
|
||||||
|
CMakeListsNode *cmln = nullptr;
|
||||||
|
if (base->filePath() == stepLists) {
|
||||||
|
cmln = base;
|
||||||
|
} else {
|
||||||
|
ProjectNode *pcmln = base->projectNode(stepLists);
|
||||||
|
cmln = static_cast<CMakeListsNode *>(pcmln);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmln) {
|
||||||
|
stepDir = stepDir.parentDir();
|
||||||
|
if (stepDir.isEmpty())
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
if (cmln->filePath().parentDir() == dir)
|
||||||
|
return cmln;
|
||||||
|
stepDir = dir;
|
||||||
|
base = cmln;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Utils::FileName &dir,
|
||||||
|
const QString &displayName)
|
||||||
|
{
|
||||||
|
CMakeListsNode *cmln = findCMakeNode(root, dir);
|
||||||
|
QTC_ASSERT(cmln, return nullptr);
|
||||||
|
|
||||||
|
Utils::FileName projectName = dir;
|
||||||
|
projectName.appendPath(".project::" + displayName);
|
||||||
|
|
||||||
|
CMakeProjectNode *pn = static_cast<CMakeProjectNode *>(cmln->projectNode(projectName));
|
||||||
|
if (!pn) {
|
||||||
|
pn = new CMakeProjectNode(projectName);
|
||||||
|
cmln->addProjectNodes({ pn });
|
||||||
|
}
|
||||||
|
pn->setDisplayName(displayName);
|
||||||
|
return pn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<Node *> ServerModeReader::updateProjects(CMakeListsNode *root,
|
||||||
|
const QList<Project *> &projects,
|
||||||
|
const QList<FileNode *> &allFiles)
|
||||||
|
{
|
||||||
|
QSet<Node *> usedNodes;
|
||||||
|
|
||||||
|
QHash<Utils::FileName, QList<FileNode *>> includeFiles;
|
||||||
|
for (FileNode *f : allFiles) {
|
||||||
|
if (f->fileType() != FileType::Header)
|
||||||
|
continue;
|
||||||
|
includeFiles[f->filePath().parentDir()].append(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Project *p : projects) {
|
||||||
|
CMakeProjectNode *pNode = findOrCreateProjectNode(root, p->sourceDirectory, p->name);
|
||||||
|
QTC_ASSERT(pNode, continue);
|
||||||
|
usedNodes.insert(pNode); // Mark as leaf to keep.
|
||||||
|
|
||||||
|
usedNodes.unite(updateTargets(root, p->targets, includeFiles));
|
||||||
|
}
|
||||||
|
return usedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils::FileName &dir,
|
||||||
|
const QString &displayName)
|
||||||
|
{
|
||||||
|
CMakeListsNode *cmln = findCMakeNode(root, dir);
|
||||||
|
QTC_ASSERT(cmln, return nullptr);
|
||||||
|
|
||||||
|
Utils::FileName targetName = dir;
|
||||||
|
targetName.appendPath(".target::" + displayName);
|
||||||
|
|
||||||
|
CMakeTargetNode *tn = static_cast<CMakeTargetNode *>(cmln->projectNode(targetName));
|
||||||
|
if (!tn) {
|
||||||
|
tn = new CMakeTargetNode(targetName);
|
||||||
|
cmln->addProjectNodes({ tn });
|
||||||
|
}
|
||||||
|
tn->setDisplayName(displayName);
|
||||||
|
return tn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<Node *> ServerModeReader::updateTargets(CMakeListsNode *root,
|
||||||
|
const QList<ServerModeReader::Target *> &targets,
|
||||||
|
const QHash<FileName, QList<FileNode *> > &headers)
|
||||||
|
{
|
||||||
|
QSet<Node *> usedNodes;
|
||||||
|
for (const Target *t : targets) {
|
||||||
|
|
||||||
|
CMakeTargetNode *tNode = findOrCreateTargetNode(root, t->sourceDirectory, t->name);
|
||||||
|
tNode->setTargetInformation(t->artifacts, t->type);
|
||||||
|
|
||||||
|
usedNodes.unite(updateFileGroups(tNode, t->sourceDirectory, t->buildDirectory,
|
||||||
|
t->fileGroups, headers));
|
||||||
|
}
|
||||||
|
return usedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Utils::FileName mapFileName(const Utils::FileName &fn, const Utils::FileName &sourceDirectory,
|
||||||
|
const Utils::FileName &buildDirectory)
|
||||||
|
{
|
||||||
|
if (fn.isChildOf(buildDirectory)) {
|
||||||
|
Utils::FileName mapped = sourceDirectory;
|
||||||
|
mapped.appendPath(QCoreApplication::translate("CMakeProjectManager::Internal", "<Build Directory>"));
|
||||||
|
QDir bd = QDir(buildDirectory.toString());
|
||||||
|
mapped.appendPath(bd.relativeFilePath(fn.toString()));
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<Node *> ServerModeReader::updateFileGroups(ProjectNode *targetRoot,
|
||||||
|
const Utils::FileName &sourceDirectory,
|
||||||
|
const Utils::FileName &buildDirectory,
|
||||||
|
const QList<ServerModeReader::FileGroup *> &fileGroups,
|
||||||
|
const QHash<FileName, QList<FileNode *> > &headers)
|
||||||
|
{
|
||||||
|
QSet<Node *> usedNodes;
|
||||||
|
QList<FileNode *> toList;
|
||||||
|
QSet<Utils::FileName> alreadyListed;
|
||||||
|
for (const FileGroup *f : fileGroups) {
|
||||||
|
const QList<FileName> newSources = Utils::filtered(f->sources, [&alreadyListed](const Utils::FileName &fn) {
|
||||||
|
const int count = alreadyListed.count();
|
||||||
|
alreadyListed.insert(fn);
|
||||||
|
return count != alreadyListed.count();
|
||||||
|
});
|
||||||
|
const QList<FileNode *> newFileNodes = Utils::transform(newSources, [f, &sourceDirectory, &buildDirectory](const Utils::FileName &fn) {
|
||||||
|
return new FileNode(mapFileName(fn, sourceDirectory, buildDirectory), FileType::Source, f->isGenerated);
|
||||||
|
});
|
||||||
|
toList.append(newFileNodes);
|
||||||
|
|
||||||
|
// Add scanned header files:
|
||||||
|
for (const IncludePath *i : f->includePaths) {
|
||||||
|
const QList<FileNode *> &headerFiles = headers.value(i->path);
|
||||||
|
const QList<FileNode *> unseenHeaders = Utils::filtered(headerFiles, [&alreadyListed](const FileNode *fn) {
|
||||||
|
const int count = alreadyListed.count();
|
||||||
|
alreadyListed.insert(fn->filePath());
|
||||||
|
return count != alreadyListed.count();
|
||||||
|
});
|
||||||
|
toList.append(Utils::transform(unseenHeaders, [&sourceDirectory, &buildDirectory](FileNode *fn) -> FileNode * {
|
||||||
|
const Utils::FileName mappedPath = mapFileName(fn->filePath(), sourceDirectory, buildDirectory);
|
||||||
|
auto copy = new FileNode(mappedPath, fn->fileType(), fn->isGenerated());
|
||||||
|
copy->setEnabled(false);
|
||||||
|
return copy;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targetRoot->buildTree(toList, sourceDirectory);
|
||||||
|
|
||||||
|
foreach (FileNode *fn, toList)
|
||||||
|
usedNodes.insert(static_cast<Node *>(fn)); // Mark all leaves as keeper!
|
||||||
|
|
||||||
|
return usedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
@@ -64,7 +64,7 @@ public:
|
|||||||
|
|
||||||
QList<CMakeBuildTarget> buildTargets() const final;
|
QList<CMakeBuildTarget> buildTargets() const final;
|
||||||
CMakeConfig parsedConfiguration() const final;
|
CMakeConfig parsedConfiguration() const final;
|
||||||
void generateProjectTree(CMakeProjectNode *root, const QList<ProjectExplorer::FileNode *> &allFiles) final;
|
void generateProjectTree(CMakeListsNode *root, const QList<ProjectExplorer::FileNode *> &allFiles) final;
|
||||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
|
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -119,6 +119,20 @@ private:
|
|||||||
void extractCMakeInputsData(const QVariantMap &data);
|
void extractCMakeInputsData(const QVariantMap &data);
|
||||||
void extractCacheData(const QVariantMap &data);
|
void extractCacheData(const QVariantMap &data);
|
||||||
|
|
||||||
|
QSet<ProjectExplorer::Node *> updateCMakeLists(CMakeListsNode *root,
|
||||||
|
const QList<ProjectExplorer::FileNode *> &cmakeLists);
|
||||||
|
QSet<ProjectExplorer::Node *> updateProjects(CMakeListsNode *root,
|
||||||
|
const QList<Project *> &projects,
|
||||||
|
const QList<ProjectExplorer::FileNode *> &allFiles);
|
||||||
|
QSet<ProjectExplorer::Node *> updateTargets(CMakeListsNode *root,
|
||||||
|
const QList<Target *> &targets,
|
||||||
|
const QHash<Utils::FileName, QList<ProjectExplorer::FileNode *>> &headers);
|
||||||
|
QSet<ProjectExplorer::Node *> updateFileGroups(ProjectExplorer::ProjectNode *targetRoot,
|
||||||
|
const Utils::FileName &sourceDirectory,
|
||||||
|
const Utils::FileName &buildDirectory,
|
||||||
|
const QList<FileGroup *> &fileGroups,
|
||||||
|
const QHash<Utils::FileName, QList<ProjectExplorer::FileNode *>> &headers);
|
||||||
|
|
||||||
bool m_hasData = false;
|
bool m_hasData = false;
|
||||||
|
|
||||||
std::unique_ptr<ServerMode> m_cmakeServer;
|
std::unique_ptr<ServerMode> m_cmakeServer;
|
||||||
|
@@ -318,7 +318,7 @@ CMakeConfig TeaLeafReader::parseConfiguration(const FileName &cacheFile, QString
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<FileNode *> &allFiles)
|
void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<FileNode *> &allFiles)
|
||||||
{
|
{
|
||||||
root->setDisplayName(m_projectName);
|
root->setDisplayName(m_projectName);
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ public:
|
|||||||
|
|
||||||
QList<CMakeBuildTarget> buildTargets() const final;
|
QList<CMakeBuildTarget> buildTargets() const final;
|
||||||
CMakeConfig parsedConfiguration() const final;
|
CMakeConfig parsedConfiguration() const final;
|
||||||
void generateProjectTree(CMakeProjectNode *root,
|
void generateProjectTree(CMakeListsNode *root,
|
||||||
const QList<ProjectExplorer::FileNode *> &allFiles) final;
|
const QList<ProjectExplorer::FileNode *> &allFiles) final;
|
||||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
|
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user