mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 19:00:54 -06:00
cmGlobalGenerator: generate build database files for targets
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user