mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-07 22:30:13 -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 {
|
} else {
|
||||||
this->LinkerLanguage = this->Target->GetSafeProperty("LINKER_LANGUAGE");
|
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;
|
cmGeneratorTarget::~cmGeneratorTarget() = default;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "cmCryptoHash.h"
|
#include "cmCryptoHash.h"
|
||||||
#include "cmCustomCommand.h"
|
#include "cmCustomCommand.h"
|
||||||
#include "cmCustomCommandLines.h"
|
#include "cmCustomCommandLines.h"
|
||||||
|
#include "cmCustomCommandTypes.h"
|
||||||
#include "cmDuration.h"
|
#include "cmDuration.h"
|
||||||
#include "cmExportBuildFileGenerator.h"
|
#include "cmExportBuildFileGenerator.h"
|
||||||
#include "cmExternalMakefileProjectGenerator.h"
|
#include "cmExternalMakefileProjectGenerator.h"
|
||||||
@@ -68,6 +69,8 @@
|
|||||||
# include "cmQtAutoGenGlobalInitializer.h"
|
# include "cmQtAutoGenGlobalInitializer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class cmListFileBacktrace;
|
||||||
|
|
||||||
const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
|
const std::string kCMAKE_PLATFORM_INFO_INITIALIZED =
|
||||||
"CMAKE_PLATFORM_INFO_INITIALIZED";
|
"CMAKE_PLATFORM_INFO_INITIALIZED";
|
||||||
|
|
||||||
@@ -1569,6 +1572,10 @@ bool cmGlobalGenerator::Compute()
|
|||||||
}
|
}
|
||||||
this->FinalizeTargetConfiguration();
|
this->FinalizeTargetConfiguration();
|
||||||
|
|
||||||
|
if (!this->AddBuildDatabaseTargets()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
this->CreateGenerationObjects();
|
this->CreateGenerationObjects();
|
||||||
|
|
||||||
// at this point this->LocalGenerators has been filled,
|
// at this point this->LocalGenerators has been filled,
|
||||||
@@ -2834,6 +2841,20 @@ bool cmGlobalGenerator::CheckCMP0037(std::string const& targetName,
|
|||||||
reason);
|
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(
|
void cmGlobalGenerator::CreateDefaultGlobalTargets(
|
||||||
std::vector<GlobalTargetInfo>& targets)
|
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
|
std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const
|
||||||
{
|
{
|
||||||
cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
|
cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
|
||||||
|
|||||||
@@ -172,6 +172,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool SupportsBuildDatabase() const { return false; }
|
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; }
|
virtual bool IsGNUMakeJobServerAware() const { return false; }
|
||||||
|
|
||||||
@@ -873,6 +876,8 @@ private:
|
|||||||
|
|
||||||
bool CheckCMP0037(std::string const& targetName,
|
bool CheckCMP0037(std::string const& targetName,
|
||||||
std::string const& reason) const;
|
std::string const& reason) const;
|
||||||
|
bool CheckCMP0037Prefix(std::string const& targetPrefix,
|
||||||
|
std::string const& reason) const;
|
||||||
|
|
||||||
void IndexMakefile(cmMakefile* mf);
|
void IndexMakefile(cmMakefile* mf);
|
||||||
void IndexLocalGenerator(cmLocalGenerator* lg);
|
void IndexLocalGenerator(cmLocalGenerator* lg);
|
||||||
@@ -918,6 +923,13 @@ private:
|
|||||||
cmFileLockPool FileLockPool;
|
cmFileLockPool FileLockPool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using PerLanguageModuleDatabases =
|
||||||
|
std::map<std::string, std::vector<std::string>>;
|
||||||
|
using PerConfigModuleDatabases =
|
||||||
|
std::map<std::string, PerLanguageModuleDatabases>;
|
||||||
|
PerConfigModuleDatabases PerConfigModuleDbs;
|
||||||
|
PerLanguageModuleDatabases PerLanguageModuleDbs;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float FirstTimeProgress;
|
float FirstTimeProgress;
|
||||||
bool NeedSymbolicMark;
|
bool NeedSymbolicMark;
|
||||||
|
|||||||
@@ -483,6 +483,7 @@ public:
|
|||||||
bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
|
bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
|
||||||
|
|
||||||
bool CheckCxxModuleSupport(CxxModuleSupportQuery query) override;
|
bool CheckCxxModuleSupport(CxxModuleSupportQuery query) override;
|
||||||
|
bool SupportsBuildDatabase() const override { return true; }
|
||||||
|
|
||||||
std::string ConvertToOutputPath(std::string path) const override;
|
std::string ConvertToOutputPath(std::string path) const override;
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <cm3p/json/value.h>
|
#include <cm3p/json/value.h>
|
||||||
#include <cm3p/json/writer.h>
|
#include <cm3p/json/writer.h>
|
||||||
|
|
||||||
|
#include "cmBuildDatabase.h"
|
||||||
#include "cmComputeLinkInformation.h"
|
#include "cmComputeLinkInformation.h"
|
||||||
#include "cmCustomCommandGenerator.h"
|
#include "cmCustomCommandGenerator.h"
|
||||||
#include "cmDyndepCollation.h"
|
#include "cmDyndepCollation.h"
|
||||||
@@ -1232,6 +1233,21 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
|
|||||||
language, "Modules.json"));
|
language, "Modules.json"));
|
||||||
build.ImplicitDeps.emplace_back(
|
build.ImplicitDeps.emplace_back(
|
||||||
this->GetTargetDependInfoPath(language, config));
|
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) {
|
for (auto const& scanFiles : scanningFiles) {
|
||||||
if (!scanFiles.ScanningOutput.empty()) {
|
if (!scanFiles.ScanningOutput.empty()) {
|
||||||
build.ExplicitDeps.push_back(scanFiles.ScanningOutput);
|
build.ExplicitDeps.push_back(scanFiles.ScanningOutput);
|
||||||
|
|||||||
Reference in New Issue
Block a user