Precompile Headers: Add REUSE_FROM signature
Add the ability to share precompiled headers artifacts between targets. Fixes: #19659
This commit is contained in:
parent
1ac4e0ef1b
commit
729d997f10
@ -9,9 +9,23 @@ Add a list of header files to precompile.
|
||||
<INTERFACE|PUBLIC|PRIVATE> [header1...]
|
||||
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
|
||||
|
||||
target_precompile_headers(<target> REUSE_FROM <other_target>)
|
||||
|
||||
Adds header files to :prop_tgt:`PRECOMPILE_HEADERS` or
|
||||
: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
|
||||
processed version of some header files, and then using that version during
|
||||
compilations rather than repeatedly parsing the original headers.
|
||||
|
@ -298,6 +298,7 @@ Properties on Targets
|
||||
/prop_tgt/PDB_OUTPUT_DIRECTORY
|
||||
/prop_tgt/POSITION_INDEPENDENT_CODE
|
||||
/prop_tgt/PRECOMPILE_HEADERS
|
||||
/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM
|
||||
/prop_tgt/PREFIX
|
||||
/prop_tgt/PRIVATE_HEADER
|
||||
/prop_tgt/PROJECT_LABEL
|
||||
|
7
Help/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM.rst
Normal file
7
Help/prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM.rst
Normal 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.
|
@ -333,10 +333,17 @@ macro(__windows_compiler_msvc lang)
|
||||
set(CMAKE_LINK_PCH ON)
|
||||
if(MSVC_VERSION GREATER_EQUAL 1910)
|
||||
# VS 2017 or greater
|
||||
set(CMAKE_PCH_PROLOGUE "#pragma system_header")
|
||||
if (NOT ${CMAKE_${lang}_COMPILER_ID} STREQUAL "Clang")
|
||||
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>)
|
||||
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")
|
||||
set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
|
||||
|
@ -171,6 +171,7 @@ std::string cmCommonTargetGenerator::ComputeTargetCompilePDB() const
|
||||
if (this->GeneratorTarget->GetType() > cmStateEnums::OBJECT_LIBRARY) {
|
||||
return compilePdbPath;
|
||||
}
|
||||
|
||||
compilePdbPath =
|
||||
this->GeneratorTarget->GetCompilePDBPath(this->GetConfigName());
|
||||
if (compilePdbPath.empty()) {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "cmRange.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmSourceFileLocation.h"
|
||||
#include "cmSourceFileLocationKind.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
@ -3371,57 +3372,67 @@ std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
|
||||
}
|
||||
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()) {
|
||||
filename =
|
||||
cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), "/");
|
||||
filename = cmStrCat(
|
||||
generatorTarget->LocalGenerator->GetCurrentBinaryDirectory(), "/");
|
||||
} else {
|
||||
// For GCC we need to have the header file .h[xx]
|
||||
// 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"));
|
||||
|
||||
const std::string filename_tmp = cmStrCat(filename, ".tmp");
|
||||
{
|
||||
if (!pchReuseFrom) {
|
||||
auto pchPrologue = this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
|
||||
auto pchEpilogue = this->Makefile->GetDefinition("CMAKE_PCH_EPILOGUE");
|
||||
|
||||
cmGeneratedFileStream file(
|
||||
filename_tmp, false,
|
||||
this->GetGlobalGenerator()->GetMakefileEncoding());
|
||||
file << "/* generated by CMake */\n\n";
|
||||
if (pchPrologue) {
|
||||
file << pchPrologue << "\n";
|
||||
}
|
||||
if (this->GetGlobalGenerator()->IsXcode()) {
|
||||
file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
|
||||
}
|
||||
if (language == "CXX") {
|
||||
file << "#ifdef __cplusplus\n";
|
||||
}
|
||||
for (auto const& header_bt : headers) {
|
||||
if (header_bt.Value.empty()) {
|
||||
continue;
|
||||
{
|
||||
cmGeneratedFileStream file(
|
||||
filename_tmp, false,
|
||||
this->GetGlobalGenerator()->GetMakefileEncoding());
|
||||
file << "/* generated by CMake */\n\n";
|
||||
if (pchPrologue) {
|
||||
file << pchPrologue << "\n";
|
||||
}
|
||||
if (header_bt.Value[0] == '<' || header_bt.Value[0] == '"') {
|
||||
file << "#include " << header_bt.Value << "\n";
|
||||
} else {
|
||||
file << "#include \"" << header_bt.Value << "\"\n";
|
||||
if (this->GetGlobalGenerator()->IsXcode()) {
|
||||
file << "#ifndef CMAKE_SKIP_PRECOMPILE_HEADERS\n";
|
||||
}
|
||||
if (language == "CXX") {
|
||||
file << "#ifdef __cplusplus\n";
|
||||
}
|
||||
for (auto const& header_bt : headers) {
|
||||
if (header_bt.Value.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (header_bt.Value[0] == '<' || header_bt.Value[0] == '\"') {
|
||||
file << "#include " << header_bt.Value << "\n";
|
||||
} else {
|
||||
file << "#include \"" << header_bt.Value << "\"\n";
|
||||
}
|
||||
}
|
||||
if (language == "CXX") {
|
||||
file << "#endif // __cplusplus\n";
|
||||
}
|
||||
if (this->GetGlobalGenerator()->IsXcode()) {
|
||||
file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
|
||||
}
|
||||
if (pchEpilogue) {
|
||||
file << pchEpilogue << "\n";
|
||||
}
|
||||
}
|
||||
if (language == "CXX") {
|
||||
file << "#endif // __cplusplus\n";
|
||||
}
|
||||
if (this->GetGlobalGenerator()->IsXcode()) {
|
||||
file << "#endif // CMAKE_SKIP_PRECOMPILE_HEADERS\n";
|
||||
}
|
||||
if (pchEpilogue) {
|
||||
file << pchEpilogue << "\n";
|
||||
}
|
||||
cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
|
||||
}
|
||||
cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
|
||||
}
|
||||
return inserted.first->second;
|
||||
}
|
||||
@ -3440,8 +3451,18 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config,
|
||||
return std::string();
|
||||
}
|
||||
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
|
||||
if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
|
||||
@ -3449,12 +3470,40 @@ std::string cmGeneratorTarget::GetPchSource(const std::string& config,
|
||||
} else {
|
||||
filename += ((language == "C") ? ".c" : ".cxx");
|
||||
}
|
||||
|
||||
const std::string filename_tmp = cmStrCat(filename, ".tmp");
|
||||
{
|
||||
cmGeneratedFileStream file(filename_tmp);
|
||||
file << "/* generated by CMake */\n";
|
||||
if (!pchReuseFrom) {
|
||||
{
|
||||
cmGeneratedFileStream file(filename_tmp);
|
||||
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;
|
||||
}
|
||||
|
@ -462,6 +462,8 @@ public:
|
||||
const std::string& language) const;
|
||||
std::string GetPchSource(const std::string& config,
|
||||
const std::string& language) const;
|
||||
std::string GetPchFileObject(const std::string& config,
|
||||
const std::string& language);
|
||||
|
||||
bool IsSystemIncludeDirectory(const std::string& dir,
|
||||
const std::string& config,
|
||||
@ -880,6 +882,7 @@ private:
|
||||
mutable std::set<std::string> LinkImplicitNullProperties;
|
||||
mutable std::map<std::string, std::string> PchHeaders;
|
||||
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,
|
||||
std::string const& config,
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmComputeLinkInformation.h"
|
||||
#include "cmCustomCommand.h"
|
||||
#include "cmCustomCommandGenerator.h"
|
||||
#include "cmCustomCommandLines.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorExpressionEvaluationFile.h"
|
||||
@ -2255,23 +2257,124 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target,
|
||||
return;
|
||||
}
|
||||
|
||||
const char* pchReuseFrom =
|
||||
target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
|
||||
|
||||
auto pch_sf = this->Makefile->GetOrCreateSource(
|
||||
pchSource, false, cmSourceFileLocationKind::Known);
|
||||
std::string pchFile = pchHeader;
|
||||
|
||||
if (!this->GetGlobalGenerator()->IsXcode()) {
|
||||
if (!pchReuseFrom) {
|
||||
target->AddSource(pchSource, true);
|
||||
}
|
||||
|
||||
// Exclude the pch files from linking
|
||||
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
|
||||
cmSystemTools::ReplaceString(pchFile, (lang == "C" ? ".h" : ".hxx"),
|
||||
pchExtension);
|
||||
pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
|
||||
|
||||
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());
|
||||
} 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 {
|
||||
pchFile += pchExtension;
|
||||
pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
|
||||
}
|
||||
|
||||
target->AddSource(pchSource, true);
|
||||
|
||||
for (auto& str : { std::ref(useOptionList), std::ref(createOptionList) }) {
|
||||
cmSystemTools::ReplaceString(str, "<PCH_HEADER>", pchHeader);
|
||||
cmSystemTools::ReplaceString(str, "<PCH_FILE>", pchFile);
|
||||
|
@ -1085,6 +1085,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
|
||||
MAKE_STATIC_PROP(COMPILE_FEATURES);
|
||||
MAKE_STATIC_PROP(COMPILE_OPTIONS);
|
||||
MAKE_STATIC_PROP(PRECOMPILE_HEADERS);
|
||||
MAKE_STATIC_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
|
||||
MAKE_STATIC_PROP(CUDA_PTX_COMPILATION);
|
||||
MAKE_STATIC_PROP(EXPORT_NAME);
|
||||
MAKE_STATIC_PROP(IMPORTED_GLOBAL);
|
||||
@ -1231,6 +1232,41 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
|
||||
<< impl->Name << "\")\n";
|
||||
impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
|
||||
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 {
|
||||
impl->Properties.SetProperty(prop, value);
|
||||
}
|
||||
@ -1308,6 +1344,14 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
|
||||
impl->LinkDirectoriesBacktraces.push_back(lfbt);
|
||||
}
|
||||
} 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) {
|
||||
impl->PrecompileHeadersEntries.emplace_back(value);
|
||||
cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace();
|
||||
|
@ -10,7 +10,7 @@
|
||||
bool cmTargetPrecompileHeadersCommand::InitialPass(
|
||||
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(
|
||||
|
@ -65,6 +65,19 @@ bool cmTargetPropCommandBase::HandleArguments(
|
||||
++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;
|
||||
|
||||
while (argIndex < args.size()) {
|
||||
|
@ -17,9 +17,10 @@ class cmTargetPropCommandBase : public cmCommand
|
||||
public:
|
||||
enum ArgumentFlags
|
||||
{
|
||||
NO_FLAGS = 0,
|
||||
PROCESS_BEFORE = 1,
|
||||
PROCESS_SYSTEM = 2
|
||||
NO_FLAGS = 0x0,
|
||||
PROCESS_BEFORE = 0x1,
|
||||
PROCESS_SYSTEM = 0x2,
|
||||
PROCESS_REUSE_FROM = 0x3
|
||||
};
|
||||
|
||||
bool HandleArguments(std::vector<std::string> const& args,
|
||||
|
20
Tests/RunCMake/PrecompileHeaders/PchReuseFrom.cmake
Normal file
20
Tests/RunCMake/PrecompileHeaders/PchReuseFrom.cmake
Normal 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)
|
@ -0,0 +1,2 @@
|
||||
^(|Warning #670: precompiled header file [^
|
||||
]* was not generated in this directory)$
|
18
Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake
Normal file
18
Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake
Normal 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)
|
@ -16,3 +16,5 @@ run_cmake(DisabledPch)
|
||||
run_test(PchInterface)
|
||||
run_cmake(PchPrologueEpilogue)
|
||||
run_test(SkipPrecompileHeaders)
|
||||
run_test(PchReuseFrom)
|
||||
run_test(PchReuseFromSubdir)
|
||||
|
3
Tests/RunCMake/PrecompileHeaders/empty.c
Normal file
3
Tests/RunCMake/PrecompileHeaders/empty.c
Normal file
@ -0,0 +1,3 @@
|
||||
void nothing()
|
||||
{
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#ifndef foo_h
|
||||
#define foo_h
|
||||
|
||||
extern int foo();
|
||||
int foo(void);
|
||||
|
||||
#endif
|
||||
|
3
Tests/RunCMake/PrecompileHeaders/subdir/CMakeLists.txt
Normal file
3
Tests/RunCMake/PrecompileHeaders/subdir/CMakeLists.txt
Normal 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)
|
Loading…
Reference in New Issue
Block a user