Precompile Headers: Add REUSE_FROM signature

Add the ability to share precompiled headers artifacts between
targets.

Fixes: #19659
This commit is contained in:
Cristian Adam 2019-08-30 16:21:19 +02:00
parent 1ac4e0ef1b
commit 729d997f10
19 changed files with 345 additions and 54 deletions

View File

@ -9,9 +9,23 @@ Add a list of header files to precompile.
<INTERFACE|PUBLIC|PRIVATE> [header1...] <INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...]) [<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
target_precompile_headers(<target> REUSE_FROM <other_target>)
Adds header files to :prop_tgt:`PRECOMPILE_HEADERS` or Adds header files to :prop_tgt:`PRECOMPILE_HEADERS` or
:prop_tgt:`INTERFACE_PRECOMPILE_HEADERS` target properties. :prop_tgt:`INTERFACE_PRECOMPILE_HEADERS` target properties.
The second signature will reuse an already precompiled header file artefact
from another target. This is done by setting the
:prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` to ``<other_target>`` value.
The ``<other_target>`` will become a dependency of ``<target>``.
.. note::
The second signature will require the same set of compiler options,
compiler flags, compiler definitions for both ``<target>``, and
``<other_target>``. Compilers (e.g. GCC) will issue a warning if the
precompiled header file cannot be used (``-Winvalid-pch``).
Precompiling header files can speed up compilation by creating a partially Precompiling header files can speed up compilation by creating a partially
processed version of some header files, and then using that version during processed version of some header files, and then using that version during
compilations rather than repeatedly parsing the original headers. compilations rather than repeatedly parsing the original headers.

View File

@ -298,6 +298,7 @@ Properties on Targets
/prop_tgt/PDB_OUTPUT_DIRECTORY /prop_tgt/PDB_OUTPUT_DIRECTORY
/prop_tgt/POSITION_INDEPENDENT_CODE /prop_tgt/POSITION_INDEPENDENT_CODE
/prop_tgt/PRECOMPILE_HEADERS /prop_tgt/PRECOMPILE_HEADERS
/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM
/prop_tgt/PREFIX /prop_tgt/PREFIX
/prop_tgt/PRIVATE_HEADER /prop_tgt/PRIVATE_HEADER
/prop_tgt/PROJECT_LABEL /prop_tgt/PROJECT_LABEL

View File

@ -0,0 +1,7 @@
PRECOMPILE_HEADERS_REUSE_FROM
-----------------------------
Target from which to reuse the precomipled headers build artifact.
See the second signature of :command:`target_precompile_headers` command
for more detailed information.

View File

@ -333,10 +333,17 @@ macro(__windows_compiler_msvc lang)
set(CMAKE_LINK_PCH ON) set(CMAKE_LINK_PCH ON)
if(MSVC_VERSION GREATER_EQUAL 1910) if(MSVC_VERSION GREATER_EQUAL 1910)
# VS 2017 or greater # VS 2017 or greater
if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang")
set(CMAKE_PCH_PROLOGUE "#pragma system_header") set(CMAKE_PCH_PROLOGUE "#pragma system_header")
else()
set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
endif() endif()
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH /Yu<PCH_HEADER> /FI<PCH_HEADER>) endif()
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH /Yc<PCH_HEADER> /FI<PCH_HEADER>) if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang")
set(CMAKE_PCH_COPY_COMPILE_PDB ON)
endif()
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH /Yu<PCH_HEADER> /Fp<PCH_FILE> /FI<PCH_HEADER>)
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH /Yc<PCH_HEADER> /Fp<PCH_FILE> /FI<PCH_HEADER>)
if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC") if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)

View File

@ -171,6 +171,7 @@ std::string cmCommonTargetGenerator::ComputeTargetCompilePDB() const
if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) { if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) {
return compilePdbPath; return compilePdbPath;
} }
compilePdbPath = compilePdbPath =
this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName()); this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName());
if (compilePdbPath.empty()) { if (compilePdbPath.empty()) {

View File

@ -35,6 +35,7 @@
#include "cmRange.h" #include "cmRange.h"
#include "cmSourceFile.h" #include "cmSourceFile.h"
#include "cmSourceFileLocation.h" #include "cmSourceFileLocation.h"
#include "cmSourceFileLocationKind.h"
#include "cmState.h" #include "cmState.h"
#include "cmStringAlgorithms.h" #include "cmStringAlgorithms.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
@ -3371,23 +3372,32 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
} }
std::string& filename = inserted.first->second; std::string& filename = inserted.first->second;
const cmGeneratorTarget* generatorTarget = this;
const char* pchReuseFrom =
generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
if (pchReuseFrom) {
generatorTarget =
this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom);
}
if (this->GetGlobalGenerator()->IsMultiConfig()) { if (this->GetGlobalGenerator()->IsMultiConfig()) {
filename = filename = cmStrCat(
cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), "/"); generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/");
} else { } else {
// For GCC we need to have the header file .h[xx] // For GCC we need to have the header file .h[xx]
// next to the .h[xx].gch file // next to the .h[xx].gch file
filename = this->ObjectDirectory; filename = generatorTarget->ObjectDirectory;
} }
filename = cmStrCat(filename, "CMakeFiles/", this->GetName(), filename = cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(),
".dir/cmake_pch", ((language == "C") ? ".h" : ".hxx")); ".dir/cmake_pch", ((language == "C") ? ".h" : ".hxx"));
const std::string filename_tmp = cmStrCat(filename, ".tmp"); const std::string filename_tmp = cmStrCat(filename, ".tmp");
{ if (!pchReuseFrom) {
auto pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE"); auto pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
auto pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE"); auto pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
{
cmGeneratedFileStream file( cmGeneratedFileStream file(
filename_tmp, false, filename_tmp, false,
this->GetGlobalGenerator()->GetMakefileEncoding()); this->GetGlobalGenerator()->GetMakefileEncoding());
@ -3405,7 +3415,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
if (header_bt.Value.empty()) { if (header_bt.Value.empty()) {
continue; continue;
} }
if (header_bt.Value[0] == '<' || header_bt.Value[0] == '"') { if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
file << "#include " << header_bt.Value << "\n"; file << "#include " << header_bt.Value << "\n";
} else { } else {
file << "#include \"" << header_bt.Value << "\"\n"; file << "#include \"" << header_bt.Value << "\"\n";
@ -3423,6 +3433,7 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
} }
cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
} }
}
return inserted.first->second; return inserted.first->second;
} }
@ -3440,8 +3451,18 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config,
return std::string(); return std::string();
} }
std::string& filename = inserted.first->second; std::string& filename = inserted.first->second;
filename = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
"/CMakeFiles/", this->GetName(), ".dir/cmake_pch"); const cmGeneratorTarget* generatorTarget = this;
const char* pchReuseFrom =
generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
if (pchReuseFrom) {
generatorTarget =
this->GetGlobalGenerator()->FindGeneratorTarget(pchReuseFrom);
}
filename =
cmStrCat(generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(),
"/CMakeFiles/", generatorTarget->GetName(), ".dir/cmake_pch");
// For GCC the source extension will be tranformed into .h[xx].gch // For GCC the source extension will be tranformed into .h[xx].gch
if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) { if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
@ -3449,13 +3470,41 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config,
} else { } else {
filename += ((language == "C") ? ".c" : ".cxx"); filename += ((language == "C") ? ".c" : ".cxx");
} }
const std::string filename_tmp = cmStrCat(filename, ".tmp"); const std::string filename_tmp = cmStrCat(filename, ".tmp");
if (!pchReuseFrom) {
{ {
cmGeneratedFileStream file(filename_tmp); cmGeneratedFileStream file(filename_tmp);
file << "/* generated by CMake */\n"; file << "/* generated by CMake */\n";
} }
cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
} }
}
return inserted.first->second;
}
std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
const std::string& language)
{
if (language != "C" && language != "CXX") {
return std::string();
}
const auto inserted =
this->PchObjectFiles.insert(std::make_pair(language + config, ""));
if (inserted.second) {
const std::string pchSource = this->GetPchSource(config, language);
if (pchSource.empty()) {
return std::string();
}
std::string& filename = inserted.first->second;
this->AddSource(pchSource, true);
auto pchSf = this->Makefile->GetOrCreateSource(
pchSource, false, cmSourceFileLocationKind::Known);
filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
}
return inserted.first->second; return inserted.first->second;
} }

View File

@ -462,6 +462,8 @@ public:
const std::string& language) const; const std::string& language) const;
std::string GetPchSource(const std::string& config, std::string GetPchSource(const std::string& config,
const std::string& language) const; const std::string& language) const;
std::string GetPchFileObject(const std::string& config,
const std::string& language);
bool IsSystemIncludeDirectory(const std::string& dir, bool IsSystemIncludeDirectory(const std::string& dir,
const std::string& config, const std::string& config,
@ -880,6 +882,7 @@ private:
mutable std::set<std::string> LinkImplicitNullProperties; mutable std::set<std::string> LinkImplicitNullProperties;
mutable std::map<std::string, std::string> PchHeaders; mutable std::map<std::string, std::string> PchHeaders;
mutable std::map<std::string, std::string> PchSources; mutable std::map<std::string, std::string> PchSources;
mutable std::map<std::string, std::string> PchObjectFiles;
void ExpandLinkItems(std::string const& prop, std::string const& value, void ExpandLinkItems(std::string const& prop, std::string const& value,
std::string const& config, std::string const& config,

View File

@ -4,7 +4,9 @@
#include "cmAlgorithms.h" #include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h" #include "cmComputeLinkInformation.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h" #include "cmCustomCommandGenerator.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratedFileStream.h" #include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h" #include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionEvaluationFile.h" #include "cmGeneratorExpressionEvaluationFile.h"
@ -2255,23 +2257,124 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target,
return; return;
} }
const char* pchReuseFrom =
target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
auto pch_sf = this->Makefile->GetOrCreateSource( auto pch_sf = this->Makefile->GetOrCreateSource(
pchSource, false, cmSourceFileLocationKind::Known); pchSource, false, cmSourceFileLocationKind::Known);
std::string pchFile = pchHeader; std::string pchFile = pchHeader;
if (!this->GetGlobalGenerator()->IsXcode()) { if (!this->GetGlobalGenerator()->IsXcode()) {
if (!pchReuseFrom) {
target->AddSource(pchSource, true);
}
// Exclude the pch files from linking // Exclude the pch files from linking
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
cmSystemTools::ReplaceString(pchFile, (lang == "C" ? ".h" : ".hxx"),
pchExtension); auto replaceExtension = [](const std::string& str,
const std::string& ext) -> std::string {
auto dot_pos = str.rfind('.');
std::string result;
if (dot_pos != std::string::npos) {
result = str.substr(0, dot_pos);
}
result += ext;
return result;
};
if (!pchReuseFrom) {
std::string pchSourceObj = target->GetPchFileObject(config, lang);
pchFile = replaceExtension(pchSourceObj, pchExtension);
pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str()); 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}");
file << "if (EXISTS \"" << from_file << "\")\n";
file << " file(COPY \"" << from_file << "\""
<< " DESTINATION \"" << to_dir << "\")\n";
file << "endif()\n";
}
cmCustomCommandLines commandLines;
cmCustomCommandLine currentLine;
currentLine.push_back(cmSystemTools::GetCMakeCommand());
currentLine.push_back(cmStrCat("-DPDB_PREFIX=", pdb_prefix));
currentLine.push_back("-P");
currentLine.push_back(copy_script);
commandLines.push_back(std::move(currentLine));
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->Makefile->AddCustomCommandToTarget(
target->GetName(), outputs, no_deps, commandLines,
cmTarget::PRE_BUILD, no_message, no_current_dir);
} else {
cmImplicitDependsList no_implicit_depends;
cmSourceFile* copy_rule = this->Makefile->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.c_str());
}
std::string pchSourceObj = reuseTarget->GetPchFileObject(config, lang);
// Link to the pch object file
target->Target->SetProperty(
"LINK_FLAGS",
this->ConvertToOutputFormat(pchSourceObj, SHELL).c_str());
pchFile = replaceExtension(pchSourceObj, pchExtension);
}
} else { } else {
pchFile += pchExtension; pchFile += pchExtension;
pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
} }
target->AddSource(pchSource, true);
for (auto& str : { std::ref(useOptionList), std::ref(createOptionList) }) { for (auto& str : { std::ref(useOptionList), std::ref(createOptionList) }) {
cmSystemTools::ReplaceString(str, "<PCH_HEADER>", pchHeader); cmSystemTools::ReplaceString(str, "<PCH_HEADER>", pchHeader);
cmSystemTools::ReplaceString(str, "<PCH_FILE>", pchFile); cmSystemTools::ReplaceString(str, "<PCH_FILE>", pchFile);

View File

@ -1085,6 +1085,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
MAKE_STATIC_PROP(COMPILE_FEATURES); MAKE_STATIC_PROP(COMPILE_FEATURES);
MAKE_STATIC_PROP(COMPILE_OPTIONS); MAKE_STATIC_PROP(COMPILE_OPTIONS);
MAKE_STATIC_PROP(PRECOMPILE_HEADERS); MAKE_STATIC_PROP(PRECOMPILE_HEADERS);
MAKE_STATIC_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
MAKE_STATIC_PROP(CUDA_PTX_COMPILATION); MAKE_STATIC_PROP(CUDA_PTX_COMPILATION);
MAKE_STATIC_PROP(EXPORT_NAME); MAKE_STATIC_PROP(EXPORT_NAME);
MAKE_STATIC_PROP(IMPORTED_GLOBAL); MAKE_STATIC_PROP(IMPORTED_GLOBAL);
@ -1231,6 +1232,41 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
<< impl->Name << "\")\n"; << impl->Name << "\")\n";
impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return; return;
} else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) {
if (this->GetProperty("PRECOMPILE_HEADERS")) {
std::ostringstream e;
e << "PRECOMPILE_HEADERS property is already set on target (\""
<< impl->Name << "\")\n";
impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
auto reusedTarget =
impl->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget(
value);
if (!reusedTarget) {
const std::string e(
"PRECOMPILE_HEADERS_REUSE_FROM set with non existing target");
impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
return;
}
std::string reusedFrom = reusedTarget->GetSafeProperty(prop);
if (reusedFrom.empty()) {
reusedFrom = value;
}
impl->Properties.SetProperty(prop, reusedFrom.c_str());
reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom.c_str());
reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
cmStrCat(reusedFrom, ".dir/").c_str());
for (auto p : { "COMPILE_PDB_NAME", "PRECOMPILE_HEADERS",
"INTERFACE_PRECOMPILE_HEADERS" }) {
this->SetProperty(p, reusedTarget->GetProperty(p));
}
this->AddUtility(reusedFrom, impl->Makefile);
} else { } else {
impl->Properties.SetProperty(prop, value); impl->Properties.SetProperty(prop, value);
} }
@ -1308,6 +1344,14 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
impl->LinkDirectoriesBacktraces.push_back(lfbt); impl->LinkDirectoriesBacktraces.push_back(lfbt);
} }
} else if (prop == "PRECOMPILE_HEADERS") { } else if (prop == "PRECOMPILE_HEADERS") {
if (this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
std::ostringstream e;
e << "PRECOMPILE_HEADERS_REUSE_FROM property is already set on target "
"(\""
<< impl->Name << "\")\n";
impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
return;
}
if (value && *value) { if (value && *value) {
impl->PrecompileHeadersEntries.emplace_back(value); impl->PrecompileHeadersEntries.emplace_back(value);
cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();

View File

@ -10,7 +10,7 @@
bool cmTargetPrecompileHeadersCommand::InitialPass( bool cmTargetPrecompileHeadersCommand::InitialPass(
std::vector<std::string> const& args, cmExecutionStatus&) std::vector<std::string> const& args, cmExecutionStatus&)
{ {
return this->HandleArguments(args, "PRECOMPILE_HEADERS"); return this->HandleArguments(args, "PRECOMPILE_HEADERS", PROCESS_REUSE_FROM);
} }
void cmTargetPrecompileHeadersCommand::HandleMissingTarget( void cmTargetPrecompileHeadersCommand::HandleMissingTarget(

View File

@ -65,6 +65,19 @@ bool cmTargetPropCommandBase::HandleArguments(
++argIndex; ++argIndex;
} }
if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") {
if (args.size() != 3) {
this->SetError("called with incorrect number of arguments");
return false;
}
++argIndex;
this->Target->SetProperty("PRECOMPILE_HEADERS_REUSE_FROM",
args[argIndex].c_str());
++argIndex;
}
this->Property = prop; this->Property = prop;
while (argIndex < args.size()) { while (argIndex < args.size()) {

View File

@ -17,9 +17,10 @@ class cmTargetPropCommandBase : public cmCommand
public: public:
enum ArgumentFlags enum ArgumentFlags
{ {
NO_FLAGS = 0, NO_FLAGS = 0x0,
PROCESS_BEFORE = 1, PROCESS_BEFORE = 0x1,
PROCESS_SYSTEM = 2 PROCESS_SYSTEM = 0x2,
PROCESS_REUSE_FROM = 0x3
}; };
bool HandleArguments(std::vector<std::string> const& args, bool HandleArguments(std::vector<std::string> const& args,

View File

@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.15)
project(PchReuseFrom C)
add_library(empty empty.c)
target_precompile_headers(empty PUBLIC
<stdio.h>
<string.h>
)
target_include_directories(empty PUBLIC include)
add_library(foo foo.c)
target_include_directories(foo PUBLIC include)
target_precompile_headers(foo REUSE_FROM empty)
add_executable(foobar foobar.c)
target_link_libraries(foobar foo )
set_target_properties(foobar PROPERTIES PRECOMPILE_HEADERS_REUSE_FROM foo)
enable_testing()
add_test(NAME foobar COMMAND foobar)

View File

@ -0,0 +1,2 @@
^(|Warning #670: precompiled header file [^
]* was not generated in this directory)$

View File

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.15)
project(PchReuseFromSubdir C)
add_library(empty empty.c)
target_precompile_headers(empty PUBLIC
<stdio.h>
<string.h>
)
target_include_directories(empty PUBLIC include)
add_library(foo foo.c)
target_include_directories(foo PUBLIC include)
target_precompile_headers(foo REUSE_FROM empty)
subdirs(subdir)
enable_testing()
add_test(NAME foobar COMMAND foobar)

View File

@ -16,3 +16,5 @@ run_cmake(DisabledPch)
run_test(PchInterface) run_test(PchInterface)
run_cmake(PchPrologueEpilogue) run_cmake(PchPrologueEpilogue)
run_test(SkipPrecompileHeaders) run_test(SkipPrecompileHeaders)
run_test(PchReuseFrom)
run_test(PchReuseFromSubdir)

View File

@ -0,0 +1,3 @@
void nothing()
{
}

View File

@ -1,6 +1,6 @@
#ifndef foo_h #ifndef foo_h
#define foo_h #define foo_h
extern int foo(); int foo(void);
#endif #endif

View File

@ -0,0 +1,3 @@
add_executable(foobar ../foobar.c)
target_link_libraries(foobar foo )
set_target_properties(foobar PROPERTIES PRECOMPILE_HEADERS_REUSE_FROM foo)