forked from qt-creator/qt-creator
FileApiReader: Make shutdown faster
Check more often for canceled future. Make more functions static. Fixes: QTCREATORBUG-27729 Change-Id: I8dd787acea6343008c7515fb6a4fdfde50b37aee Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -12,10 +12,10 @@
|
|||||||
#include <cppeditor/cppeditorconstants.h>
|
#include <cppeditor/cppeditorconstants.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/icon.h>
|
||||||
#include <utils/mimeutils.h>
|
#include <utils/mimeutils.h>
|
||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/icon.h>
|
|
||||||
|
|
||||||
#include <projectexplorer/projecttree.h>
|
#include <projectexplorer/projecttree.h>
|
||||||
|
|
||||||
@@ -45,14 +45,13 @@ public:
|
|||||||
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeListNodes;
|
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeListNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefiles,
|
static CMakeFileResult extractCMakeFilesData(const QFuture<void> &cancelFuture,
|
||||||
const FilePath &sourceDirectory,
|
const std::vector<CMakeFileInfo> &cmakefiles,
|
||||||
const FilePath &buildDirectory)
|
const FilePath &sourceDirectory,
|
||||||
|
const FilePath &buildDirectory)
|
||||||
{
|
{
|
||||||
CMakeFileResult result;
|
|
||||||
|
|
||||||
if (cmakefiles.empty())
|
if (cmakefiles.empty())
|
||||||
return result;
|
return {};
|
||||||
|
|
||||||
// Uniquify fileInfos
|
// Uniquify fileInfos
|
||||||
std::set<CMakeFileInfo> cmakeFileSet{cmakefiles.begin(), cmakefiles.end()};
|
std::set<CMakeFileInfo> cmakeFileSet{cmakefiles.begin(), cmakefiles.end()};
|
||||||
@@ -60,7 +59,9 @@ CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefil
|
|||||||
// Load and parse cmake files. We use concurrency here to speed up the process of
|
// Load and parse cmake files. We use concurrency here to speed up the process of
|
||||||
// reading many small files, which can get slow especially on remote devices.
|
// reading many small files, which can get slow especially on remote devices.
|
||||||
QFuture<CMakeFileInfo> mapResult
|
QFuture<CMakeFileInfo> mapResult
|
||||||
= QtConcurrent::mapped(cmakeFileSet, [sourceDirectory](const auto &info) {
|
= QtConcurrent::mapped(cmakeFileSet, [cancelFuture, sourceDirectory](const auto &info) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return CMakeFileInfo();
|
||||||
const FilePath sfn = sourceDirectory.resolvePath(info.path);
|
const FilePath sfn = sourceDirectory.resolvePath(info.path);
|
||||||
CMakeFileInfo absolute(info);
|
CMakeFileInfo absolute(info);
|
||||||
absolute.path = sfn;
|
absolute.path = sfn;
|
||||||
@@ -86,7 +87,15 @@ CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefil
|
|||||||
|
|
||||||
mapResult.waitForFinished();
|
mapResult.waitForFinished();
|
||||||
|
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
CMakeFileResult result;
|
||||||
|
|
||||||
for (const auto &info : mapResult.results()) {
|
for (const auto &info : mapResult.results()) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
result.cmakeFiles.insert(info);
|
result.cmakeFiles.insert(info);
|
||||||
|
|
||||||
if (info.isCMake && !info.isCMakeListsDotTxt) {
|
if (info.isCMake && !info.isCMakeListsDotTxt) {
|
||||||
@@ -132,22 +141,17 @@ public:
|
|||||||
std::vector<TargetDetails> targetDetails;
|
std::vector<TargetDetails> targetDetails;
|
||||||
};
|
};
|
||||||
|
|
||||||
PreprocessedData preprocess(FileApiData &data,
|
static PreprocessedData preprocess(const QFuture<void> &cancelFuture, FileApiData &data,
|
||||||
const FilePath &sourceDirectory,
|
const FilePath &sourceDirectory, const FilePath &buildDirectory)
|
||||||
const FilePath &buildDirectory,
|
|
||||||
QString &errorMessage)
|
|
||||||
{
|
{
|
||||||
Q_UNUSED(errorMessage)
|
|
||||||
|
|
||||||
PreprocessedData result;
|
PreprocessedData result;
|
||||||
|
|
||||||
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
||||||
|
|
||||||
result.codemodel = std::move(data.codemodel);
|
result.codemodel = std::move(data.codemodel);
|
||||||
|
|
||||||
CMakeFileResult cmakeFileResult = extractCMakeFilesData(data.cmakeFiles,
|
CMakeFileResult cmakeFileResult = extractCMakeFilesData(cancelFuture, data.cmakeFiles,
|
||||||
sourceDirectory,
|
sourceDirectory, buildDirectory);
|
||||||
buildDirectory);
|
|
||||||
|
|
||||||
result.cmakeFiles = std::move(cmakeFileResult.cmakeFiles);
|
result.cmakeFiles = std::move(cmakeFileResult.cmakeFiles);
|
||||||
result.cmakeNodesSource = std::move(cmakeFileResult.cmakeNodesSource);
|
result.cmakeNodesSource = std::move(cmakeFileResult.cmakeNodesSource);
|
||||||
@@ -160,10 +164,11 @@ PreprocessedData preprocess(FileApiData &data,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<FolderNode::LocationInfo> extractBacktraceInformation(const BacktraceInfo &backtraces,
|
static QVector<FolderNode::LocationInfo> extractBacktraceInformation(
|
||||||
const FilePath &sourceDir,
|
const BacktraceInfo &backtraces,
|
||||||
int backtraceIndex,
|
const FilePath &sourceDir,
|
||||||
unsigned int locationInfoPriority)
|
int backtraceIndex,
|
||||||
|
unsigned int locationInfoPriority)
|
||||||
{
|
{
|
||||||
QVector<FolderNode::LocationInfo> info;
|
QVector<FolderNode::LocationInfo> info;
|
||||||
// Set up a default target path:
|
// Set up a default target path:
|
||||||
@@ -200,135 +205,145 @@ static bool isChildOf(const FilePath &path, const FilePaths &prefixes)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
|
static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
|
||||||
const FilePath &sourceDirectory,
|
const FilePath &sourceDirectory,
|
||||||
const FilePath &buildDirectory,
|
const FilePath &buildDirectory,
|
||||||
bool haveLibrariesRelativeToBuildDirectory)
|
bool relativeLibs)
|
||||||
{
|
{
|
||||||
const QList<CMakeBuildTarget> result = transform<QList>(input.targetDetails,
|
const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir);
|
||||||
[&sourceDirectory, &buildDirectory,
|
|
||||||
&haveLibrariesRelativeToBuildDirectory](const TargetDetails &t) {
|
|
||||||
const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir);
|
|
||||||
|
|
||||||
CMakeBuildTarget ct;
|
CMakeBuildTarget ct;
|
||||||
ct.title = t.name;
|
ct.title = t.name;
|
||||||
if (!t.artifacts.isEmpty())
|
if (!t.artifacts.isEmpty())
|
||||||
ct.executable = buildDirectory.resolvePath(t.artifacts.at(0));
|
ct.executable = buildDirectory.resolvePath(t.artifacts.at(0));
|
||||||
TargetType type = UtilityType;
|
TargetType type = UtilityType;
|
||||||
if (t.type == "EXECUTABLE")
|
if (t.type == "EXECUTABLE")
|
||||||
type = ExecutableType;
|
type = ExecutableType;
|
||||||
else if (t.type == "STATIC_LIBRARY")
|
else if (t.type == "STATIC_LIBRARY")
|
||||||
type = StaticLibraryType;
|
type = StaticLibraryType;
|
||||||
else if (t.type == "OBJECT_LIBRARY")
|
else if (t.type == "OBJECT_LIBRARY")
|
||||||
type = ObjectLibraryType;
|
type = ObjectLibraryType;
|
||||||
else if (t.type == "MODULE_LIBRARY" || t.type == "SHARED_LIBRARY")
|
else if (t.type == "MODULE_LIBRARY" || t.type == "SHARED_LIBRARY")
|
||||||
type = DynamicLibraryType;
|
type = DynamicLibraryType;
|
||||||
else
|
else
|
||||||
type = UtilityType;
|
type = UtilityType;
|
||||||
ct.targetType = type;
|
ct.targetType = type;
|
||||||
ct.workingDirectory = ct.executable.isEmpty()
|
ct.workingDirectory = ct.executable.isEmpty()
|
||||||
? currentBuildDir.absolutePath()
|
? currentBuildDir.absolutePath()
|
||||||
: ct.executable.parentDir();
|
: ct.executable.parentDir();
|
||||||
ct.sourceDirectory = sourceDirectory.resolvePath(t.sourceDir);
|
ct.sourceDirectory = sourceDirectory.resolvePath(t.sourceDir);
|
||||||
|
|
||||||
ct.backtrace = extractBacktraceInformation(t.backtraceGraph, sourceDirectory, t.backtrace, 0);
|
ct.backtrace = extractBacktraceInformation(t.backtraceGraph, sourceDirectory, t.backtrace, 0);
|
||||||
|
|
||||||
for (const DependencyInfo &d : t.dependencies) {
|
for (const DependencyInfo &d : t.dependencies) {
|
||||||
ct.dependencyDefinitions.append(
|
ct.dependencyDefinitions.append(
|
||||||
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, d.backtrace, 100));
|
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, d.backtrace, 100));
|
||||||
}
|
}
|
||||||
for (const SourceInfo &si : t.sources) {
|
for (const SourceInfo &si : t.sources) {
|
||||||
ct.sourceDefinitions.append(
|
ct.sourceDefinitions.append(
|
||||||
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, si.backtrace, 200));
|
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, si.backtrace, 200));
|
||||||
}
|
}
|
||||||
for (const CompileInfo &ci : t.compileGroups) {
|
for (const CompileInfo &ci : t.compileGroups) {
|
||||||
for (const IncludeInfo &ii : ci.includes) {
|
for (const IncludeInfo &ii : ci.includes) {
|
||||||
ct.includeDefinitions.append(
|
ct.includeDefinitions.append(
|
||||||
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, ii.backtrace, 300));
|
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, ii.backtrace, 300));
|
||||||
|
}
|
||||||
|
for (const DefineInfo &di : ci.defines) {
|
||||||
|
ct.defineDefinitions.append(
|
||||||
|
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, di.backtrace, 400));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const InstallDestination &id : t.installDestination) {
|
||||||
|
ct.installDefinitions.append(
|
||||||
|
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, id.backtrace, 500));
|
||||||
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
});
|
||||||
|
|
||||||
|
ct.qtcRunnable = t.folderTargetProperty == "qtc_runnable";
|
||||||
|
|
||||||
|
// Extract library directories for executables:
|
||||||
|
for (const FragmentInfo &f : t.link.value().fragments) {
|
||||||
|
if (f.role == "flags") // ignore all flags fragments
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// CMake sometimes mixes several shell-escaped pieces into one fragment. Disentangle that again:
|
||||||
|
const QStringList parts = ProcessArgs::splitArgs(f.fragment, HostOsInfo::hostOs());
|
||||||
|
for (QString part : parts) {
|
||||||
|
// Library search paths that are added with target_link_directories are added as
|
||||||
|
// -LIBPATH:... (Windows/MSVC), or
|
||||||
|
// -L... (Unix/GCC)
|
||||||
|
// with role "libraryPath"
|
||||||
|
if (f.role == "libraryPath") {
|
||||||
|
if (part.startsWith("-LIBPATH:"))
|
||||||
|
part = part.mid(9);
|
||||||
|
else if (part.startsWith("-L"))
|
||||||
|
part = part.mid(2);
|
||||||
}
|
}
|
||||||
for (const DefineInfo &di : ci.defines) {
|
|
||||||
ct.defineDefinitions.append(
|
|
||||||
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, di.backtrace, 400));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const InstallDestination &id : t.installDestination) {
|
|
||||||
ct.installDefinitions.append(
|
|
||||||
extractBacktraceInformation(t.backtraceGraph, sourceDirectory, id.backtrace, 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ct.targetType == ExecutableType) {
|
// Some projects abuse linking to libraries to pass random flags to the linker, so ignore
|
||||||
Utils::FilePaths librarySeachPaths;
|
// flags mixed into a fragment
|
||||||
// Is this a GUI application?
|
if (part.startsWith("-"))
|
||||||
ct.linksToQtGui = Utils::contains(t.link.value().fragments,
|
continue;
|
||||||
[](const FragmentInfo &f) {
|
|
||||||
return f.role == "libraries"
|
|
||||||
&& (f.fragment.contains("QtGui")
|
|
||||||
|| f.fragment.contains("Qt5Gui")
|
|
||||||
|| f.fragment.contains("Qt6Gui"));
|
|
||||||
});
|
|
||||||
|
|
||||||
ct.qtcRunnable = t.folderTargetProperty == "qtc_runnable";
|
const FilePath buildDir = relativeLibs ? buildDirectory : currentBuildDir;
|
||||||
|
FilePath tmp = buildDir.resolvePath(part);
|
||||||
|
|
||||||
// Extract library directories for executables:
|
if (f.role == "libraries")
|
||||||
for (const FragmentInfo &f : t.link.value().fragments) {
|
tmp = tmp.parentDir();
|
||||||
if (f.role == "flags") // ignore all flags fragments
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// CMake sometimes mixes several shell-escaped pieces into one fragment. Disentangle that again:
|
if (!tmp.isEmpty() && tmp.isDir()) {
|
||||||
const QStringList parts = ProcessArgs::splitArgs(f.fragment, HostOsInfo::hostOs());
|
// f.role is libraryPath or frameworkPath
|
||||||
for (QString part : parts) {
|
// On *nix, exclude sub-paths from "/lib(64)", "/usr/lib(64)" and
|
||||||
// Library search paths that are added with target_link_directories are added as
|
// "/usr/local/lib" since these are usually in the standard search
|
||||||
// -LIBPATH:... (Windows/MSVC), or
|
// paths. There probably are more, but the naming schemes are arbitrary
|
||||||
// -L... (Unix/GCC)
|
// so we'd need to ask the linker ("ld --verbose | grep SEARCH_DIR").
|
||||||
// with role "libraryPath"
|
if (buildDir.osType() == OsTypeWindows
|
||||||
if (f.role == "libraryPath") {
|
|| !isChildOf(tmp,
|
||||||
if (part.startsWith("-LIBPATH:"))
|
{"/lib",
|
||||||
part = part.mid(9);
|
"/lib64",
|
||||||
else if (part.startsWith("-L"))
|
"/usr/lib",
|
||||||
part = part.mid(2);
|
"/usr/lib64",
|
||||||
}
|
"/usr/local/lib"})) {
|
||||||
|
librarySeachPaths.append(tmp);
|
||||||
// Some projects abuse linking to libraries to pass random flags to the linker, so ignore
|
// Libraries often have their import libs in ../lib and the
|
||||||
// flags mixed into a fragment
|
// actual dll files in ../bin on windows. Qt is one example of that.
|
||||||
if (part.startsWith("-"))
|
if (tmp.fileName() == "lib" && buildDir.osType() == OsTypeWindows) {
|
||||||
continue;
|
const FilePath path = tmp.parentDir().pathAppended("bin");
|
||||||
|
if (path.isDir())
|
||||||
const FilePath buildDir = haveLibrariesRelativeToBuildDirectory ? buildDirectory : currentBuildDir;
|
librarySeachPaths.append(path);
|
||||||
FilePath tmp = buildDir.resolvePath(part);
|
|
||||||
|
|
||||||
if (f.role == "libraries")
|
|
||||||
tmp = tmp.parentDir();
|
|
||||||
|
|
||||||
if (!tmp.isEmpty() && tmp.isDir()) {
|
|
||||||
// f.role is libraryPath or frameworkPath
|
|
||||||
// On *nix, 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 (buildDir.osType() == OsTypeWindows
|
|
||||||
|| !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" && buildDir.osType() == OsTypeWindows) {
|
|
||||||
const FilePath path = tmp.parentDir().pathAppended("bin");
|
|
||||||
if (path.isDir())
|
|
||||||
librarySeachPaths.append(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ct.libraryDirectories = filteredUnique(librarySeachPaths);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ct.libraryDirectories = filteredUnique(librarySeachPaths);
|
||||||
|
}
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
return ct;
|
static QList<CMakeBuildTarget> generateBuildTargets(const QFuture<void> &cancelFuture,
|
||||||
});
|
const PreprocessedData &input,
|
||||||
|
const FilePath &sourceDirectory,
|
||||||
|
const FilePath &buildDirectory,
|
||||||
|
bool relativeLibs)
|
||||||
|
{
|
||||||
|
QList<CMakeBuildTarget> result;
|
||||||
|
result.reserve(input.targetDetails.size());
|
||||||
|
for (const TargetDetails &t : input.targetDetails) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
result.append(toBuildTarget(t, sourceDirectory, buildDirectory, relativeLibs));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,24 +356,28 @@ static QStringList splitFragments(const QStringList &fragments)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPchFile(const FilePath &buildDirectory, const FilePath &path)
|
static bool isPchFile(const FilePath &buildDirectory, const FilePath &path)
|
||||||
{
|
{
|
||||||
return path.isChildOf(buildDirectory) && path.fileName().startsWith("cmake_pch");
|
return path.isChildOf(buildDirectory) && path.fileName().startsWith("cmake_pch");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUnityFile(const FilePath &buildDirectory, const FilePath &path)
|
static bool isUnityFile(const FilePath &buildDirectory, const FilePath &path)
|
||||||
{
|
{
|
||||||
return path.isChildOf(buildDirectory) && path.parentDir().fileName() == "Unity"
|
return path.isChildOf(buildDirectory) && path.parentDir().fileName() == "Unity"
|
||||||
&& path.fileName().startsWith("unity_");
|
&& path.fileName().startsWith("unity_");
|
||||||
}
|
}
|
||||||
|
|
||||||
RawProjectParts generateRawProjectParts(const PreprocessedData &input,
|
static RawProjectParts generateRawProjectParts(const QFuture<void> &cancelFuture,
|
||||||
const FilePath &sourceDirectory,
|
const PreprocessedData &input,
|
||||||
const FilePath &buildDirectory)
|
const FilePath &sourceDirectory,
|
||||||
|
const FilePath &buildDirectory)
|
||||||
{
|
{
|
||||||
RawProjectParts rpps;
|
RawProjectParts rpps;
|
||||||
|
|
||||||
for (const TargetDetails &t : input.targetDetails) {
|
for (const TargetDetails &t : input.targetDetails) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
bool needPostfix = t.compileGroups.size() > 1;
|
bool needPostfix = t.compileGroups.size() > 1;
|
||||||
int count = 1;
|
int count = 1;
|
||||||
for (const CompileInfo &ci : t.compileGroups) {
|
for (const CompileInfo &ci : t.compileGroups) {
|
||||||
@@ -520,7 +539,9 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
|
|||||||
return rpps;
|
return rpps;
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath directorySourceDir(const Configuration &c, const FilePath &sourceDir, int directoryIndex)
|
static FilePath directorySourceDir(const Configuration &c,
|
||||||
|
const FilePath &sourceDir,
|
||||||
|
int directoryIndex)
|
||||||
{
|
{
|
||||||
const size_t di = static_cast<size_t>(directoryIndex);
|
const size_t di = static_cast<size_t>(directoryIndex);
|
||||||
QTC_ASSERT(di < c.directories.size(), return {});
|
QTC_ASSERT(di < c.directories.size(), return {});
|
||||||
@@ -528,7 +549,9 @@ FilePath directorySourceDir(const Configuration &c, const FilePath &sourceDir, i
|
|||||||
return sourceDir.resolvePath(c.directories[di].sourcePath);
|
return sourceDir.resolvePath(c.directories[di].sourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath directoryBuildDir(const Configuration &c, const FilePath &buildDir, int directoryIndex)
|
static FilePath directoryBuildDir(const Configuration &c,
|
||||||
|
const FilePath &buildDir,
|
||||||
|
int directoryIndex)
|
||||||
{
|
{
|
||||||
const size_t di = static_cast<size_t>(directoryIndex);
|
const size_t di = static_cast<size_t>(directoryIndex);
|
||||||
QTC_ASSERT(di < c.directories.size(), return {});
|
QTC_ASSERT(di < c.directories.size(), return {});
|
||||||
@@ -536,11 +559,15 @@ FilePath directoryBuildDir(const Configuration &c, const FilePath &buildDir, int
|
|||||||
return buildDir.resolvePath(c.directories[di].buildPath);
|
return buildDir.resolvePath(c.directories[di].buildPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addProjects(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
|
static void addProjects(const QFuture<void> &cancelFuture,
|
||||||
const Configuration &config,
|
const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
|
||||||
const FilePath &sourceDir)
|
const Configuration &config,
|
||||||
|
const FilePath &sourceDir)
|
||||||
{
|
{
|
||||||
for (const FileApiDetails::Project &p : config.projects) {
|
for (const FileApiDetails::Project &p : config.projects) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
if (p.parent == -1)
|
if (p.parent == -1)
|
||||||
continue; // Top-level project has already been covered
|
continue; // Top-level project has already been covered
|
||||||
FilePath dir = directorySourceDir(config, sourceDir, p.directories[0]);
|
FilePath dir = directorySourceDir(config, sourceDir, p.directories[0]);
|
||||||
@@ -548,9 +575,9 @@ void addProjects(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderNode *createSourceGroupNode(const QString &sourceGroupName,
|
static FolderNode *createSourceGroupNode(const QString &sourceGroupName,
|
||||||
const FilePath &sourceDirectory,
|
const FilePath &sourceDirectory,
|
||||||
FolderNode *targetRoot)
|
FolderNode *targetRoot)
|
||||||
{
|
{
|
||||||
FolderNode *currentNode = targetRoot;
|
FolderNode *currentNode = targetRoot;
|
||||||
|
|
||||||
@@ -576,11 +603,11 @@ FolderNode *createSourceGroupNode(const QString &sourceGroupName,
|
|||||||
return currentNode;
|
return currentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addCompileGroups(ProjectNode *targetRoot,
|
static void addCompileGroups(ProjectNode *targetRoot,
|
||||||
const Utils::FilePath &topSourceDirectory,
|
const Utils::FilePath &topSourceDirectory,
|
||||||
const Utils::FilePath &sourceDirectory,
|
const Utils::FilePath &sourceDirectory,
|
||||||
const Utils::FilePath &buildDirectory,
|
const Utils::FilePath &buildDirectory,
|
||||||
const TargetDetails &td)
|
const TargetDetails &td)
|
||||||
{
|
{
|
||||||
const bool showSourceFolders = settings().showSourceSubFolders();
|
const bool showSourceFolders = settings().showSourceSubFolders();
|
||||||
const bool inSourceBuild = (sourceDirectory == buildDirectory);
|
const bool inSourceBuild = (sourceDirectory == buildDirectory);
|
||||||
@@ -683,11 +710,12 @@ static void addGeneratedFilesNode(ProjectNode *targetRoot, const FilePath &topLe
|
|||||||
addCMakeVFolder(targetRoot, buildDir, 10, Tr::tr("<Generated Files>"), std::move(nodes));
|
addCMakeVFolder(targetRoot, buildDir, 10, Tr::tr("<Generated Files>"), std::move(nodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
|
static void addTargets(const QFuture<void> &cancelFuture,
|
||||||
const Configuration &config,
|
const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
|
||||||
const std::vector<TargetDetails> &targetDetails,
|
const Configuration &config,
|
||||||
const FilePath &sourceDir,
|
const std::vector<TargetDetails> &targetDetails,
|
||||||
const FilePath &buildDir)
|
const FilePath &sourceDir,
|
||||||
|
const FilePath &buildDir)
|
||||||
{
|
{
|
||||||
QHash<QString, const TargetDetails *> targetDetailsHash;
|
QHash<QString, const TargetDetails *> targetDetailsHash;
|
||||||
for (const TargetDetails &t : targetDetails)
|
for (const TargetDetails &t : targetDetails)
|
||||||
@@ -702,6 +730,9 @@ void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cm
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const FileApiDetails::Target &t : config.targets) {
|
for (const FileApiDetails::Target &t : config.targets) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
const TargetDetails &td = getTargetDetails(t.id);
|
const TargetDetails &td = getTargetDetails(t.id);
|
||||||
|
|
||||||
const FilePath dir = directorySourceDir(config, sourceDir, t.directory);
|
const FilePath dir = directorySourceDir(config, sourceDir, t.directory);
|
||||||
@@ -717,8 +748,10 @@ void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CMakeProjectNode> generateRootProjectNode(
|
static std::unique_ptr<CMakeProjectNode> generateRootProjectNode(const QFuture<void> &cancelFuture,
|
||||||
PreprocessedData &data, const FilePath &sourceDirectory, const FilePath &buildDirectory)
|
PreprocessedData &data,
|
||||||
|
const FilePath &sourceDirectory,
|
||||||
|
const FilePath &buildDirectory)
|
||||||
{
|
{
|
||||||
std::unique_ptr<CMakeProjectNode> result = std::make_unique<CMakeProjectNode>(sourceDirectory);
|
std::unique_ptr<CMakeProjectNode> result = std::make_unique<CMakeProjectNode>(sourceDirectory);
|
||||||
|
|
||||||
@@ -733,25 +766,34 @@ std::unique_ptr<CMakeProjectNode> generateRootProjectNode(
|
|||||||
std::move(data.cmakeListNodes));
|
std::move(data.cmakeListNodes));
|
||||||
data.cmakeListNodes.clear(); // Remove all the nullptr in the vector...
|
data.cmakeListNodes.clear(); // Remove all the nullptr in the vector...
|
||||||
|
|
||||||
addProjects(cmakeListsNodes, data.codemodel, sourceDirectory);
|
addProjects(cancelFuture, cmakeListsNodes, data.codemodel, sourceDirectory);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
addTargets(cmakeListsNodes,
|
addTargets(cancelFuture,
|
||||||
|
cmakeListsNodes,
|
||||||
data.codemodel,
|
data.codemodel,
|
||||||
data.targetDetails,
|
data.targetDetails,
|
||||||
sourceDirectory,
|
sourceDirectory,
|
||||||
buildDirectory);
|
buildDirectory);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
if (!data.cmakeNodesSource.empty() || !data.cmakeNodesBuild.empty()
|
if (!data.cmakeNodesSource.empty() || !data.cmakeNodesBuild.empty()
|
||||||
|| !data.cmakeNodesOther.empty())
|
|| !data.cmakeNodesOther.empty()) {
|
||||||
addCMakeInputs(result.get(),
|
addCMakeInputs(result.get(),
|
||||||
sourceDirectory,
|
sourceDirectory,
|
||||||
buildDirectory,
|
buildDirectory,
|
||||||
std::move(data.cmakeNodesSource),
|
std::move(data.cmakeNodesSource),
|
||||||
std::move(data.cmakeNodesBuild),
|
std::move(data.cmakeNodesBuild),
|
||||||
std::move(data.cmakeNodesOther));
|
std::move(data.cmakeNodesOther));
|
||||||
|
}
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
addCMakePresets(result.get(), sourceDirectory);
|
addCMakePresets(result.get(), sourceDirectory);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
data.cmakeNodesSource.clear(); // Remove all the nullptr in the vector...
|
data.cmakeNodesSource.clear(); // Remove all the nullptr in the vector...
|
||||||
data.cmakeNodesBuild.clear(); // Remove all the nullptr in the vector...
|
data.cmakeNodesBuild.clear(); // Remove all the nullptr in the vector...
|
||||||
@@ -760,7 +802,9 @@ std::unique_ptr<CMakeProjectNode> generateRootProjectNode(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupLocationInfoForTargets(CMakeProjectNode *rootNode, const QList<CMakeBuildTarget> &targets)
|
static void setupLocationInfoForTargets(const QFuture<void> &cancelFuture,
|
||||||
|
CMakeProjectNode *rootNode,
|
||||||
|
const QList<CMakeBuildTarget> &targets)
|
||||||
{
|
{
|
||||||
const QSet<QString> titles = Utils::transform<QSet>(targets, &CMakeBuildTarget::title);
|
const QSet<QString> titles = Utils::transform<QSet>(targets, &CMakeBuildTarget::title);
|
||||||
QHash<QString, FolderNode *> buildKeyToNode;
|
QHash<QString, FolderNode *> buildKeyToNode;
|
||||||
@@ -771,6 +815,9 @@ void setupLocationInfoForTargets(CMakeProjectNode *rootNode, const QList<CMakeBu
|
|||||||
buildKeyToNode.insert(buildKey, folderNode);
|
buildKeyToNode.insert(buildKey, folderNode);
|
||||||
});
|
});
|
||||||
for (const CMakeBuildTarget &t : targets) {
|
for (const CMakeBuildTarget &t : targets) {
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
FolderNode *folderNode = buildKeyToNode.value(t.title);
|
FolderNode *folderNode = buildKeyToNode.value(t.title);
|
||||||
if (folderNode) {
|
if (folderNode) {
|
||||||
QSet<std::pair<FilePath, int>> locations;
|
QSet<std::pair<FilePath, int>> locations;
|
||||||
@@ -811,33 +858,43 @@ using namespace FileApiDetails;
|
|||||||
// extractData:
|
// extractData:
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
FileApiQtcData extractData(FileApiData &input,
|
FileApiQtcData extractData(const QFuture<void> &cancelFuture, FileApiData &input,
|
||||||
const FilePath &sourceDirectory,
|
const Utils::FilePath &sourceDir, const Utils::FilePath &buildDir)
|
||||||
const FilePath &buildDirectory)
|
|
||||||
{
|
{
|
||||||
FileApiQtcData result;
|
FileApiQtcData result;
|
||||||
|
|
||||||
// Preprocess our input:
|
// Preprocess our input:
|
||||||
PreprocessedData data = preprocess(input, sourceDirectory, buildDirectory, result.errorMessage);
|
PreprocessedData data = preprocess(cancelFuture, input, sourceDir, buildDir);
|
||||||
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
if (cancelFuture.isCanceled())
|
||||||
if (!result.errorMessage.isEmpty()) {
|
return {};
|
||||||
|
|
||||||
|
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
||||||
|
if (!result.errorMessage.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
// Ninja generator from CMake version 3.20.5 has libraries relative to build directory
|
// Ninja generator from CMake version 3.20.5 has libraries relative to build directory
|
||||||
const bool haveLibrariesRelativeToBuildDirectory =
|
const bool haveLibrariesRelativeToBuildDirectory =
|
||||||
input.replyFile.generator.startsWith("Ninja")
|
input.replyFile.generator.startsWith("Ninja")
|
||||||
&& input.replyFile.cmakeVersion >= QVersionNumber(3, 20, 5);
|
&& input.replyFile.cmakeVersion >= QVersionNumber(3, 20, 5);
|
||||||
|
|
||||||
result.buildTargets = generateBuildTargets(data, sourceDirectory, buildDirectory, haveLibrariesRelativeToBuildDirectory);
|
result.buildTargets = generateBuildTargets(cancelFuture, data, sourceDir, buildDir,
|
||||||
|
haveLibrariesRelativeToBuildDirectory);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
result.cmakeFiles = std::move(data.cmakeFiles);
|
result.cmakeFiles = std::move(data.cmakeFiles);
|
||||||
result.projectParts = generateRawProjectParts(data, sourceDirectory, buildDirectory);
|
result.projectParts = generateRawProjectParts(cancelFuture, data, sourceDir, buildDir);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
auto rootProjectNode = generateRootProjectNode(data, sourceDirectory, buildDirectory);
|
auto rootProjectNode = generateRootProjectNode(cancelFuture, data, sourceDir, buildDir);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
ProjectTree::applyTreeManager(rootProjectNode.get(), ProjectTree::AsyncPhase); // QRC nodes
|
ProjectTree::applyTreeManager(rootProjectNode.get(), ProjectTree::AsyncPhase); // QRC nodes
|
||||||
result.rootProjectNode = std::move(rootProjectNode);
|
result.rootProjectNode = std::move(rootProjectNode);
|
||||||
|
|
||||||
setupLocationInfoForTargets(result.rootProjectNode.get(), result.buildTargets);
|
setupLocationInfoForTargets(cancelFuture, result.rootProjectNode.get(), result.buildTargets);
|
||||||
|
if (cancelFuture.isCanceled())
|
||||||
|
return {};
|
||||||
|
|
||||||
result.ctestPath = input.replyFile.ctestExecutable;
|
result.ctestPath = input.replyFile.ctestExecutable;
|
||||||
result.isMultiConfig = input.replyFile.isMultiConfig;
|
result.isMultiConfig = input.replyFile.isMultiConfig;
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ public:
|
|||||||
bool usesAllCapsTargets = false;
|
bool usesAllCapsTargets = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
FileApiQtcData extractData(FileApiData &data,
|
FileApiQtcData extractData(const QFuture<void> &cancelFuture, FileApiData &input,
|
||||||
const Utils::FilePath &sourceDirectory,
|
const Utils::FilePath &sourceDir, const Utils::FilePath &buildDir);
|
||||||
const Utils::FilePath &buildDirectory);
|
|
||||||
|
|
||||||
} // CMakeProjectManager::Internal
|
} // CMakeProjectManager::Internal
|
||||||
|
|||||||
@@ -252,7 +252,8 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac
|
|||||||
|
|
||||||
const FilePath sourceDirectory = m_parameters.sourceDirectory;
|
const FilePath sourceDirectory = m_parameters.sourceDirectory;
|
||||||
const FilePath buildDirectory = m_parameters.buildDirectory;
|
const FilePath buildDirectory = m_parameters.buildDirectory;
|
||||||
const QString cmakeBuildType = m_parameters.cmakeBuildType == "Build" ? "" : m_parameters.cmakeBuildType;
|
const QString cmakeBuildType = m_parameters.cmakeBuildType == "Build"
|
||||||
|
? "" : m_parameters.cmakeBuildType;
|
||||||
|
|
||||||
m_lastReplyTimestamp = replyFilePath.lastModified();
|
m_lastReplyTimestamp = replyFilePath.lastModified();
|
||||||
|
|
||||||
@@ -264,10 +265,12 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac
|
|||||||
replyFilePath,
|
replyFilePath,
|
||||||
cmakeBuildType,
|
cmakeBuildType,
|
||||||
result->errorMessage);
|
result->errorMessage);
|
||||||
if (result->errorMessage.isEmpty())
|
if (result->errorMessage.isEmpty()) {
|
||||||
*result = extractData(data, sourceDirectory, buildDirectory);
|
*result = extractData(QFuture<void>(promise.future()), data,
|
||||||
else
|
sourceDirectory, buildDirectory);
|
||||||
|
} else {
|
||||||
qWarning() << result->errorMessage;
|
qWarning() << result->errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
promise.addResult(result);
|
promise.addResult(result);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user