Merge topic 'multi-ninja-pch'

a55df20499 Multi-Ninja: Add precompile headers support

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4201
This commit is contained in:
Brad King 2020-01-20 16:59:19 +00:00 committed by Kitware Robot
commit 941c09616b
13 changed files with 210 additions and 151 deletions

View File

@ -3407,8 +3407,15 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
{ "OBJCXX", ".objcxx.hxx" }
};
filename = cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(),
".dir/cmake_pch", languageToExtension.at(language));
filename =
cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
if (this->GetGlobalGenerator()->IsMultiConfig()) {
filename = cmStrCat(filename, "/", config);
}
filename =
cmStrCat(filename, "/cmake_pch", languageToExtension.at(language));
const std::string filename_tmp = cmStrCat(filename, ".tmp");
if (!pchReuseFrom) {

View File

@ -415,6 +415,8 @@ public:
virtual bool IsXcode() const { return false; }
virtual bool IsVisualStudio() const { return false; }
/** Return true if we know the exact location of object files.
If false, store the reason in the given string.
This is meaningful only after EnableLanguage has been called. */

View File

@ -150,6 +150,8 @@ public:
bool Open(const std::string& bindir, const std::string& projectName,
bool dryRun) override;
bool IsVisualStudio() const override { return true; }
protected:
cmGlobalVisualStudioGenerator(cmake* cm,
std::string const& platformInGeneratorName);

View File

@ -2421,163 +2421,170 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
{
// FIXME: Handle all configurations in multi-config generators.
std::string config;
if (!this->GetGlobalGenerator()->IsMultiConfig()) {
config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
std::vector<std::string> configsList;
std::string configDefault = this->Makefile->GetConfigurations(configsList);
if (configsList.empty()) {
configsList.push_back(configDefault);
}
const std::string buildType = cmSystemTools::UpperCase(config);
// FIXME: Refactor collection of sources to not evaluate object libraries.
std::vector<cmSourceFile*> sources;
target->GetSourceFiles(sources, buildType);
for (std::string const& config : configsList) {
const std::string buildType = cmSystemTools::UpperCase(config);
for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
auto langSources =
std::count_if(sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
return lang == sf->GetLanguage() &&
!sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
});
if (langSources == 0) {
continue;
}
// FIXME: Refactor collection of sources to not evaluate object libraries.
std::vector<cmSourceFile*> sources;
target->GetSourceFiles(sources, buildType);
const std::string pchSource = target->GetPchSource(config, lang);
const std::string pchHeader = target->GetPchHeader(config, lang);
if (pchSource.empty() || pchHeader.empty()) {
continue;
}
const std::string pchExtension =
this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
if (pchExtension.empty()) {
continue;
}
const char* pchReuseFrom =
target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
auto pch_sf = this->Makefile->GetOrCreateSource(
pchSource, false, cmSourceFileLocationKind::Known);
if (!this->GetGlobalGenerator()->IsXcode()) {
if (!pchReuseFrom) {
target->AddSource(pchSource, true);
for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
auto langSources = std::count_if(
sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
return lang == sf->GetLanguage() &&
!sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
});
if (langSources == 0) {
continue;
}
const std::string pchFile = target->GetPchFile(config, lang);
const std::string pchSource = target->GetPchSource(config, lang);
const std::string pchHeader = target->GetPchHeader(config, lang);
// Exclude the pch files from linking
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
if (pchSource.empty() || pchHeader.empty()) {
continue;
}
const std::string pchExtension =
this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
if (pchExtension.empty()) {
continue;
}
const char* pchReuseFrom =
target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
auto pch_sf = this->Makefile->GetOrCreateSource(
pchSource, false, cmSourceFileLocationKind::Known);
if (!this->GetGlobalGenerator()->IsXcode()) {
if (!pchReuseFrom) {
pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
} else {
auto reuseTarget =
this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
const std::string pdb_prefix =
this->GetGlobalGenerator()->IsMultiConfig()
? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
: "";
const std::string target_compile_pdb_dir = cmStrCat(
target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
target->GetName(), ".dir/");
const std::string copy_script =
cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
cmGeneratedFileStream file(copy_script);
file << "# CMake generated file\n";
for (auto extension : { ".pdb", ".idb" }) {
const std::string from_file = cmStrCat(
reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(),
"/", pchReuseFrom, ".dir/${PDB_PREFIX}", pchReuseFrom,
extension);
const std::string to_dir = cmStrCat(
target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
target->GetName(), ".dir/${PDB_PREFIX}");
const std::string to_file =
cmStrCat(to_dir, pchReuseFrom, extension);
std::string dest_file = to_file;
const std::string prefix = target->GetSafeProperty("PREFIX");
if (!prefix.empty()) {
dest_file = cmStrCat(to_dir, prefix, pchReuseFrom, extension);
}
file << "if (EXISTS \"" << from_file << "\" AND \"" << from_file
<< "\" IS_NEWER_THAN \"" << dest_file << "\")\n";
file << " file(COPY \"" << from_file << "\""
<< " DESTINATION \"" << to_dir << "\")\n";
if (!prefix.empty()) {
file << " file(REMOVE \"" << dest_file << "\")\n";
file << " file(RENAME \"" << to_file << "\" \"" << dest_file
<< "\")\n";
}
file << "endif()\n";
}
cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
{ cmSystemTools::GetCMakeCommand(),
cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script });
const std::string no_main_dependency;
const std::vector<std::string> no_deps;
const char* no_message = "";
const char* no_current_dir = nullptr;
std::vector<std::string> no_byproducts;
std::vector<std::string> outputs;
outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
pchReuseFrom, ".pdb"));
if (this->GetGlobalGenerator()->IsMultiConfig()) {
this->AddCustomCommandToTarget(
target->GetName(), outputs, no_deps, commandLines,
cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
} else {
cmImplicitDependsList no_implicit_depends;
cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
outputs, no_byproducts, no_deps, no_main_dependency,
no_implicit_depends, commandLines, no_message, no_current_dir);
if (copy_rule) {
target->AddSource(copy_rule->ResolveFullPath());
}
}
target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
target_compile_pdb_dir);
}
std::string pchSourceObj =
reuseTarget->GetPchFileObject(config, lang);
// Link to the pch object file
target->Target->AppendProperty(
"LINK_FLAGS",
cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
true);
target->AddSource(pchSource, true);
}
} else {
pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
}
// Add pchHeader to source files, which will
// be grouped as "Precompile Header File"
auto pchHeader_sf = this->Makefile->GetOrCreateSource(
pchHeader, false, cmSourceFileLocationKind::Known);
std::string err;
pchHeader_sf->ResolveFullPath(&err);
target->AddSource(pchHeader);
const std::string pchFile = target->GetPchFile(config, lang);
// Exclude the pch files from linking
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
if (!pchReuseFrom) {
pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
} else {
auto reuseTarget =
this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
const std::string pdb_prefix =
this->GetGlobalGenerator()->IsMultiConfig()
? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
: "";
const std::string target_compile_pdb_dir = cmStrCat(
target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
target->GetName(), ".dir/");
const std::string copy_script =
cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
cmGeneratedFileStream file(copy_script);
file << "# CMake generated file\n";
for (auto extension : { ".pdb", ".idb" }) {
const std::string from_file =
cmStrCat(reuseTarget->GetLocalGenerator()
->GetCurrentBinaryDirectory(),
"/", pchReuseFrom, ".dir/${PDB_PREFIX}",
pchReuseFrom, extension);
const std::string to_dir = cmStrCat(
target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
"/", target->GetName(), ".dir/${PDB_PREFIX}");
const std::string to_file =
cmStrCat(to_dir, pchReuseFrom, extension);
std::string dest_file = to_file;
const std::string prefix = target->GetSafeProperty("PREFIX");
if (!prefix.empty()) {
dest_file =
cmStrCat(to_dir, prefix, pchReuseFrom, extension);
}
file << "if (EXISTS \"" << from_file << "\" AND \""
<< from_file << "\" IS_NEWER_THAN \"" << dest_file
<< "\")\n";
file << " file(COPY \"" << from_file << "\""
<< " DESTINATION \"" << to_dir << "\")\n";
if (!prefix.empty()) {
file << " file(REMOVE \"" << dest_file << "\")\n";
file << " file(RENAME \"" << to_file << "\" \"" << dest_file
<< "\")\n";
}
file << "endif()\n";
}
cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
{ cmSystemTools::GetCMakeCommand(),
cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script });
const std::string no_main_dependency;
const std::vector<std::string> no_deps;
const char* no_message = "";
const char* no_current_dir = nullptr;
std::vector<std::string> no_byproducts;
std::vector<std::string> outputs;
outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
pchReuseFrom, ".pdb"));
if (this->GetGlobalGenerator()->IsVisualStudio()) {
this->AddCustomCommandToTarget(
target->GetName(), outputs, no_deps, commandLines,
cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
} else {
cmImplicitDependsList no_implicit_depends;
cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
outputs, no_byproducts, no_deps, no_main_dependency,
no_implicit_depends, commandLines, no_message,
no_current_dir);
if (copy_rule) {
target->AddSource(copy_rule->ResolveFullPath());
}
}
target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
target_compile_pdb_dir);
}
std::string pchSourceObj =
reuseTarget->GetPchFileObject(config, lang);
// Link to the pch object file
target->Target->AppendProperty(
"LINK_FLAGS",
cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
true);
}
} else {
pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
}
// Add pchHeader to source files, which will
// be grouped as "Precompile Header File"
auto pchHeader_sf = this->Makefile->GetOrCreateSource(
pchHeader, false, cmSourceFileLocationKind::Known);
std::string err;
pchHeader_sf->ResolveFullPath(&err);
target->AddSource(pchHeader);
}
}
}
}

