diff options
author | Ben Boeckel <ben.boeckel@kitware.com> | 2023-09-28 17:30:43 (GMT) |
---|---|---|
committer | Ben Boeckel <ben.boeckel@kitware.com> | 2024-08-27 16:37:36 (GMT) |
commit | 84bc710d84c912a8d5dc1a972ed9c021adda4c55 (patch) | |
tree | a1bcbbd2eea23906f2000a1f15288f36bdd316f1 | |
parent | 670f753f24fccaffee15c078e319ef2d85116ee3 (diff) | |
download | CMake-84bc710d84c912a8d5dc1a972ed9c021adda4c55.zip CMake-84bc710d84c912a8d5dc1a972ed9c021adda4c55.tar.gz CMake-84bc710d84c912a8d5dc1a972ed9c021adda4c55.tar.bz2 |
cmGlobalGenerator: generate build database files for targets
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 14 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 216 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 12 | ||||
-rw-r--r-- | Source/cmGlobalNinjaGenerator.h | 1 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 16 |
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); |