mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-06 05:16:58 +00:00
PCH: Add all PCH sources before computing PCH files to avoid rebuilding caches
Issue: #25962
This commit is contained in:
1 parent
8b969d1e63
commit
525cebab82
3 files changed
+154
-108
No files matched your search
+132
-108
@@ -2935,13 +2935,37 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
|
||||
std::vector<std::string> configsList =
|
||||
this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
|
||||
|
||||
cmValue const pchExtension =
|
||||
this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
|
||||
|
||||
auto* reuseTarget = target->GetPchReuseTarget();
|
||||
bool const haveReuseTarget = reuseTarget && reuseTarget != target;
|
||||
|
||||
// Adding a source clears the target's source caches, which GetPchFile
|
||||
// rebuilds. Add the sources of all PCHs before computing any PCH file
|
||||
// so the caches are rebuilt once rather than once per PCH.
|
||||
struct PchInfo
|
||||
{
|
||||
std::string Config;
|
||||
std::string Lang;
|
||||
std::string Arch;
|
||||
std::string Source;
|
||||
std::string Header;
|
||||
cmSourceFile* SourceFile;
|
||||
cmSourceFile* HeaderFile;
|
||||
};
|
||||
std::vector<PchInfo> pchInfos;
|
||||
|
||||
// A PCH source is added for all configurations, so it is a source of its
|
||||
// language in later configurations too.
|
||||
std::set<std::string> pchSourceLangs;
|
||||
|
||||
for (std::string const& config : configsList) {
|
||||
// FIXME: Refactor collection of sources to not evaluate object
|
||||
// libraries.
|
||||
std::vector<cmSourceFile*> sources;
|
||||
target->GetSourceFiles(sources, config);
|
||||
|
||||
std::string const configUpper = cmSystemTools::UpperCase(config);
|
||||
static std::array<std::string, 4> const langs = { { "C", "CXX", "OBJC",
|
||||
"OBJCXX" } };
|
||||
|
||||
@@ -2964,7 +2988,8 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
|
||||
!((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) ||
|
||||
sf->GetProperty("SKIP_PRECOMPILE_HEADERS"));
|
||||
});
|
||||
if (langSources == 0) {
|
||||
if (langSources == 0 &&
|
||||
pchSourceLangs.find(lang) == pchSourceLangs.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3006,16 +3031,10 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
|
||||
continue;
|
||||
}
|
||||
|
||||
cmValue pchExtension =
|
||||
this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
|
||||
|
||||
if (pchExtension.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* reuseTarget = target->GetPchReuseTarget();
|
||||
bool const haveReuseTarget = reuseTarget && reuseTarget != target;
|
||||
|
||||
auto* pch_sf = this->Makefile->GetOrCreateSource(
|
||||
pchSource, false, cmSourceFileLocationKind::Known);
|
||||
pch_sf->SetSpecialSourceType(
|
||||
@@ -3026,111 +3045,116 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
|
||||
|
||||
if (!this->GetGlobalGenerator()->IsXcode()) {
|
||||
if (!haveReuseTarget) {
|
||||
target->AddSource(pchSource, true);
|
||||
pchSourceLangs.insert(lang);
|
||||
}
|
||||
|
||||
std::string const pchFile = target->GetPchFile(config, lang, arch);
|
||||
|
||||
// Exclude the pch files from linking
|
||||
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
|
||||
if (!haveReuseTarget) {
|
||||
pch_sf->AppendProperty(
|
||||
"OBJECT_OUTPUTS",
|
||||
cmStrCat("$<$<CONFIG:", config, ">:", pchFile, '>'));
|
||||
} else {
|
||||
if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
|
||||
|
||||
std::string const compilerId =
|
||||
this->Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_COMPILER_ID"));
|
||||
|
||||
std::string const compilerVersion =
|
||||
this->Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_COMPILER_VERSION"));
|
||||
|
||||
std::string const langFlags =
|
||||
this->Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper));
|
||||
|
||||
bool editAndContinueDebugInfo = false;
|
||||
bool programDatabaseDebugInfo = false;
|
||||
cm::optional<std::string> msvcDebugInformationFormat =
|
||||
this->GetMSVCDebugFormatName(config, target);
|
||||
if (msvcDebugInformationFormat &&
|
||||
!msvcDebugInformationFormat->empty()) {
|
||||
editAndContinueDebugInfo =
|
||||
*msvcDebugInformationFormat == "EditAndContinue";
|
||||
programDatabaseDebugInfo =
|
||||
*msvcDebugInformationFormat == "ProgramDatabase";
|
||||
} else {
|
||||
editAndContinueDebugInfo =
|
||||
langFlags.find("/ZI") != std::string::npos ||
|
||||
langFlags.find("-ZI") != std::string::npos;
|
||||
programDatabaseDebugInfo =
|
||||
langFlags.find("/Zi") != std::string::npos ||
|
||||
langFlags.find("-Zi") != std::string::npos;
|
||||
}
|
||||
|
||||
if (editAndContinueDebugInfo) {
|
||||
this->CopyPchCompilePdb(config, lang, target, reuseTarget,
|
||||
{ ".pdb", ".idb" });
|
||||
} else if (programDatabaseDebugInfo) {
|
||||
this->CopyPchCompilePdb(config, lang, target, reuseTarget,
|
||||
{ ".pdb" });
|
||||
}
|
||||
}
|
||||
|
||||
// Link to the pch object file
|
||||
std::string pchSourceObj;
|
||||
// Fastbuild will propagate pch.obj for us, no need to link to it
|
||||
// explicitly.
|
||||
if (!this->GetGlobalGenerator()->IsFastbuild()) {
|
||||
pchSourceObj =
|
||||
reuseTarget->GetPchFileObject(config, lang, arch);
|
||||
}
|
||||
|
||||
if (target->GetType() != cm::TargetType::OBJECT_LIBRARY) {
|
||||
std::string linkerProperty = "LINK_FLAGS_";
|
||||
if (target->GetType() == cm::TargetType::STATIC_LIBRARY) {
|
||||
linkerProperty = "STATIC_LIBRARY_FLAGS_";
|
||||
}
|
||||
target->Target->AppendProperty(
|
||||
cmStrCat(linkerProperty, configUpper),
|
||||
cmStrCat(' ',
|
||||
this->ConvertToOutputFormat(pchSourceObj, SHELL)),
|
||||
cm::nullopt, true);
|
||||
} else if (reuseTarget->GetType() ==
|
||||
cm::TargetType::OBJECT_LIBRARY) {
|
||||
target->Target->AppendProperty(
|
||||
"INTERFACE_LINK_LIBRARIES",
|
||||
cmStrCat("$<$<CONFIG:", config,
|
||||
">:$<LINK_ONLY:", pchSourceObj, ">>"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pch_sf->SetProperty("PCH_EXTENSION", pchExtension);
|
||||
}
|
||||
|
||||
// Add pchHeader to source files, which will
|
||||
// be grouped as "Precompile Header File"
|
||||
auto* pchHeader_sf = this->Makefile->GetOrCreateSource(
|
||||
pchHeader, false, cmSourceFileLocationKind::Known);
|
||||
pchHeader_sf->SetSpecialSourceType(
|
||||
cmSourceFile::SpecialSourceType::PchHeader);
|
||||
std::string err;
|
||||
pchHeader_sf->ResolveFullPath(&err);
|
||||
if (!err.empty()) {
|
||||
this->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Unable to resolve full path of PCH-header '",
|
||||
pchHeader, "' assigned to target ", target->GetName(),
|
||||
", although its path is supposed to be known!"));
|
||||
}
|
||||
target->AddSource(pchHeader);
|
||||
pchInfos.push_back(
|
||||
{ config, lang, arch, pchSource, pchHeader, pch_sf, nullptr });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (PchInfo& pch : pchInfos) {
|
||||
if (!haveReuseTarget) {
|
||||
target->AddSource(pch.Source, true);
|
||||
}
|
||||
|
||||
// Add pchHeader to source files, which will
|
||||
// be grouped as "Precompile Header File"
|
||||
pch.HeaderFile = this->Makefile->GetOrCreateSource(
|
||||
pch.Header, false, cmSourceFileLocationKind::Known);
|
||||
pch.HeaderFile->SetSpecialSourceType(
|
||||
cmSourceFile::SpecialSourceType::PchHeader);
|
||||
target->AddSource(pch.Header);
|
||||
}
|
||||
|
||||
for (PchInfo const& pch : pchInfos) {
|
||||
std::string const& config = pch.Config;
|
||||
std::string const& lang = pch.Lang;
|
||||
std::string const& arch = pch.Arch;
|
||||
cmSourceFile* pch_sf = pch.SourceFile;
|
||||
|
||||
std::string const pchFile = target->GetPchFile(config, lang, arch);
|
||||
|
||||
// Exclude the pch files from linking
|
||||
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
|
||||
if (!haveReuseTarget) {
|
||||
pch_sf->AppendProperty(
|
||||
"OBJECT_OUTPUTS",
|
||||
cmStrCat("$<$<CONFIG:", config, ">:", pchFile, '>'));
|
||||
} else {
|
||||
std::string const configUpper = cmSystemTools::UpperCase(config);
|
||||
|
||||
if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
|
||||
std::string const langFlags = this->Makefile->GetSafeDefinition(
|
||||
cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper));
|
||||
|
||||
bool editAndContinueDebugInfo = false;
|
||||
bool programDatabaseDebugInfo = false;
|
||||
cm::optional<std::string> msvcDebugInformationFormat =
|
||||
this->GetMSVCDebugFormatName(config, target);
|
||||
if (msvcDebugInformationFormat &&
|
||||
!msvcDebugInformationFormat->empty()) {
|
||||
editAndContinueDebugInfo =
|
||||
*msvcDebugInformationFormat == "EditAndContinue";
|
||||
programDatabaseDebugInfo =
|
||||
*msvcDebugInformationFormat == "ProgramDatabase";
|
||||
} else {
|
||||
editAndContinueDebugInfo =
|
||||
langFlags.find("/ZI") != std::string::npos ||
|
||||
langFlags.find("-ZI") != std::string::npos;
|
||||
programDatabaseDebugInfo =
|
||||
langFlags.find("/Zi") != std::string::npos ||
|
||||
langFlags.find("-Zi") != std::string::npos;
|
||||
}
|
||||
|
||||
if (editAndContinueDebugInfo) {
|
||||
this->CopyPchCompilePdb(config, lang, target, reuseTarget,
|
||||
{ ".pdb", ".idb" });
|
||||
} else if (programDatabaseDebugInfo) {
|
||||
this->CopyPchCompilePdb(config, lang, target, reuseTarget,
|
||||
{ ".pdb" });
|
||||
}
|
||||
}
|
||||
|
||||
// Link to the pch object file
|
||||
std::string pchSourceObj;
|
||||
// Fastbuild will propagate pch.obj for us, no need to link to it
|
||||
// explicitly.
|
||||
if (!this->GetGlobalGenerator()->IsFastbuild()) {
|
||||
pchSourceObj = reuseTarget->GetPchFileObject(config, lang, arch);
|
||||
}
|
||||
|
||||
if (target->GetType() != cm::TargetType::OBJECT_LIBRARY) {
|
||||
std::string linkerProperty = "LINK_FLAGS_";
|
||||
if (target->GetType() == cm::TargetType::STATIC_LIBRARY) {
|
||||
linkerProperty = "STATIC_LIBRARY_FLAGS_";
|
||||
}
|
||||
target->Target->AppendProperty(
|
||||
cmStrCat(linkerProperty, configUpper),
|
||||
cmStrCat(' ', this->ConvertToOutputFormat(pchSourceObj, SHELL)),
|
||||
cm::nullopt, true);
|
||||
} else if (reuseTarget->GetType() == cm::TargetType::OBJECT_LIBRARY) {
|
||||
target->Target->AppendProperty(
|
||||
"INTERFACE_LINK_LIBRARIES",
|
||||
cmStrCat("$<$<CONFIG:", config, ">:$<LINK_ONLY:", pchSourceObj,
|
||||
">>"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pch_sf->SetProperty("PCH_EXTENSION", pchExtension);
|
||||
}
|
||||
|
||||
// With CMAKE_LINK_PCH, GetPchFile above writes a reused PCH header.
|
||||
std::string err;
|
||||
if (pch.HeaderFile->ResolveFullPath(&err).empty()) {
|
||||
this->IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Unable to resolve full path of PCH-header '", pch.Header,
|
||||
"' assigned to target ", target->GetName(),
|
||||
", although its path is supposed to be known!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmLocalGenerator::CopyPchCompilePdb(
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
|
||||
|
||||
enable_language(C)
|
||||
enable_language(CXX)
|
||||
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/lib.c "int lib_c(void) { return 0; }\n")
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/lib.cpp "int lib_cxx() { return 0; }\n")
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void) { return 0; }\n")
|
||||
|
||||
# With Visual Studio, the C and C++ PCH objects of this target need
|
||||
# disambiguated names.
|
||||
add_library(mixed STATIC ${CMAKE_BINARY_DIR}/lib.c ${CMAKE_BINARY_DIR}/lib.cpp)
|
||||
target_precompile_headers(mixed PRIVATE <stddef.h>)
|
||||
|
||||
# This links the C PCH object of 'mixed', whose name must match in every
|
||||
# configuration.
|
||||
add_executable(main_c ${CMAKE_BINARY_DIR}/main.c)
|
||||
target_precompile_headers(main_c REUSE_FROM mixed)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME main_c COMMAND main_c)
|
||||
@@ -31,3 +31,4 @@ run_cmake(PchReuseWithoutPch)
|
||||
run_build_verbose(PchReuseAppend)
|
||||
run_build_verbose(PchReuseDeclarationOrder)
|
||||
run_test(PchReuseFromObjLib)
|
||||
run_test(PchReuseFromMultilanguage)
|
||||
Reference in new issue
Block a user