summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Boeckel <ben.boeckel@kitware.com>2023-09-28 17:30:43 (GMT)
committerBen Boeckel <ben.boeckel@kitware.com>2024-08-27 16:37:36 (GMT)
commit84bc710d84c912a8d5dc1a972ed9c021adda4c55 (patch)
treea1bcbbd2eea23906f2000a1f15288f36bdd316f1
parent670f753f24fccaffee15c078e319ef2d85116ee3 (diff)
downloadCMake-84bc710d84c912a8d5dc1a972ed9c021adda4c55.zip
CMake-84bc710d84c912a8d5dc1a972ed9c021adda4c55.tar.gz
CMake-84bc710d84c912a8d5dc1a972ed9c021adda4c55.tar.bz2
cmGlobalGenerator: generate build database files for targets
-rw-r--r--Source/cmGeneratorTarget.cxx14
-rw-r--r--Source/cmGlobalGenerator.cxx216
-rw-r--r--Source/cmGlobalGenerator.h12
-rw-r--r--Source/cmGlobalNinjaGenerator.h1
-rw-r--r--Source/cmNinjaTargetGenerator.cxx16
5 files changed, 259 insertions, 0 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index ced18fd..fcf790f 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -139,6 +139,20 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
} else {
this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
}
+
+ auto configs =
+ this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+ std::string build_db_languages[] = { "CXX" };
+ for (auto const& language : build_db_languages) {
+ for (auto const& config : configs) {
+ auto bdb_path = this->BuildDatabasePath(language, config);
+ if (!bdb_path.empty()) {
+ this->Makefile->GetOrCreateGeneratedSource(bdb_path);
+ this->GetGlobalGenerator()->AddBuildDatabaseFile(language, config,
+ bdb_path);
+ }
+ }
+ }
}
cmGeneratorTarget::~cmGeneratorTarget() = default;
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index aeebc6f..a38208c 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -32,6 +32,7 @@
#include "cmCryptoHash.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
+#include "cmCustomCommandTypes.h"
#include "cmDuration.h"
#include "cmExportBuildFileGenerator.h"
#include "cmExternalMakefileProjectGenerator.h"
@@ -68,6 +69,8 @@
# include "cmQtAutoGenGlobalInitializer.h"
#endif
+class cmListFileBacktrace;
+
const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
"CMAKE_PLATFORM_INFO_INITIALIZED";
@@ -1569,6 +1572,10 @@ bool cmGlobalGenerator::Compute()
}
this->FinalizeTargetConfiguration();
+ if (!this->AddBuildDatabaseTargets()) {
+ return false;
+ }
+
this->CreateGenerationObjects();
// at this point this->LocalGenerators has been filled,
@@ -2834,6 +2841,20 @@ bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
reason);
}
+bool cmGlobalGenerator::CheckCMP0037Prefix(std::string const& targetPrefix,
+ std::string const& reason) const
+{
+ bool ret = true;
+ for (auto const& tgtPair : this->TargetSearchIndex) {
+ if (cmHasPrefix(tgtPair.first, targetPrefix) &&
+ !RaiseCMP0037Message(this->GetCMakeInstance(), tgtPair.second,
+ tgtPair.first, reason)) {
+ ret = false;
+ }
+ }
+ return ret;
+}
+
void cmGlobalGenerator::CreateDefaultGlobalTargets(
std::vector<GlobalTargetInfo>& targets)
{
@@ -3186,6 +3207,201 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
}
}
+class ModuleCompilationDatabaseCommandAction
+{
+public:
+ ModuleCompilationDatabaseCommandAction(
+ std::string output, std::function<std::vector<std::string>()> inputs)
+ : Output(std::move(output))
+ , Inputs(std::move(inputs))
+ {
+ }
+ void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ std::unique_ptr<cmCustomCommand> cc);
+
+private:
+ std::string const Output;
+ std::function<std::vector<std::string>()> const Inputs;
+};
+
+void ModuleCompilationDatabaseCommandAction::operator()(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ std::unique_ptr<cmCustomCommand> cc)
+{
+ auto inputs = this->Inputs();
+
+ cmCustomCommandLines command_lines;
+ cmCustomCommandLine command_line;
+ {
+ command_line.emplace_back(cmSystemTools::GetCMakeCommand());
+ command_line.emplace_back("-E");
+ command_line.emplace_back("cmake_module_compile_db");
+ command_line.emplace_back("merge");
+ command_line.emplace_back("-o");
+ command_line.emplace_back(this->Output);
+ for (auto const& input : inputs) {
+ command_line.emplace_back(input);
+ }
+ }
+ command_lines.emplace_back(std::move(command_line));
+
+ cc->SetBacktrace(lfbt);
+ cc->SetCommandLines(command_lines);
+ cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
+ cc->SetDependsExplicitOnly(true);
+ cc->SetOutputs(this->Output);
+ if (!inputs.empty()) {
+ cc->SetMainDependency(inputs[0]);
+ }
+ cc->SetDepends(inputs);
+ detail::AddCustomCommandToOutput(lg, cmCommandOrigin::Generator,
+ std::move(cc), false);
+}
+
+class ModuleCompilationDatabaseTargetAction
+{
+public:
+ ModuleCompilationDatabaseTargetAction(std::string output, cmTarget* target)
+ : Output(std::move(output))
+ , Target(target)
+ {
+ }
+ void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ std::unique_ptr<cmCustomCommand> cc);
+
+private:
+ std::string const Output;
+ cmTarget* const Target;
+};
+
+void ModuleCompilationDatabaseTargetAction::operator()(
+ cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
+ std::unique_ptr<cmCustomCommand> cc)
+{
+ cc->SetBacktrace(lfbt);
+ cc->SetWorkingDirectory(lg.GetBinaryDirectory().c_str());
+ std::vector<std::string> target_inputs;
+ target_inputs.emplace_back(this->Output);
+ cc->SetDepends(target_inputs);
+ detail::AddUtilityCommand(lg, cmCommandOrigin::Generator, this->Target,
+ std::move(cc));
+}
+
+void cmGlobalGenerator::AddBuildDatabaseFile(std::string const& lang,
+ std::string const& config,
+ std::string const& path)
+{
+ if (!config.empty()) {
+ this->PerConfigModuleDbs[config][lang].push_back(path);
+ }
+ this->PerLanguageModuleDbs[lang].push_back(path);
+}
+
+bool cmGlobalGenerator::AddBuildDatabaseTargets()
+{
+ auto& mf = this->Makefiles[0];
+ if (!mf->IsOn("CMAKE_EXPORT_BUILD_DATABASE")) {
+ return true;
+ }
+
+ static const auto reservedTargets = { "cmake_build_database" };
+ for (auto const& target : reservedTargets) {
+ if (!this->CheckCMP0037(target,
+ "when exporting build databases are enabled")) {
+ return false;
+ }
+ }
+ static const auto reservedPrefixes = { "cmake_build_database-" };
+ for (auto const& prefix : reservedPrefixes) {
+ if (!this->CheckCMP0037Prefix(
+ prefix, "when exporting build databases are enabled")) {
+ return false;
+ }
+ }
+
+ if (!this->SupportsBuildDatabase()) {
+ return true;
+ }
+
+ auto configs = mf->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
+ static cm::static_string_view TargetPrefix = "cmake_build_database"_s;
+ auto AddMergeTarget =
+ [&mf](std::string const& name, const char* comment,
+ std::string const& output,
+ std::function<std::vector<std::string>()> inputs) {
+ // Add the custom command.
+ {
+ ModuleCompilationDatabaseCommandAction action{ output,
+ std::move(inputs) };
+ auto cc = cm::make_unique<cmCustomCommand>();
+ cc->SetComment(comment);
+ mf->AddGeneratorAction(
+ std::move(cc), action,
+ cmMakefile::GeneratorActionWhen::AfterGeneratorTargets);
+ }
+
+ // Add a custom target with the given name.
+ {
+ cmTarget* target = mf->AddNewUtilityTarget(name, true);
+ ModuleCompilationDatabaseTargetAction action{ output, target };
+ auto cc = cm::make_unique<cmCustomCommand>();
+ mf->AddGeneratorAction(std::move(cc), action);
+ }
+ };
+
+ std::string module_languages[] = { "CXX" };
+
+ // Add per-configuration targets.
+ for (auto const& config : configs) {
+ // Add per-language targets.
+ std::vector<std::string> all_config_paths;
+ for (auto const& lang : module_languages) {
+ auto comment = cmStrCat("Combining module command databases for ", lang,
+ " and ", config);
+ auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
+ lang, '_', config, ".json");
+ mf->GetOrCreateGeneratedSource(output);
+ AddMergeTarget(cmStrCat(TargetPrefix, '-', lang, '-', config),
+ comment.c_str(), output, [this, config, lang]() {
+ return this->PerConfigModuleDbs[config][lang];
+ });
+ all_config_paths.emplace_back(std::move(output));
+ }
+
+ // Add the overall target.
+ auto comment = cmStrCat("Combining module command databases for ", config);
+ auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
+ config, ".json");
+ mf->GetOrCreateGeneratedSource(output);
+ AddMergeTarget(cmStrCat(TargetPrefix, '-', config), comment.c_str(),
+ output, [all_config_paths]() { return all_config_paths; });
+ }
+
+ // NMC considerations
+ // Add per-language targets.
+ std::vector<std::string> all_config_paths;
+ for (auto const& lang : module_languages) {
+ auto comment = cmStrCat("Combining module command databases for ", lang);
+ auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database_",
+ lang, ".json");
+ mf->GetOrCreateGeneratedSource(output);
+ AddMergeTarget(
+ cmStrCat(TargetPrefix, '-', lang), comment.c_str(), output,
+ [this, lang]() { return this->PerLanguageModuleDbs[lang]; });
+ all_config_paths.emplace_back(std::move(output));
+ }
+
+ // Add the overall target.
+ auto const* comment = "Combining all module command databases";
+ auto output = cmStrCat(mf->GetHomeOutputDirectory(), "/build_database.json");
+ mf->GetOrCreateGeneratedSource(output);
+ AddMergeTarget(std::string(TargetPrefix), comment, output,
+ [all_config_paths]() { return all_config_paths; });
+
+ return true;
+}
+
std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
{
cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 355cb80..a865adb 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -172,6 +172,9 @@ public:
}
virtual bool SupportsBuildDatabase() const { return false; }
+ bool AddBuildDatabaseTargets();
+ void AddBuildDatabaseFile(std::string const& lang, std::string const& config,
+ std::string const& path);
virtual bool IsGNUMakeJobServerAware() const { return false; }
@@ -873,6 +876,8 @@ private:
bool CheckCMP0037(std::string const& targetName,
std::string const& reason) const;
+ bool CheckCMP0037Prefix(std::string const& targetPrefix,
+ std::string const& reason) const;
void IndexMakefile(cmMakefile* mf);
void IndexLocalGenerator(cmLocalGenerator* lg);
@@ -918,6 +923,13 @@ private:
cmFileLockPool FileLockPool;
#endif
+ using PerLanguageModuleDatabases =
+ std::map<std::string, std::vector<std::string>>;
+ using PerConfigModuleDatabases =
+ std::map<std::string, PerLanguageModuleDatabases>;
+ PerConfigModuleDatabases PerConfigModuleDbs;
+ PerLanguageModuleDatabases PerLanguageModuleDbs;
+
protected:
float FirstTimeProgress;
bool NeedSymbolicMark;
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 1cdcfb7..69b2361 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -483,6 +483,7 @@ public:
bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
bool CheckCxxModuleSupport(CxxModuleSupportQuery query) override;
+ bool SupportsBuildDatabase() const override { return true; }
std::string ConvertToOutputPath(std::string path) const override;
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index a10635a..90c395b 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -22,6 +22,7 @@
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
+#include "cmBuildDatabase.h"
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include "cmDyndepCollation.h"
@@ -1232,6 +1233,21 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
language, "Modules.json"));
build.ImplicitDeps.emplace_back(
this->GetTargetDependInfoPath(language, config));
+ {
+ auto bdb_path =
+ this->GeneratorTarget->BuildDatabasePath(language, config);
+ if (!bdb_path.empty()) {
+ build.ImplicitOuts.emplace_back(this->ConvertToNinjaPath(bdb_path));
+ }
+ }
+ auto bdb_path = this->GeneratorTarget->BuildDatabasePath(language, config);
+ if (!bdb_path.empty()) {
+ auto db = cmBuildDatabase::ForTarget(this->GeneratorTarget, config);
+ auto mcdb_template_path = cmStrCat(bdb_path, ".in");
+ db.Write(mcdb_template_path);
+ build.ImplicitDeps.emplace_back(std::move(mcdb_template_path));
+ build.ImplicitOuts.emplace_back(std::move(bdb_path));
+ }
for (auto const& scanFiles : scanningFiles) {
if (!scanFiles.ScanningOutput.empty()) {
build.ExplicitDeps.push_back(scanFiles.ScanningOutput);