cmGlobalGenerator: generate build database files for targets

This commit is contained in:
Ben Boeckel
2023-09-28 13:30:43 -04:00
parent 670f753f24
commit 84bc710d84
5 changed files with 259 additions and 0 deletions

View File

@@ -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;

View File

@@ -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(

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);