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> [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.
|
||||||
|
@ -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
|
||||||
|
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)
|
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)
|
||||||
|
@ -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()) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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(
|
||||||
|
@ -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()) {
|
||||||
|
@ -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,
|
||||||
|
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_test(PchInterface)
|
||||||
run_cmake(PchPrologueEpilogue)
|
run_cmake(PchPrologueEpilogue)
|
||||||
run_test(SkipPrecompileHeaders)
|
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
|
#ifndef foo_h
|
||||||
#define foo_h
|
#define foo_h
|
||||||
|
|
||||||
extern int foo();
|
int foo(void);
|
||||||
|
|
||||||
#endif
|
#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