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_cmakeCache.clear();
|
||||
QTC_ASSERT(!m_futureInterface || m_futureInterface->isFinished(), return);
|
||||
m_futureInterface.reset();
|
||||
|
||||
m_reader.reset(nullptr);
|
||||
m_reader.reset();
|
||||
}
|
||||
|
||||
bool BuildDirManager::updateCMakeStateBeforeBuild()
|
||||
@@ -323,7 +324,7 @@ bool BuildDirManager::persistCMakeState()
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildDirManager::generateProjectTree(CMakeProjectNode *root)
|
||||
void BuildDirManager::generateProjectTree(CMakeListsNode *root)
|
||||
{
|
||||
QTC_ASSERT(m_reader, return);
|
||||
QTC_ASSERT(m_futureInterface, return);
|
||||
|
@@ -72,7 +72,7 @@ public:
|
||||
bool updateCMakeStateBeforeBuild();
|
||||
bool persistCMakeState();
|
||||
|
||||
void generateProjectTree(CMakeProjectNode *root);
|
||||
void generateProjectTree(CMakeListsNode *root);
|
||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const;
|
||||
|
@@ -49,6 +49,7 @@ namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeListsNode;
|
||||
|
||||
class BuildDirReader : public QObject
|
||||
{
|
||||
@@ -100,7 +101,7 @@ public:
|
||||
|
||||
virtual CMakeConfig parsedConfiguration() const = 0;
|
||||
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
|
||||
virtual void generateProjectTree(CMakeProjectNode *root,
|
||||
virtual void generateProjectTree(CMakeListsNode *root,
|
||||
const QList<ProjectExplorer::FileNode *> &allFiles) = 0;
|
||||
virtual QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) = 0;
|
||||
|
||||
|
@@ -202,7 +202,7 @@ QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
|
||||
return m_buildDirManager->buildTargets();
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::generateProjectTree(CMakeProjectNode *root) const
|
||||
void CMakeBuildConfiguration::generateProjectTree(CMakeListsNode *root) const
|
||||
{
|
||||
if (!m_buildDirManager || m_buildDirManager->isParsing())
|
||||
return;
|
||||
|
@@ -46,6 +46,7 @@ namespace Internal {
|
||||
class BuildDirManager;
|
||||
class CMakeBuildConfigurationFactory;
|
||||
class CMakeBuildSettingsWidget;
|
||||
class CMakeListsNode;
|
||||
|
||||
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
||||
{
|
||||
@@ -84,7 +85,7 @@ public:
|
||||
void clearCache();
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const;
|
||||
void generateProjectTree(CMakeProjectNode *root) const;
|
||||
void generateProjectTree(CMakeListsNode *root) const;
|
||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder);
|
||||
|
||||
static Utils::FileName
|
||||
|
@@ -78,7 +78,7 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName)
|
||||
setDocument(new TextEditor::TextDocument);
|
||||
document()->setFilePath(fileName);
|
||||
|
||||
setRootProjectNode(new CMakeProjectNode(FileName::fromString(fileName.toFileInfo().absolutePath())));
|
||||
setRootProjectNode(new CMakeListsNode(fileName));
|
||||
setProjectContext(Core::Context(CMakeProjectManager::Constants::PROJECTCONTEXT));
|
||||
setProjectLanguages(Core::Context(ProjectExplorer::Constants::LANG_CXX));
|
||||
|
||||
@@ -104,7 +104,7 @@ void CMakeProject::updateProjectData()
|
||||
return;
|
||||
Kit *k = t->kit();
|
||||
|
||||
cmakeBc->generateProjectTree(static_cast<CMakeProjectNode *>(rootProjectNode()));
|
||||
cmakeBc->generateProjectTree(static_cast<CMakeListsNode *>(rootProjectNode()));
|
||||
|
||||
updateApplicationAndDeploymentTargets();
|
||||
updateTargetRunConfigurations(t);
|
||||
|
@@ -41,9 +41,8 @@ QT_END_NAMESPACE
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
namespace Internal {
|
||||
class CMakeBuildSettingsWidget;
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeProjectNode;
|
||||
class CMakeBuildSettingsWidget;
|
||||
class CMakeManager;
|
||||
} // namespace Internal
|
||||
|
||||
@@ -76,8 +75,7 @@ public:
|
||||
class CMAKE_EXPORT CMakeProject : public ProjectExplorer::Project
|
||||
{
|
||||
Q_OBJECT
|
||||
// for changeBuildDirectory
|
||||
friend class Internal::CMakeBuildSettingsWidget;
|
||||
|
||||
public:
|
||||
CMakeProject(Internal::CMakeManager *manager, const Utils::FileName &filename);
|
||||
~CMakeProject() final;
|
||||
@@ -128,6 +126,7 @@ private:
|
||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||
|
||||
friend class Internal::CMakeBuildConfiguration;
|
||||
friend class Internal::CMakeBuildSettingsWidget;
|
||||
};
|
||||
|
||||
} // namespace CMakeProjectManager
|
||||
|
@@ -25,22 +25,122 @@
|
||||
|
||||
#include "cmakeprojectnodes.h"
|
||||
|
||||
#include "cmakeprojectconstants.h"
|
||||
|
||||
#include <coreplugin/fileiconprovider.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
using namespace CMakeProjectManager;
|
||||
using namespace CMakeProjectManager::Internal;
|
||||
|
||||
CMakeProjectNode::CMakeProjectNode(const Utils::FileName &dirName)
|
||||
: ProjectExplorer::ProjectNode(dirName)
|
||||
CMakeInputsNode::CMakeInputsNode(const Utils::FileName &cmakeLists) :
|
||||
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
|
||||
return true;
|
||||
Utils::FileName result = cmakeLists;
|
||||
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);
|
||||
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 {
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
CMakeProjectNode(const Utils::FileName &dirName);
|
||||
bool showInSimpleTree() const override;
|
||||
QList<ProjectExplorer::ProjectAction> supportedActions(Node *node) const override;
|
||||
CMakeProjectNode(const Utils::FileName &directory);
|
||||
|
||||
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
|
||||
|
@@ -211,24 +211,90 @@ CMakeConfig ServerModeReader::parsedConfiguration() const
|
||||
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);
|
||||
QSet<Utils::FileName> knownFiles;
|
||||
for (auto it = m_cmakeInputsFileNodes.constBegin(); it != m_cmakeInputsFileNodes.constEnd(); ++it)
|
||||
knownFiles.insert((*it)->filePath());
|
||||
|
||||
QList<FileNode *> fileGroupNodes = m_cmakeInputsFileNodes;
|
||||
m_cmakeInputsFileNodes.clear(); // Clean out, they are not going to be used anymore!
|
||||
foreach (const FileGroup *fg, m_fileGroups) {
|
||||
for (const FileName &s : fg->sources) {
|
||||
const int oldCount = knownFiles.count();
|
||||
knownFiles.insert(s);
|
||||
if (oldCount != knownFiles.count())
|
||||
fileGroupNodes.append(new FileNode(s, FileType::Source, fg->isGenerated));
|
||||
FolderNode *folder
|
||||
= findOrDefault(base->folderNodes(), [basePath](const FolderNode *fn) {
|
||||
return fn->filePath() == basePath;
|
||||
});
|
||||
if (files.isEmpty()) {
|
||||
return folder;
|
||||
} else {
|
||||
if (!folder) {
|
||||
folder = new VirtualFolderNode(basePath, priority);
|
||||
folder->setDisplayName(displayName);
|
||||
base->addFolderNodes({ folder });
|
||||
}
|
||||
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)
|
||||
@@ -448,5 +514,231 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
|
||||
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 CMakeProjectManager
|
||||
|
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() 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;
|
||||
|
||||
private:
|
||||
@@ -119,6 +119,20 @@ private:
|
||||
void extractCMakeInputsData(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;
|
||||
|
||||
std::unique_ptr<ServerMode> m_cmakeServer;
|
||||
|
@@ -318,7 +318,7 @@ CMakeConfig TeaLeafReader::parseConfiguration(const FileName &cacheFile, QString
|
||||
return result;
|
||||
}
|
||||
|
||||
void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<FileNode *> &allFiles)
|
||||
void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<FileNode *> &allFiles)
|
||||
{
|
||||
root->setDisplayName(m_projectName);
|
||||
|
||||
|
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const final;
|
||||
CMakeConfig parsedConfiguration() const final;
|
||||
void generateProjectTree(CMakeProjectNode *root,
|
||||
void generateProjectTree(CMakeListsNode *root,
|
||||
const QList<ProjectExplorer::FileNode *> &allFiles) final;
|
||||
QSet<Core::Id> updateCodeModel(CppTools::ProjectPartBuilder &ppBuilder) final;
|
||||
|
||||
|
Reference in New Issue
Block a user