mirror of
https://github.com/reactos/CMake.git
synced 2024-11-24 03:59:58 +00:00
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:
commit
941c09616b
@ -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) {
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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})
|
||||
|
17
Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake
Normal file
17
Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake
Normal 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()
|
9
Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
Normal file
9
Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
Normal 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>
|
||||
)
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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})
|
||||
|
@ -13,6 +13,7 @@ function(run_test name)
|
||||
endfunction()
|
||||
|
||||
run_cmake(DisabledPch)
|
||||
run_cmake(PchDebugGenex)
|
||||
run_test(PchInterface)
|
||||
run_cmake(PchPrologueEpilogue)
|
||||
run_test(SkipPrecompileHeaders)
|
||||
|
@ -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}")
|
||||
|
@ -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.")
|
||||
|
Loading…
Reference in New Issue
Block a user