2019-06-13 14:24:04 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** 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 "fileapidataextractor.h"
|
|
|
|
|
|
2020-04-17 15:30:05 +02:00
|
|
|
#include "fileapiparser.h"
|
2019-06-13 14:24:04 +02:00
|
|
|
#include "projecttreehelper.h"
|
|
|
|
|
|
|
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/qtcprocess.h>
|
2020-01-14 13:53:09 +01:00
|
|
|
#include <utils/utilsicons.h>
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2021-06-21 16:14:20 +02:00
|
|
|
#include <projectexplorer/projecttree.h>
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
#include <QDir>
|
|
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
using namespace CMakeProjectManager;
|
|
|
|
|
using namespace CMakeProjectManager::Internal;
|
|
|
|
|
using namespace CMakeProjectManager::Internal::FileApiDetails;
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// Helpers:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
class CMakeFileResult
|
|
|
|
|
{
|
|
|
|
|
public:
|
2021-09-01 19:49:08 +02:00
|
|
|
QSet<CMakeFileInfo> cmakeFiles;
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeNodesSource;
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeNodesBuild;
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeNodesOther;
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeListNodes;
|
|
|
|
|
};
|
|
|
|
|
|
2021-09-01 19:49:08 +02:00
|
|
|
CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefiles,
|
2019-06-13 14:24:04 +02:00
|
|
|
const FilePath &sourceDirectory,
|
|
|
|
|
const FilePath &buildDirectory)
|
|
|
|
|
{
|
|
|
|
|
CMakeFileResult result;
|
|
|
|
|
|
|
|
|
|
for (const CMakeFileInfo &info : cmakefiles) {
|
2021-09-09 15:50:19 +02:00
|
|
|
const FilePath sfn = sourceDirectory.resolvePath(info.path);
|
2019-06-13 14:24:04 +02:00
|
|
|
const int oldCount = result.cmakeFiles.count();
|
2021-09-01 19:49:08 +02:00
|
|
|
CMakeFileInfo absolute(info);
|
|
|
|
|
absolute.path = sfn;
|
|
|
|
|
result.cmakeFiles.insert(absolute);
|
2019-06-13 14:24:04 +02:00
|
|
|
if (oldCount < result.cmakeFiles.count()) {
|
|
|
|
|
if (info.isCMake && !info.isCMakeListsDotTxt) {
|
|
|
|
|
// Skip files that cmake considers to be part of the installation -- but include
|
2020-04-07 14:44:22 +02:00
|
|
|
// CMakeLists.txt files. This fixes cmake binaries running from their own
|
2019-06-13 14:24:04 +02:00
|
|
|
// build directory.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto node = std::make_unique<FileNode>(sfn, FileType::Project);
|
|
|
|
|
node->setIsGenerated(info.isGenerated
|
|
|
|
|
&& !info.isCMakeListsDotTxt); // CMakeLists.txt are never
|
|
|
|
|
// generated, independent
|
|
|
|
|
// what cmake thinks:-)
|
|
|
|
|
|
|
|
|
|
if (info.isCMakeListsDotTxt) {
|
|
|
|
|
result.cmakeListNodes.emplace_back(std::move(node));
|
2021-09-09 15:50:19 +02:00
|
|
|
} else if (sfn.isChildOf(sourceDirectory)) {
|
2019-06-13 14:24:04 +02:00
|
|
|
result.cmakeNodesSource.emplace_back(std::move(node));
|
2021-09-09 15:50:19 +02:00
|
|
|
} else if (sfn.isChildOf(buildDirectory)) {
|
2019-06-13 14:24:04 +02:00
|
|
|
result.cmakeNodesBuild.emplace_back(std::move(node));
|
|
|
|
|
} else {
|
|
|
|
|
result.cmakeNodesOther.emplace_back(std::move(node));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PreprocessedData
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CMakeProjectManager::CMakeConfig cache;
|
|
|
|
|
|
2021-09-01 19:49:08 +02:00
|
|
|
QSet<CMakeFileInfo> cmakeFiles;
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeNodesSource;
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeNodesBuild;
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeNodesOther;
|
|
|
|
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeListNodes;
|
|
|
|
|
|
|
|
|
|
Configuration codemodel;
|
|
|
|
|
std::vector<TargetDetails> targetDetails;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PreprocessedData preprocess(FileApiData &data,
|
|
|
|
|
const FilePath &sourceDirectory,
|
|
|
|
|
const FilePath &buildDirectory,
|
|
|
|
|
QString &errorMessage)
|
|
|
|
|
{
|
2021-01-25 18:00:52 +01:00
|
|
|
Q_UNUSED(errorMessage)
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
PreprocessedData result;
|
|
|
|
|
|
|
|
|
|
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
|
|
|
|
|
2021-01-14 16:38:55 +01:00
|
|
|
result.codemodel = std::move(data.codemodel);
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
CMakeFileResult cmakeFileResult = extractCMakeFilesData(data.cmakeFiles,
|
|
|
|
|
sourceDirectory,
|
|
|
|
|
buildDirectory);
|
|
|
|
|
|
|
|
|
|
result.cmakeFiles = std::move(cmakeFileResult.cmakeFiles);
|
|
|
|
|
result.cmakeNodesSource = std::move(cmakeFileResult.cmakeNodesSource);
|
|
|
|
|
result.cmakeNodesBuild = std::move(cmakeFileResult.cmakeNodesBuild);
|
|
|
|
|
result.cmakeNodesOther = std::move(cmakeFileResult.cmakeNodesOther);
|
|
|
|
|
result.cmakeListNodes = std::move(cmakeFileResult.cmakeListNodes);
|
|
|
|
|
|
|
|
|
|
result.targetDetails = std::move(data.targetDetails);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-26 13:57:24 +02:00
|
|
|
QVector<FolderNode::LocationInfo> extractBacktraceInformation(const BacktraceInfo &backtraces,
|
|
|
|
|
const QDir &sourceDir,
|
|
|
|
|
int backtraceIndex,
|
|
|
|
|
unsigned int locationInfoPriority)
|
|
|
|
|
{
|
|
|
|
|
QVector<FolderNode::LocationInfo> info;
|
|
|
|
|
// Set up a default target path:
|
|
|
|
|
while (backtraceIndex != -1) {
|
|
|
|
|
const size_t bi = static_cast<size_t>(backtraceIndex);
|
|
|
|
|
QTC_ASSERT(bi < backtraces.nodes.size(), break);
|
|
|
|
|
const BacktraceNode &btNode = backtraces.nodes[bi];
|
|
|
|
|
backtraceIndex = btNode.parent; // advance to next node
|
|
|
|
|
|
|
|
|
|
const size_t fileIndex = static_cast<size_t>(btNode.file);
|
|
|
|
|
QTC_ASSERT(fileIndex < backtraces.files.size(), break);
|
|
|
|
|
const FilePath path = FilePath::fromString(
|
|
|
|
|
sourceDir.absoluteFilePath(backtraces.files[fileIndex]));
|
|
|
|
|
|
|
|
|
|
if (btNode.command < 0) {
|
|
|
|
|
// No command, skip: The file itself is already covered:-)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t commandIndex = static_cast<size_t>(btNode.command);
|
|
|
|
|
QTC_ASSERT(commandIndex < backtraces.commands.size(), break);
|
|
|
|
|
|
|
|
|
|
const QString command = backtraces.commands[commandIndex];
|
|
|
|
|
|
|
|
|
|
info.append(FolderNode::LocationInfo(command, path, btNode.line, locationInfoPriority));
|
|
|
|
|
}
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-05 13:25:32 +01:00
|
|
|
static bool isChildOf(const FilePath &path, const QStringList &prefixes)
|
|
|
|
|
{
|
|
|
|
|
for (const QString &prefix : prefixes)
|
|
|
|
|
if (path.isChildOf(FilePath::fromString(prefix)))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
|
2019-07-25 13:52:10 +02:00
|
|
|
const FilePath &sourceDirectory,
|
2021-08-19 18:51:18 +02:00
|
|
|
const FilePath &buildDirectory,
|
|
|
|
|
bool haveLibrariesRelativeToBuildDirectory)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
|
|
|
|
QDir sourceDir(sourceDirectory.toString());
|
2019-07-25 13:52:10 +02:00
|
|
|
|
2021-06-09 17:05:50 +02:00
|
|
|
const QList<CMakeBuildTarget> result = transform<QList>(input.targetDetails,
|
2021-08-19 18:51:18 +02:00
|
|
|
[&sourceDir, &sourceDirectory, &buildDirectory,
|
|
|
|
|
&haveLibrariesRelativeToBuildDirectory](const TargetDetails &t) {
|
2021-09-08 16:13:43 +02:00
|
|
|
const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir);
|
2020-01-21 14:00:56 +01:00
|
|
|
|
2019-07-26 11:37:13 +02:00
|
|
|
CMakeBuildTarget ct;
|
|
|
|
|
ct.title = t.name;
|
2021-06-09 17:05:50 +02:00
|
|
|
if (!t.artifacts.isEmpty())
|
2021-09-08 16:13:43 +02:00
|
|
|
ct.executable = buildDirectory.resolvePath(t.artifacts.at(0));
|
2019-07-26 11:37:13 +02:00
|
|
|
TargetType type = UtilityType;
|
|
|
|
|
if (t.type == "EXECUTABLE")
|
|
|
|
|
type = ExecutableType;
|
|
|
|
|
else if (t.type == "STATIC_LIBRARY")
|
|
|
|
|
type = StaticLibraryType;
|
|
|
|
|
else if (t.type == "OBJECT_LIBRARY")
|
|
|
|
|
type = ObjectLibraryType;
|
|
|
|
|
else if (t.type == "MODULE_LIBRARY" || t.type == "SHARED_LIBRARY")
|
|
|
|
|
type = DynamicLibraryType;
|
|
|
|
|
else
|
|
|
|
|
type = UtilityType;
|
|
|
|
|
ct.targetType = type;
|
2020-01-21 14:00:56 +01:00
|
|
|
ct.workingDirectory = ct.executable.isEmpty()
|
2021-06-09 17:05:50 +02:00
|
|
|
? currentBuildDir.absolutePath()
|
2020-01-21 14:00:56 +01:00
|
|
|
: ct.executable.parentDir();
|
2021-09-08 16:13:43 +02:00
|
|
|
ct.sourceDirectory = sourceDirectory.resolvePath(t.sourceDir);
|
2019-07-26 11:37:13 +02:00
|
|
|
|
2019-07-26 13:57:24 +02:00
|
|
|
ct.backtrace = extractBacktraceInformation(t.backtraceGraph, sourceDir, t.backtrace, 0);
|
|
|
|
|
|
|
|
|
|
for (const DependencyInfo &d : t.dependencies) {
|
|
|
|
|
ct.dependencyDefinitions.append(
|
|
|
|
|
extractBacktraceInformation(t.backtraceGraph, sourceDir, d.backtrace, 100));
|
|
|
|
|
}
|
|
|
|
|
for (const SourceInfo &si : t.sources) {
|
|
|
|
|
ct.sourceDefinitions.append(
|
|
|
|
|
extractBacktraceInformation(t.backtraceGraph, sourceDir, si.backtrace, 200));
|
|
|
|
|
}
|
|
|
|
|
for (const CompileInfo &ci : t.compileGroups) {
|
|
|
|
|
for (const IncludeInfo &ii : ci.includes) {
|
|
|
|
|
ct.includeDefinitions.append(
|
|
|
|
|
extractBacktraceInformation(t.backtraceGraph, sourceDir, ii.backtrace, 300));
|
|
|
|
|
}
|
|
|
|
|
for (const DefineInfo &di : ci.defines) {
|
|
|
|
|
ct.defineDefinitions.append(
|
|
|
|
|
extractBacktraceInformation(t.backtraceGraph, sourceDir, di.backtrace, 400));
|
2019-07-26 11:37:13 +02:00
|
|
|
}
|
2019-07-24 13:42:23 +02:00
|
|
|
}
|
2019-07-26 13:57:24 +02:00
|
|
|
for (const InstallDestination &id : t.installDestination) {
|
2021-06-09 14:08:44 +02:00
|
|
|
ct.installDefinitions.append(
|
2019-07-26 13:57:24 +02:00
|
|
|
extractBacktraceInformation(t.backtraceGraph, sourceDir, id.backtrace, 500));
|
|
|
|
|
}
|
2019-07-24 13:42:23 +02:00
|
|
|
|
2020-06-08 16:22:04 +02:00
|
|
|
if (ct.targetType == ExecutableType) {
|
|
|
|
|
Utils::FilePaths librarySeachPaths;
|
|
|
|
|
// Is this a GUI application?
|
|
|
|
|
ct.linksToQtGui = Utils::contains(t.link.value().fragments,
|
|
|
|
|
[](const FragmentInfo &f) {
|
|
|
|
|
return f.role == "libraries"
|
|
|
|
|
&& (f.fragment.contains("QtGui")
|
|
|
|
|
|| f.fragment.contains("Qt5Gui")
|
|
|
|
|
|| f.fragment.contains("Qt6Gui"));
|
|
|
|
|
});
|
|
|
|
|
|
2021-06-24 17:44:14 +02:00
|
|
|
ct.qtcRunnable = t.folderTargetProperty == "qtc_runnable";
|
|
|
|
|
|
2020-06-08 16:22:04 +02:00
|
|
|
// Extract library directories for executables:
|
2019-12-12 11:15:36 +01:00
|
|
|
for (const FragmentInfo &f : t.link.value().fragments) {
|
2020-06-08 16:22:04 +02:00
|
|
|
if (f.role == "flags") // ignore all flags fragments
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// CMake sometimes mixes several shell-escaped pieces into one fragment. Disentangle that again:
|
2021-05-06 13:07:36 +02:00
|
|
|
const QStringList parts = ProcessArgs::splitArgs(f.fragment);
|
2020-06-15 13:40:39 +02:00
|
|
|
for (const QString &part : parts) {
|
2020-06-08 16:22:04 +02:00
|
|
|
// Some projects abuse linking to libraries to pass random flags to the linker, so ignore
|
|
|
|
|
// flags mixed into a fragment
|
|
|
|
|
if (part.startsWith("-"))
|
|
|
|
|
continue;
|
|
|
|
|
|
2021-08-19 18:51:18 +02:00
|
|
|
const FilePath buildDir = haveLibrariesRelativeToBuildDirectory ? buildDirectory : currentBuildDir;
|
2021-09-08 16:13:43 +02:00
|
|
|
FilePath tmp = buildDir.resolvePath(FilePath::fromUserInput(part));
|
2020-06-08 16:22:04 +02:00
|
|
|
|
|
|
|
|
if (f.role == "libraries")
|
|
|
|
|
tmp = tmp.parentDir();
|
|
|
|
|
|
2021-03-05 13:25:32 +01:00
|
|
|
if (!tmp.isEmpty() && tmp.isDir()) {
|
|
|
|
|
// f.role is libraryPath or frameworkPath
|
|
|
|
|
// On Linux, exclude sub-paths from "/lib(64)", "/usr/lib(64)" and
|
|
|
|
|
// "/usr/local/lib" since these are usually in the standard search
|
|
|
|
|
// paths. There probably are more, but the naming schemes are arbitrary
|
|
|
|
|
// so we'd need to ask the linker ("ld --verbose | grep SEARCH_DIR").
|
|
|
|
|
if (!HostOsInfo::isLinuxHost()
|
|
|
|
|
|| !isChildOf(tmp,
|
|
|
|
|
{"/lib",
|
|
|
|
|
"/lib64",
|
|
|
|
|
"/usr/lib",
|
|
|
|
|
"/usr/lib64",
|
|
|
|
|
"/usr/local/lib"})) {
|
|
|
|
|
librarySeachPaths.append(tmp);
|
|
|
|
|
// Libraries often have their import libs in ../lib and the
|
|
|
|
|
// actual dll files in ../bin on windows. Qt is one example of that.
|
|
|
|
|
if (tmp.fileName() == "lib" && HostOsInfo::isWindowsHost()) {
|
|
|
|
|
const FilePath path = tmp.parentDir().pathAppended("bin");
|
|
|
|
|
|
|
|
|
|
if (path.isDir())
|
|
|
|
|
librarySeachPaths.append(path);
|
|
|
|
|
}
|
2020-06-08 16:22:04 +02:00
|
|
|
}
|
2020-01-21 14:00:56 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-12-12 11:15:36 +01:00
|
|
|
}
|
2020-06-08 16:22:04 +02:00
|
|
|
ct.libraryDirectories = filteredUnique(librarySeachPaths);
|
2019-12-12 11:15:36 +01:00
|
|
|
}
|
|
|
|
|
|
2019-07-26 11:37:13 +02:00
|
|
|
return ct;
|
|
|
|
|
});
|
2019-06-13 14:24:04 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QStringList splitFragments(const QStringList &fragments)
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
for (const QString &f : fragments) {
|
2021-05-06 13:07:36 +02:00
|
|
|
result += ProcessArgs::splitArgs(f);
|
2019-06-13 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-28 18:22:45 +02:00
|
|
|
RawProjectParts generateRawProjectParts(const PreprocessedData &input,
|
2020-04-08 19:37:21 +02:00
|
|
|
const FilePath &sourceDirectory)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
2019-08-28 18:22:45 +02:00
|
|
|
RawProjectParts rpps;
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
int counter = 0;
|
|
|
|
|
for (const TargetDetails &t : input.targetDetails) {
|
2020-04-18 20:55:35 +00:00
|
|
|
QDir sourceDir(sourceDirectory.toString());
|
|
|
|
|
|
2019-09-19 10:55:19 +02:00
|
|
|
bool needPostfix = t.compileGroups.size() > 1;
|
|
|
|
|
int count = 1;
|
2019-06-13 14:24:04 +02:00
|
|
|
for (const CompileInfo &ci : t.compileGroups) {
|
|
|
|
|
if (ci.language != "C" && ci.language != "CXX" && ci.language != "CUDA")
|
|
|
|
|
continue; // No need to bother the C++ codemodel
|
|
|
|
|
|
|
|
|
|
// CMake users worked around Creator's inability of listing header files by creating
|
|
|
|
|
// custom targets with all the header files. This target breaks the code model, so
|
|
|
|
|
// keep quiet about it:-)
|
|
|
|
|
if (ci.defines.empty() && ci.includes.empty() && allOf(ci.sources, [t](const int sid) {
|
|
|
|
|
const SourceInfo &source = t.sources[static_cast<size_t>(sid)];
|
|
|
|
|
return Node::fileTypeForFileName(FilePath::fromString(source.path))
|
|
|
|
|
== FileType::Header;
|
|
|
|
|
})) {
|
|
|
|
|
qWarning() << "Not reporting all-header compilegroup of target" << t.name
|
|
|
|
|
<< "to code model.";
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 17:01:37 +02:00
|
|
|
QString ending;
|
2021-01-11 15:57:16 +01:00
|
|
|
QString qtcPchFile;
|
|
|
|
|
if (ci.language == "C") {
|
2019-09-18 17:01:37 +02:00
|
|
|
ending = "/cmake_pch.h";
|
2021-01-11 15:57:16 +01:00
|
|
|
qtcPchFile = "qtc_cmake_pch.h";
|
|
|
|
|
}
|
|
|
|
|
else if (ci.language == "CXX") {
|
2019-09-18 17:01:37 +02:00
|
|
|
ending = "/cmake_pch.hxx";
|
2021-01-11 15:57:16 +01:00
|
|
|
qtcPchFile = "qtc_cmake_pch.hxx";
|
|
|
|
|
}
|
2019-09-18 17:01:37 +02:00
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
++counter;
|
2019-08-28 18:22:45 +02:00
|
|
|
RawProjectPart rpp;
|
2019-06-13 14:24:04 +02:00
|
|
|
rpp.setProjectFileLocation(t.sourceDir.pathAppended("CMakeLists.txt").toString());
|
2019-06-20 14:03:40 +02:00
|
|
|
rpp.setBuildSystemTarget(t.name);
|
2019-09-19 10:55:19 +02:00
|
|
|
const QString postfix = needPostfix ? "_cg" + QString::number(count) : QString();
|
|
|
|
|
rpp.setDisplayName(t.id + postfix);
|
2019-06-13 14:24:04 +02:00
|
|
|
rpp.setMacros(transform<QVector>(ci.defines, &DefineInfo::define));
|
|
|
|
|
rpp.setHeaderPaths(transform<QVector>(ci.includes, &IncludeInfo::path));
|
|
|
|
|
|
2021-01-11 15:57:16 +01:00
|
|
|
QStringList fragments = splitFragments(ci.fragments);
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2020-04-18 20:55:35 +00:00
|
|
|
FilePath precompiled_header
|
|
|
|
|
= FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) {
|
|
|
|
|
return si.path.endsWith(ending);
|
|
|
|
|
}).path);
|
2019-09-18 17:01:37 +02:00
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
rpp.setFiles(transform<QList>(ci.sources, [&t, &sourceDir](const int si) {
|
|
|
|
|
return sourceDir.absoluteFilePath(t.sources[static_cast<size_t>(si)].path);
|
|
|
|
|
}));
|
2019-10-21 15:06:28 +02:00
|
|
|
if (!precompiled_header.isEmpty()) {
|
|
|
|
|
if (precompiled_header.toFileInfo().isRelative()) {
|
2020-04-08 19:37:21 +02:00
|
|
|
const FilePath parentDir = FilePath::fromString(sourceDir.absolutePath());
|
2019-10-21 15:06:28 +02:00
|
|
|
precompiled_header = parentDir.pathAppended(precompiled_header.toString());
|
|
|
|
|
}
|
2021-01-11 15:57:16 +01:00
|
|
|
|
|
|
|
|
// Remove the CMake PCH usage command line options in order to avoid the case
|
|
|
|
|
// when the build system would produce a .pch/.gch file that would be treated
|
|
|
|
|
// by the Clang code model as its own and fail.
|
|
|
|
|
auto remove = [&](const QStringList &args) {
|
|
|
|
|
auto foundPos = std::search(fragments.begin(), fragments.end(),
|
|
|
|
|
args.begin(), args.end());
|
|
|
|
|
if (foundPos != fragments.end())
|
|
|
|
|
fragments.erase(foundPos, std::next(foundPos, args.size()));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
remove({"-Xclang", "-include-pch", "-Xclang", precompiled_header.toString() + ".gch"});
|
|
|
|
|
remove({"-Xclang", "-include-pch", "-Xclang", precompiled_header.toString() + ".pch"});
|
|
|
|
|
remove({"-Xclang", "-include", "-Xclang", precompiled_header.toString()});
|
|
|
|
|
remove({"-include", precompiled_header.toString()});
|
|
|
|
|
remove({"/FI", precompiled_header.toString()});
|
|
|
|
|
|
|
|
|
|
// Make a copy of the CMake PCH header and use it instead
|
|
|
|
|
FilePath qtc_precompiled_header = precompiled_header.parentDir().pathAppended(qtcPchFile);
|
|
|
|
|
FileUtils::copyIfDifferent(precompiled_header, qtc_precompiled_header);
|
|
|
|
|
|
|
|
|
|
rpp.setPreCompiledHeaders({qtc_precompiled_header.toString()});
|
2019-10-21 15:06:28 +02:00
|
|
|
}
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2021-01-11 15:57:16 +01:00
|
|
|
RawProjectPartFlags cProjectFlags;
|
|
|
|
|
cProjectFlags.commandLineFlags = fragments;
|
|
|
|
|
rpp.setFlagsForC(cProjectFlags);
|
|
|
|
|
|
|
|
|
|
RawProjectPartFlags cxxProjectFlags;
|
|
|
|
|
cxxProjectFlags.commandLineFlags = cProjectFlags.commandLineFlags;
|
|
|
|
|
rpp.setFlagsForCxx(cxxProjectFlags);
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
const bool isExecutable = t.type == "EXECUTABLE";
|
2019-08-28 13:04:16 +02:00
|
|
|
rpp.setBuildTargetType(isExecutable ? ProjectExplorer::BuildTargetType::Executable
|
|
|
|
|
: ProjectExplorer::BuildTargetType::Library);
|
2019-06-13 14:24:04 +02:00
|
|
|
rpps.append(rpp);
|
2019-09-19 10:55:19 +02:00
|
|
|
++count;
|
2019-06-13 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rpps;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-13 14:24:03 +02:00
|
|
|
FilePath directorySourceDir(const Configuration &c, const FilePath &sourceDir, int directoryIndex)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
|
|
|
|
const size_t di = static_cast<size_t>(directoryIndex);
|
2019-06-21 08:49:01 +02:00
|
|
|
QTC_ASSERT(di < c.directories.size(), return FilePath());
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2021-09-13 14:24:03 +02:00
|
|
|
return sourceDir.resolvePath(c.directories[di].sourcePath).cleanPath();
|
2019-06-13 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
|
2021-09-13 14:24:03 +02:00
|
|
|
FilePath directoryBuildDir(const Configuration &c, const FilePath &buildDir, int directoryIndex)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
|
|
|
|
const size_t di = static_cast<size_t>(directoryIndex);
|
2019-06-21 08:49:01 +02:00
|
|
|
QTC_ASSERT(di < c.directories.size(), return FilePath());
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2021-09-13 14:24:03 +02:00
|
|
|
return buildDir.resolvePath(c.directories[di].buildPath).cleanPath();
|
2019-06-13 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void addProjects(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
|
|
|
|
|
const Configuration &config,
|
2021-09-13 14:24:03 +02:00
|
|
|
const FilePath &sourceDir)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
|
|
|
|
for (const FileApiDetails::Project &p : config.projects) {
|
|
|
|
|
if (p.parent == -1)
|
|
|
|
|
continue; // Top-level project has already been covered
|
|
|
|
|
FilePath dir = directorySourceDir(config, sourceDir, p.directories[0]);
|
|
|
|
|
createProjectNode(cmakeListsNodes, dir, p.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 14:21:05 +01:00
|
|
|
FolderNode *createSourceGroupNode(const QString &sourceGroupName,
|
|
|
|
|
const FilePath &sourceDirectory,
|
|
|
|
|
FolderNode *targetRoot)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
2020-01-14 14:21:05 +01:00
|
|
|
FolderNode *currentNode = targetRoot;
|
|
|
|
|
|
|
|
|
|
if (!sourceGroupName.isEmpty()) {
|
|
|
|
|
const QStringList parts = sourceGroupName.split("\\");
|
|
|
|
|
|
|
|
|
|
for (const QString &p : parts) {
|
|
|
|
|
FolderNode *existingNode = Utils::findOrDefault(currentNode->folderNodes(),
|
|
|
|
|
[&p](const FolderNode *fn) {
|
|
|
|
|
return fn->displayName() == p;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!existingNode) {
|
|
|
|
|
auto node = createCMakeVFolder(sourceDirectory, Node::DefaultFolderPriority + 5, p);
|
|
|
|
|
node->setListInProject(false);
|
2021-04-08 16:31:31 +02:00
|
|
|
node->setIcon(
|
|
|
|
|
[] { return QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()); });
|
2020-01-14 14:21:05 +01:00
|
|
|
|
|
|
|
|
existingNode = node.get();
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2020-01-14 14:21:05 +01:00
|
|
|
currentNode->addNode(std::move(node));
|
|
|
|
|
}
|
2019-06-13 14:24:04 +02:00
|
|
|
|
2020-01-14 14:21:05 +01:00
|
|
|
currentNode = existingNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return currentNode;
|
2019-06-13 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void addCompileGroups(ProjectNode *targetRoot,
|
|
|
|
|
const Utils::FilePath &topSourceDirectory,
|
|
|
|
|
const Utils::FilePath &sourceDirectory,
|
|
|
|
|
const Utils::FilePath &buildDirectory,
|
|
|
|
|
const TargetDetails &td,
|
2019-06-20 15:51:04 +02:00
|
|
|
QSet<FilePath> &knownHeaderNodes)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
|
|
|
|
const bool inSourceBuild = (sourceDirectory == buildDirectory);
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<FileNode>> toList;
|
|
|
|
|
QSet<Utils::FilePath> alreadyListed;
|
|
|
|
|
|
|
|
|
|
// Files already added by other configurations:
|
|
|
|
|
targetRoot->forEachGenericNode(
|
|
|
|
|
[&alreadyListed](const Node *n) { alreadyListed.insert(n->filePath()); });
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<FileNode>> buildFileNodes;
|
|
|
|
|
std::vector<std::unique_ptr<FileNode>> otherFileNodes;
|
2020-01-14 13:53:09 +01:00
|
|
|
std::vector<std::vector<std::unique_ptr<FileNode>>> sourceGroupFileNodes{td.sourceGroups.size()};
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
for (const SourceInfo &si : td.sources) {
|
2021-09-13 14:24:03 +02:00
|
|
|
const FilePath sourcePath = topSourceDirectory.resolvePath(si.path).cleanPath();
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
// Filter out already known files:
|
|
|
|
|
const int count = alreadyListed.count();
|
|
|
|
|
alreadyListed.insert(sourcePath);
|
|
|
|
|
if (count == alreadyListed.count())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Create FileNodes from the file
|
|
|
|
|
auto node = std::make_unique<FileNode>(sourcePath, Node::fileTypeForFileName(sourcePath));
|
|
|
|
|
node->setIsGenerated(si.isGenerated);
|
|
|
|
|
|
|
|
|
|
// Register headers:
|
|
|
|
|
if (node->fileType() == FileType::Header)
|
2019-06-20 15:51:04 +02:00
|
|
|
knownHeaderNodes.insert(node->filePath());
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
// Where does the file node need to go?
|
|
|
|
|
if (sourcePath.isChildOf(buildDirectory) && !inSourceBuild) {
|
|
|
|
|
buildFileNodes.emplace_back(std::move(node));
|
|
|
|
|
} else if (sourcePath.isChildOf(sourceDirectory)) {
|
2020-01-14 13:53:09 +01:00
|
|
|
sourceGroupFileNodes[si.sourceGroup].emplace_back(std::move(node));
|
2019-06-13 14:24:04 +02:00
|
|
|
} else {
|
|
|
|
|
otherFileNodes.emplace_back(std::move(node));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 13:53:09 +01:00
|
|
|
// Calculate base directory for source groups:
|
|
|
|
|
for (size_t i = 0; i < sourceGroupFileNodes.size(); ++i) {
|
|
|
|
|
std::vector<std::unique_ptr<FileNode>> ¤t = sourceGroupFileNodes[i];
|
|
|
|
|
FilePath baseDirectory;
|
|
|
|
|
// All the sourceGroupFileNodes are below sourceDirectory, so this is safe:
|
|
|
|
|
for (const std::unique_ptr<FileNode> &fn : current) {
|
|
|
|
|
if (baseDirectory.isEmpty()) {
|
|
|
|
|
baseDirectory = fn->filePath().parentDir();
|
|
|
|
|
} else {
|
|
|
|
|
baseDirectory = Utils::FileUtils::commonPath(baseDirectory, fn->filePath());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-14 14:21:05 +01:00
|
|
|
FolderNode *insertNode = createSourceGroupNode(td.sourceGroups[i],
|
|
|
|
|
baseDirectory,
|
|
|
|
|
targetRoot);
|
2020-06-21 01:24:25 -07:00
|
|
|
insertNode->addNestedNodes(std::move(current), baseDirectory);
|
2020-01-14 13:53:09 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
addCMakeVFolder(targetRoot,
|
|
|
|
|
buildDirectory,
|
|
|
|
|
100,
|
|
|
|
|
QCoreApplication::translate("CMakeProjectManager::Internal::FileApi",
|
|
|
|
|
"<Build Directory>"),
|
|
|
|
|
std::move(buildFileNodes));
|
|
|
|
|
addCMakeVFolder(targetRoot,
|
|
|
|
|
Utils::FilePath(),
|
|
|
|
|
10,
|
|
|
|
|
QCoreApplication::translate("CMakeProjectManager::Internal::FileApi",
|
|
|
|
|
"<Other Locations>"),
|
|
|
|
|
std::move(otherFileNodes));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
|
|
|
|
|
const Configuration &config,
|
|
|
|
|
const std::vector<TargetDetails> &targetDetails,
|
2021-09-13 14:24:03 +02:00
|
|
|
const FilePath &sourceDir,
|
|
|
|
|
const FilePath &buildDir,
|
2019-06-20 15:51:04 +02:00
|
|
|
QSet<FilePath> &knownHeaderNodes)
|
2019-06-13 14:24:04 +02:00
|
|
|
{
|
|
|
|
|
for (const FileApiDetails::Target &t : config.targets) {
|
|
|
|
|
const TargetDetails &td = Utils::findOrDefault(targetDetails,
|
|
|
|
|
Utils::equal(&TargetDetails::id, t.id));
|
|
|
|
|
|
|
|
|
|
const FilePath dir = directorySourceDir(config, sourceDir, t.directory);
|
|
|
|
|
|
|
|
|
|
CMakeTargetNode *tNode = createTargetNode(cmakeListsNodes, dir, t.name);
|
|
|
|
|
QTC_ASSERT(tNode, continue);
|
|
|
|
|
|
|
|
|
|
tNode->setTargetInformation(td.artifacts, td.type);
|
|
|
|
|
tNode->setBuildDirectory(directoryBuildDir(config, buildDir, t.directory));
|
|
|
|
|
|
2021-09-13 14:24:03 +02:00
|
|
|
addCompileGroups(tNode, sourceDir, dir, tNode->buildDirectory(), td, knownHeaderNodes);
|
2019-06-13 14:24:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-20 15:51:04 +02:00
|
|
|
std::pair<std::unique_ptr<CMakeProjectNode>, QSet<FilePath>> generateRootProjectNode(
|
2019-06-13 14:24:04 +02:00
|
|
|
PreprocessedData &data, const FilePath &sourceDirectory, const FilePath &buildDirectory)
|
|
|
|
|
{
|
2019-06-20 15:51:04 +02:00
|
|
|
std::pair<std::unique_ptr<CMakeProjectNode>, QSet<FilePath>> result;
|
2019-06-13 14:24:04 +02:00
|
|
|
result.first = std::make_unique<CMakeProjectNode>(sourceDirectory);
|
|
|
|
|
|
|
|
|
|
const FileApiDetails::Project topLevelProject
|
|
|
|
|
= findOrDefault(data.codemodel.projects, equal(&FileApiDetails::Project::parent, -1));
|
|
|
|
|
if (!topLevelProject.name.isEmpty())
|
|
|
|
|
result.first->setDisplayName(topLevelProject.name);
|
2020-06-10 11:39:12 +02:00
|
|
|
else
|
|
|
|
|
result.first->setDisplayName(sourceDirectory.fileName());
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
QHash<FilePath, ProjectNode *> cmakeListsNodes = addCMakeLists(result.first.get(),
|
|
|
|
|
std::move(data.cmakeListNodes));
|
|
|
|
|
data.cmakeListNodes.clear(); // Remove all the nullptr in the vector...
|
|
|
|
|
|
2019-06-20 15:51:04 +02:00
|
|
|
QSet<FilePath> knownHeaders;
|
2021-09-13 14:24:03 +02:00
|
|
|
addProjects(cmakeListsNodes, data.codemodel, sourceDirectory);
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
addTargets(cmakeListsNodes,
|
|
|
|
|
data.codemodel,
|
|
|
|
|
data.targetDetails,
|
|
|
|
|
sourceDirectory,
|
2021-09-13 14:24:03 +02:00
|
|
|
buildDirectory,
|
2019-06-13 14:24:04 +02:00
|
|
|
knownHeaders);
|
|
|
|
|
|
|
|
|
|
// addHeaderNodes(root.get(), knownHeaders, allFiles);
|
|
|
|
|
|
|
|
|
|
if (!data.cmakeNodesSource.empty() || !data.cmakeNodesBuild.empty()
|
|
|
|
|
|| !data.cmakeNodesOther.empty())
|
|
|
|
|
addCMakeInputs(result.first.get(),
|
|
|
|
|
sourceDirectory,
|
|
|
|
|
buildDirectory,
|
|
|
|
|
std::move(data.cmakeNodesSource),
|
|
|
|
|
std::move(data.cmakeNodesBuild),
|
|
|
|
|
std::move(data.cmakeNodesOther));
|
|
|
|
|
|
|
|
|
|
data.cmakeNodesSource.clear(); // Remove all the nullptr in the vector...
|
|
|
|
|
data.cmakeNodesBuild.clear(); // Remove all the nullptr in the vector...
|
|
|
|
|
data.cmakeNodesOther.clear(); // Remove all the nullptr in the vector...
|
|
|
|
|
|
|
|
|
|
result.second = knownHeaders;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-26 13:57:24 +02:00
|
|
|
void setupLocationInfoForTargets(CMakeProjectNode *rootNode, const QList<CMakeBuildTarget> &targets)
|
|
|
|
|
{
|
|
|
|
|
for (const CMakeBuildTarget &t : targets) {
|
|
|
|
|
FolderNode *folderNode = static_cast<FolderNode *>(
|
|
|
|
|
rootNode->findNode(Utils::equal(&Node::buildKey, t.title)));
|
|
|
|
|
if (folderNode) {
|
|
|
|
|
QSet<std::pair<FilePath, int>> locations;
|
|
|
|
|
auto dedup = [&locations](const Backtrace &bt) {
|
|
|
|
|
QVector<FolderNode::LocationInfo> result;
|
|
|
|
|
for (const FolderNode::LocationInfo &i : bt) {
|
|
|
|
|
int count = locations.count();
|
|
|
|
|
locations.insert(std::make_pair(i.path, i.line));
|
|
|
|
|
if (count != locations.count()) {
|
|
|
|
|
result.append(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QVector<FolderNode::LocationInfo> result = dedup(t.backtrace);
|
|
|
|
|
auto dedupMulti = [&dedup](const Backtraces &bts) {
|
|
|
|
|
QVector<FolderNode::LocationInfo> result;
|
|
|
|
|
for (const Backtrace &bt : bts) {
|
|
|
|
|
result.append(dedup(bt));
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
result += dedupMulti(t.dependencyDefinitions);
|
|
|
|
|
result += dedupMulti(t.includeDefinitions);
|
|
|
|
|
result += dedupMulti(t.defineDefinitions);
|
|
|
|
|
result += dedupMulti(t.sourceDefinitions);
|
|
|
|
|
result += dedupMulti(t.installDefinitions);
|
|
|
|
|
|
|
|
|
|
folderNode->setLocationInfo(result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace CMakeProjectManager {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
using namespace FileApiDetails;
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// extractData:
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
FileApiQtcData extractData(FileApiData &input,
|
|
|
|
|
const FilePath &sourceDirectory,
|
|
|
|
|
const FilePath &buildDirectory)
|
|
|
|
|
{
|
|
|
|
|
FileApiQtcData result;
|
|
|
|
|
|
|
|
|
|
// Preprocess our input:
|
|
|
|
|
PreprocessedData data = preprocess(input, sourceDirectory, buildDirectory, result.errorMessage);
|
|
|
|
|
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
|
|
|
|
if (!result.errorMessage.isEmpty()) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 18:51:18 +02:00
|
|
|
// Ninja generator from CMake version 3.20.5 has libraries relative to build directory
|
|
|
|
|
const bool haveLibrariesRelativeToBuildDirectory =
|
|
|
|
|
input.replyFile.generator.startsWith("Ninja")
|
|
|
|
|
&& input.replyFile.cmakeVersion >= QVersionNumber(3, 20, 5);
|
|
|
|
|
|
|
|
|
|
result.buildTargets = generateBuildTargets(data, sourceDirectory, buildDirectory, haveLibrariesRelativeToBuildDirectory);
|
2019-06-13 14:24:04 +02:00
|
|
|
result.cmakeFiles = std::move(data.cmakeFiles);
|
2020-04-08 19:37:21 +02:00
|
|
|
result.projectParts = generateRawProjectParts(data, sourceDirectory);
|
2019-06-13 14:24:04 +02:00
|
|
|
|
|
|
|
|
auto pair = generateRootProjectNode(data, sourceDirectory, buildDirectory);
|
2021-06-21 16:14:20 +02:00
|
|
|
ProjectTree::applyTreeManager(pair.first.get()); // QRC nodes
|
2019-06-13 14:24:04 +02:00
|
|
|
result.rootProjectNode = std::move(pair.first);
|
|
|
|
|
result.knownHeaders = std::move(pair.second);
|
|
|
|
|
|
2019-07-26 13:57:24 +02:00
|
|
|
setupLocationInfoForTargets(result.rootProjectNode.get(), result.buildTargets);
|
|
|
|
|
|
2020-09-28 15:10:04 +02:00
|
|
|
result.ctestPath = input.replyFile.ctestExecutable;
|
2021-01-14 16:38:55 +01:00
|
|
|
result.isMultiConfig = input.replyFile.isMultiConfig;
|
|
|
|
|
if (input.replyFile.isMultiConfig && input.replyFile.generator != "Ninja Multi-Config")
|
|
|
|
|
result.usesAllCapsTargets = true;
|
2020-09-28 15:10:04 +02:00
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-26 15:36:59 +01:00
|
|
|
FileApiQtcData generateFallbackData(const FilePath &topCmakeFile,
|
|
|
|
|
const FilePath &sourceDirectory,
|
|
|
|
|
const FilePath &buildDirectory,
|
|
|
|
|
QString errorMessage)
|
|
|
|
|
{
|
2020-12-11 17:56:08 +01:00
|
|
|
Q_UNUSED(buildDirectory)
|
|
|
|
|
|
2020-10-26 15:36:59 +01:00
|
|
|
FileApiQtcData result;
|
|
|
|
|
|
|
|
|
|
result.rootProjectNode.reset(new CMakeProjectNode{sourceDirectory});
|
|
|
|
|
result.rootProjectNode->setDisplayName(sourceDirectory.fileName());
|
|
|
|
|
result.errorMessage = errorMessage;
|
|
|
|
|
|
|
|
|
|
if (!topCmakeFile.isEmpty()) {
|
|
|
|
|
auto node = std::make_unique<FileNode>(topCmakeFile, FileType::Project);
|
|
|
|
|
node->setIsGenerated(false);
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<FileNode>> fileNodes;
|
|
|
|
|
fileNodes.emplace_back(std::move(node));
|
|
|
|
|
|
|
|
|
|
addCMakeLists(result.rootProjectNode.get(), std::move(fileNodes));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 14:24:04 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace CMakeProjectManager
|