View File

@ -1,4 +1,7 @@
set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
endif()
set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
if (NOT EXISTS ${foo_pch_header})

View File

@ -0,0 +1,17 @@
if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
return()
endif()
set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
if (NOT EXISTS ${foo_pch_header})
set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")
return()
endif()
file(STRINGS ${foo_pch_header} foo_pch_header_strings)
if (NOT foo_pch_header_strings MATCHES ";#include \"[^\"]*PrecompileHeaders/include/foo.h\";#include <stdio.h>(;|$)")
set(RunCMake_TEST_FAILED "Generated foo pch header\n ${foo_pch_header}\nhas bad content:\n ${foo_pch_header_strings}")
return()
endif()

View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.15)
project(PchDebugGenex C)
add_library(foo foo.c)
target_include_directories(foo PUBLIC include)
target_precompile_headers(foo PUBLIC
"$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/include/foo.h>"
<stdio.h>
)

View File

@ -1,5 +1,9 @@
set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.h")
endif()
if (NOT EXISTS ${foo_pch_header})
set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")

View File

@ -1,5 +1,9 @@
set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.hxx")
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.h")
set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.hxx")
endif()
if (NOT EXISTS ${foobar_pch_h_header})
set(RunCMake_TEST_FAILED "Generated foobar C pch header ${foobar_pch_h_header} does not exist")

View File

@ -1,4 +1,7 @@
set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/cmake_pch.hxx")
if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/Debug/cmake_pch.hxx")
endif()
file(STRINGS ${main_pch_header} main_pch_header_strings)
string(REGEX MATCH "#pragma warning\\(push, 0\\).*#include.*pch.h.*#pragma warning\\(pop\\)" matched_code ${main_pch_header_strings})

View File

@ -13,6 +13,7 @@ function(run_test name)
endfunction()
run_cmake(DisabledPch)
run_cmake(PchDebugGenex)
run_test(PchInterface)
run_cmake(PchPrologueEpilogue)
run_test(SkipPrecompileHeaders)

View File

@ -1,4 +1,4 @@
set(pch_header "CMakeFiles/tgt.dir/cmake_pch.hxx")
set(pch_header "CMakeFiles/tgt.dir/Debug/cmake_pch.hxx")
set(pch_source [=[CMakeFiles\\tgt.dir\\cmake_pch.cxx]=])
if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${pch_header}")

View File

@ -1,4 +1,4 @@
set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/cmake_pch.hxx")
set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Debug/cmake_pch.hxx")
if(NOT EXISTS "${pch_header}")
set(RunCMake_TEST_FAILED "Generated PCH header ${pch_header} does not exist.")