forked from qt-creator/qt-creator
CMakePM: Implement BuildSystem::addDependencies
This can be triggered via C++ QuickFix or the new C++ class wizard. Change-Id: I93439fb823a2e5c359a3f6b310c1cd642201d1a1 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -50,3 +50,11 @@ add_qtc_plugin(CMakeProjectManager
|
|||||||
3rdparty/cmake/cmListFileCache.h
|
3rdparty/cmake/cmListFileCache.h
|
||||||
3rdparty/rstparser/rstparser.cc 3rdparty/rstparser/rstparser.h
|
3rdparty/rstparser/rstparser.cc 3rdparty/rstparser/rstparser.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE test_cases RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} testcases/*)
|
||||||
|
qtc_add_resources(CMakeProjectManager "testcases"
|
||||||
|
CONDITION WITH_TESTS
|
||||||
|
PREFIX "/cmakeprojectmanager"
|
||||||
|
BASE "."
|
||||||
|
FILES ${test_cases}
|
||||||
|
)
|
||||||
|
@@ -62,6 +62,11 @@
|
|||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
#include <cppeditor/cpptoolstestcase.h>
|
||||||
|
#include <QTest>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
@@ -1077,6 +1082,178 @@ void CMakeBuildSystem::buildNamedTarget(const QString &target)
|
|||||||
CMakeProjectManager::Internal::buildTarget(this, target);
|
CMakeProjectManager::Internal::buildTarget(this, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result<bool> insertDependencies(
|
||||||
|
const QString &targetName,
|
||||||
|
const FilePath &targetCMakeFile,
|
||||||
|
int targetDefinitionLine,
|
||||||
|
const QStringList &dependencies,
|
||||||
|
int qtMajorVersion)
|
||||||
|
{
|
||||||
|
std::optional<cmListFile> cmakeListFile = getUncachedCMakeListFile(targetCMakeFile);
|
||||||
|
if (!cmakeListFile)
|
||||||
|
return ResultError("Failed to read " + targetCMakeFile.toUserOutput());
|
||||||
|
|
||||||
|
std::optional<cmListFileFunction> function
|
||||||
|
= findFunction(*cmakeListFile, [targetDefinitionLine](const auto &func) {
|
||||||
|
return func.Line() == targetDefinitionLine;
|
||||||
|
});
|
||||||
|
if (!function.has_value())
|
||||||
|
return ResultError(QString("Failed to locate the target defining function at %1").arg(targetDefinitionLine));
|
||||||
|
const int targetDefinitionLastLine = function->LineEnd();
|
||||||
|
|
||||||
|
//
|
||||||
|
// find_package
|
||||||
|
//
|
||||||
|
const QString qtPackage = QString("Qt%1").arg(qtMajorVersion);
|
||||||
|
function = findFunction(
|
||||||
|
*cmakeListFile,
|
||||||
|
[qtPackage](const auto &func) {
|
||||||
|
return func.LowerCaseName() == "find_package" && func.Arguments().size() > 0
|
||||||
|
&& func.Arguments()[0].Value == qtPackage;
|
||||||
|
},
|
||||||
|
/* reverse = */ true);
|
||||||
|
|
||||||
|
const QString findComponents = transform(dependencies, [](const QString &dep) {
|
||||||
|
QTC_ASSERT(dep.size() > 3, return dep);
|
||||||
|
return dep.mid(3);
|
||||||
|
}).join(" ");
|
||||||
|
QString snippet = QString("find_package(%1 REQUIRED COMPONENTS %2)\n%3")
|
||||||
|
.arg(qtPackage)
|
||||||
|
.arg(findComponents)
|
||||||
|
.arg(!function ? QString("\n") : QString(""));
|
||||||
|
|
||||||
|
int insertionLine = function ? function->LineEnd() + 1 : targetDefinitionLine;
|
||||||
|
Result<bool> inserted = insertSnippetSilently(targetCMakeFile, {snippet, insertionLine, 0});
|
||||||
|
if (!inserted)
|
||||||
|
return inserted;
|
||||||
|
const int insertedFindPackageOffset = 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// target_link_libraries
|
||||||
|
//
|
||||||
|
cmakeListFile = getUncachedCMakeListFile(targetCMakeFile);
|
||||||
|
|
||||||
|
function = findFunction(
|
||||||
|
*cmakeListFile,
|
||||||
|
[targetName](const auto &func) {
|
||||||
|
return func.LowerCaseName() == "target_link_libraries" && func.Arguments().size() > 0
|
||||||
|
&& func.Arguments()[0].Value == targetName;
|
||||||
|
},
|
||||||
|
/* reverse = */ true);
|
||||||
|
|
||||||
|
const QString targetPrefix = QString("Qt%1::").arg(qtMajorVersion);
|
||||||
|
const QString linkLibraries
|
||||||
|
= transform(dependencies, [targetPrefix](const QString &dep) -> QString {
|
||||||
|
QTC_ASSERT(dep.size() > 3, return targetPrefix + dep);
|
||||||
|
return targetPrefix + dep.mid(3);
|
||||||
|
}).join(" ");
|
||||||
|
snippet = QString("%1target_link_libraries(%2 PRIVATE %3)\n")
|
||||||
|
.arg(!function ? QString("\n") : QString(""))
|
||||||
|
.arg(targetName)
|
||||||
|
.arg(linkLibraries);
|
||||||
|
|
||||||
|
insertionLine = (function ? function->LineEnd()
|
||||||
|
: targetDefinitionLastLine + insertedFindPackageOffset)
|
||||||
|
+ 1;
|
||||||
|
return insertSnippetSilently(targetCMakeFile, {snippet, insertionLine, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CMakeBuildSystem::addDependencies(
|
||||||
|
ProjectExplorer::Node *context, const QStringList &dependencies)
|
||||||
|
{
|
||||||
|
if (auto n = dynamic_cast<CMakeTargetNode *>(context)) {
|
||||||
|
const QString targetName = n->buildKey();
|
||||||
|
const std::optional<Link> cmakeFile = cmakeFileForBuildKey(targetName, buildTargets());
|
||||||
|
if (!cmakeFile)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int qtMajorVersion = 6;
|
||||||
|
if (auto qt = m_findPackagesFilesHash.value("Qt5Core"); qt.hasValidTarget())
|
||||||
|
qtMajorVersion = 5;
|
||||||
|
|
||||||
|
Result<bool> inserted = insertDependencies(
|
||||||
|
targetName,
|
||||||
|
cmakeFile->targetFilePath,
|
||||||
|
cmakeFile->targetLine,
|
||||||
|
dependencies,
|
||||||
|
qtMajorVersion);
|
||||||
|
if (!inserted) {
|
||||||
|
qCCritical(cmakeBuildSystemLog) << inserted.error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return BuildSystem::addDependencies(context, dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
class AddDependenciesTest final : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
const auto projectDir = std::make_unique<CppEditor::Tests::TemporaryCopiedDir>(
|
||||||
|
":/cmakeprojectmanager/testcases/adddependencies");
|
||||||
|
|
||||||
|
QVERIFY(insertDependencies(
|
||||||
|
"HelloQt",
|
||||||
|
projectDir->filePath().pathAppended("existing_qt5.cmake"),
|
||||||
|
18,
|
||||||
|
{"Qt.Concurrent"},
|
||||||
|
5));
|
||||||
|
QVERIFY(insertDependencies(
|
||||||
|
"HelloQt",
|
||||||
|
projectDir->filePath().pathAppended("existing_qt6.cmake"),
|
||||||
|
8,
|
||||||
|
{"Qt.Concurrent"},
|
||||||
|
6));
|
||||||
|
QVERIFY(insertDependencies(
|
||||||
|
"HelloCpp",
|
||||||
|
projectDir->filePath().pathAppended("no_qt6.cmake"),
|
||||||
|
8,
|
||||||
|
{"Qt.Concurrent"},
|
||||||
|
6));
|
||||||
|
|
||||||
|
// Compare files.
|
||||||
|
static const QString suffix = "_expected.cmake";
|
||||||
|
const FileFilter filter({"*" + suffix}, QDir::Files);
|
||||||
|
const FilePaths expectedDocuments = projectDir->filePath().dirEntries(filter);
|
||||||
|
QVERIFY(!expectedDocuments.isEmpty());
|
||||||
|
for (const FilePath &expected : expectedDocuments) {
|
||||||
|
const FilePath actual = expected.parentDir().pathAppended(
|
||||||
|
expected.fileName().chopped(suffix.length()) + ".cmake");
|
||||||
|
QVERIFY(actual.exists());
|
||||||
|
const auto actualContents = actual.fileContents();
|
||||||
|
QVERIFY(actualContents);
|
||||||
|
const auto expectedContents = expected.fileContents();
|
||||||
|
const QByteArrayList actualLines = actualContents->split('\n');
|
||||||
|
const QByteArrayList expectedLines = expectedContents->split('\n');
|
||||||
|
if (actualLines.size() != expectedLines.size()) {
|
||||||
|
qDebug().noquote().nospace() << "---\n" << *expectedContents << "EOF";
|
||||||
|
qDebug().noquote().nospace() << "+++\n" << *actualContents << "EOF";
|
||||||
|
}
|
||||||
|
QCOMPARE(actualLines.size(), expectedLines.size());
|
||||||
|
for (int i = 0; i < actualLines.size(); ++i) {
|
||||||
|
const QByteArray actualLine = actualLines.at(i);
|
||||||
|
const QByteArray expectedLine = expectedLines.at(i);
|
||||||
|
if (actualLine != expectedLine)
|
||||||
|
qDebug() << "Unexpected content in line" << (i + 1) << "of file"
|
||||||
|
<< actual.fileName();
|
||||||
|
QCOMPARE(actualLine, expectedLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QObject *createAddDependenciesTest()
|
||||||
|
{
|
||||||
|
return new AddDependenciesTest;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
FilePaths CMakeBuildSystem::filesGeneratedFrom(const FilePath &sourceFile) const
|
FilePaths CMakeBuildSystem::filesGeneratedFrom(const FilePath &sourceFile) const
|
||||||
{
|
{
|
||||||
FilePath project = projectDirectory();
|
FilePath project = projectDirectory();
|
||||||
@@ -2608,3 +2785,7 @@ ExtraCompiler *CMakeBuildSystem::findExtraCompiler(const ExtraCompilerFilter &fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // CMakeProjectManager::Internal
|
} // CMakeProjectManager::Internal
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
#include <cmakebuildsystem.moc>
|
||||||
|
#endif
|
||||||
|
@@ -68,6 +68,8 @@ public:
|
|||||||
|
|
||||||
Utils::FilePaths filesGeneratedFrom(const Utils::FilePath &sourceFile) const final;
|
Utils::FilePaths filesGeneratedFrom(const Utils::FilePath &sourceFile) const final;
|
||||||
|
|
||||||
|
bool addDependencies(ProjectExplorer::Node *context, const QStringList &dependencies) final;
|
||||||
|
|
||||||
// Actions:
|
// Actions:
|
||||||
void runCMake();
|
void runCMake();
|
||||||
void runCMakeAndScanProjectTree();
|
void runCMakeAndScanProjectTree();
|
||||||
@@ -269,5 +271,9 @@ private:
|
|||||||
QString m_warning;
|
QString m_warning;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
QObject *createAddDependenciesTest();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace CMakeProjectManager
|
} // namespace CMakeProjectManager
|
||||||
|
@@ -108,4 +108,10 @@ QtcPlugin {
|
|||||||
"rstparser/rstparser.h"
|
"rstparser/rstparser.h"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtcTestFiles {
|
||||||
|
name: "test data"
|
||||||
|
files: "testcases/**/*"
|
||||||
|
fileTags: qtc.withPluginTests ? ["qt.core.resource_data"] : []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,6 +80,7 @@ class CMakeProjectPlugin final : public ExtensionSystem::IPlugin
|
|||||||
addTestCreator(createCMakeOutputParserTest);
|
addTestCreator(createCMakeOutputParserTest);
|
||||||
addTestCreator(createCMakeAutogenParserTest);
|
addTestCreator(createCMakeAutogenParserTest);
|
||||||
addTestCreator(createCMakeProjectImporterTest);
|
addTestCreator(createCMakeProjectImporterTest);
|
||||||
|
addTestCreator(createAddDependenciesTest);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FileIconProvider::registerIconOverlayForSuffix(Constants::Icons::FILE_OVERLAY, "cmake");
|
FileIconProvider::registerIconOverlayForSuffix(Constants::Icons::FILE_OVERLAY, "cmake");
|
||||||
|
@@ -0,0 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
|
|
||||||
|
project(HelloQt VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.7.0")
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||||
|
|
||||||
|
add_executable(HelloQt
|
||||||
|
mainwindow.ui
|
||||||
|
mainwindow.cpp
|
||||||
|
main.cpp
|
||||||
|
resources.qrc
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(HelloQt Qt5::Widgets)
|
@@ -0,0 +1,27 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
|
|
||||||
|
project(HelloQt VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.7.0")
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS Concurrent)
|
||||||
|
|
||||||
|
add_executable(HelloQt
|
||||||
|
mainwindow.ui
|
||||||
|
mainwindow.cpp
|
||||||
|
main.cpp
|
||||||
|
resources.qrc
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(HelloQt Qt5::Widgets)
|
||||||
|
target_link_libraries(HelloQt PRIVATE Qt5::Concurrent)
|
@@ -0,0 +1,35 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
project(HelloQt LANGUAGES CXX)
|
||||||
|
|
||||||
|
find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets)
|
||||||
|
|
||||||
|
qt_standard_project_setup()
|
||||||
|
|
||||||
|
qt_add_executable(HelloQt
|
||||||
|
WIN32 MACOSX_BUNDLE
|
||||||
|
main.cpp
|
||||||
|
mainwindow.cpp
|
||||||
|
mainwindow.h
|
||||||
|
mainwindow.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(HelloQt
|
||||||
|
PRIVATE
|
||||||
|
Qt::Core
|
||||||
|
Qt::Widgets
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
install(TARGETS HelloQt
|
||||||
|
BUNDLE DESTINATION .
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_generate_deploy_app_script(
|
||||||
|
TARGET HelloQt
|
||||||
|
OUTPUT_SCRIPT deploy_script
|
||||||
|
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||||
|
)
|
||||||
|
install(SCRIPT ${deploy_script})
|
@@ -0,0 +1,37 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
project(HelloQt LANGUAGES CXX)
|
||||||
|
|
||||||
|
find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets)
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Concurrent)
|
||||||
|
|
||||||
|
qt_standard_project_setup()
|
||||||
|
|
||||||
|
qt_add_executable(HelloQt
|
||||||
|
WIN32 MACOSX_BUNDLE
|
||||||
|
main.cpp
|
||||||
|
mainwindow.cpp
|
||||||
|
mainwindow.h
|
||||||
|
mainwindow.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(HelloQt
|
||||||
|
PRIVATE
|
||||||
|
Qt::Core
|
||||||
|
Qt::Widgets
|
||||||
|
)
|
||||||
|
target_link_libraries(HelloQt PRIVATE Qt6::Concurrent)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
install(TARGETS HelloQt
|
||||||
|
BUNDLE DESTINATION .
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_generate_deploy_app_script(
|
||||||
|
TARGET HelloQt
|
||||||
|
OUTPUT_SCRIPT deploy_script
|
||||||
|
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||||
|
)
|
||||||
|
install(SCRIPT ${deploy_script})
|
@@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(HelloCpp LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
add_executable(HelloCpp main.cpp)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS HelloCpp
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
@@ -0,0 +1,18 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(HelloCpp LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Concurrent)
|
||||||
|
|
||||||
|
add_executable(HelloCpp main.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(HelloCpp PRIVATE Qt6::Concurrent)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS HelloCpp
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
Reference in New Issue
Block a user