Precompile headers: Add methods to generate PCH sources

Co-Author: Daniel Pfeifer <daniel@pfeifer-mail.de>
This commit is contained in:
Cristian Adam 2019-07-13 12:07:30 +02:00 committed by Brad King
parent 375d01c680
commit b8626261e9
17 changed files with 282 additions and 4 deletions

View File

@ -96,5 +96,7 @@ else()
set(CMAKE_${lang}_ARCHIVE_FINISH_IPO
"\"${__ranlib}\" <TARGET>"
)
set(CMAKE_PCH_PROLOGUE "#pragma clang system_header")
endmacro()
endif()

View File

@ -11,6 +11,9 @@ set(__COMPILER_GNU 1)
include(Compiler/CMakeCommonCompilerMacros)
include(Internal/CMakeCheckCompilerFlag)
set(__pch_header_C "c-header")
set(__pch_header_CXX "c++-header")
macro(__compiler_gnu lang)
# Feature flags.
set(CMAKE_${lang}_VERBOSE_FLAG "-v")
@ -104,4 +107,9 @@ macro(__compiler_gnu lang)
unset(_COMPILER_ARGS)
endif()
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
set(CMAKE_PCH_EXTENSION .gch)
set(CMAKE_PCH_PROLOGUE "#pragma GCC system_header")
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Winvalid-pch -include <PCH_HEADER>)
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Winvalid-pch -x ${__pch_header_${lang}} -include <PCH_HEADER>)
endmacro()

View File

@ -32,5 +32,12 @@ else()
unset(_COMPILER_ARGS)
endif()
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "-QdM" "-P" "-Za" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
# Precompile Headers
set(CMAKE_PCH_EXTENSION .pchi)
set(CMAKE_LINK_PCH ON)
set(CMAKE_PCH_EPILOGUE "#pragma hdrstop")
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Winvalid-pch -Wno-pch-messages -pch-use <PCH_FILE> -include <PCH_HEADER>)
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Winvalid-pch -Wno-pch-messages -pch-create <PCH_FILE> -include <PCH_HEADER>)
endmacro()
endif()

View File

@ -8,6 +8,9 @@ if(__WINDOWS_CLANG)
endif()
set(__WINDOWS_CLANG 1)
set(__pch_header_C "c-header")
set(__pch_header_CXX "c++-header")
macro(__windows_compiler_clang_gnu lang)
set(CMAKE_LIBRARY_PATH_FLAG "-L")
set(CMAKE_LINK_LIBRARY_FLAG "-l")
@ -73,6 +76,10 @@ macro(__windows_compiler_clang_gnu lang)
string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG -Xclang -gcodeview ${__ADDED_FLAGS}")
set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
set(CMAKE_PCH_EXTENSION .gch)
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Winvalid-pch -include <PCH_HEADER>)
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Winvalid-pch -x ${__pch_header_${lang}} -include <PCH_HEADER>)
unset(__ADDED_FLAGS)
unset(__ADDED_FLAGS_DEBUG)
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER)

View File

@ -119,6 +119,13 @@ macro(__embarcadero_language lang)
"tlib ${CMAKE_START_TEMP_FILE}/p512 <LINK_FLAGS> /a <TARGET_QUOTED> <OBJECTS>${CMAKE_END_TEMP_FILE}"
)
# Precompile Headers
if (EMBARCADERO)
set(CMAKE_PCH_EXTENSION .pch)
set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Xclang -include-pch -Xclang <PCH_FILE>)
set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Xclang -emit-pch -Xclang -include -Xclang <PCH_HEADER>)
endif()
# Initial configuration flags.
string(APPEND CMAKE_${lang}_FLAGS_INIT " ${_tM}")
string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -Od -v")

View File

@ -329,6 +329,15 @@ macro(__windows_compiler_msvc lang)
set(CMAKE_${lang}_LINK_EXECUTABLE
"${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
set(CMAKE_PCH_EXTENSION .pch)
set(CMAKE_LINK_PCH ON)
if(MSVC_VERSION GREATER_EQUAL 1910)
# VS 2017 or greater
set(CMAKE_PCH_PROLOGUE "#pragma system_header")
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("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)

View File

@ -21,6 +21,7 @@
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionContext.h"
#include "cmGeneratorExpressionDAGChecker.h"
@ -3355,6 +3356,115 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders(
return list;
}
std::string cmGeneratorTarget::GetPchHeader(const std::string& config,
const std::string& language) const
{
if (language != "C" && language != "CXX") {
return std::string();
}
if (this->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
return std::string();
}
const auto inserted =
this->PchHeaders.insert(std::make_pair(language + config, ""));
if (inserted.second) {
const std::vector<BT<std::string>> headers =
this->GetPrecompileHeaders(config, language);
if (headers.empty()) {
return std::string();
}
std::string& filename = inserted.first->second;
if (this->GetGlobalGenerator()->IsMultiConfig()) {
filename =
cmStrCat(this->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 = cmStrCat(filename, "CMakeFiles/", this->GetName(),
".dir/cmake_pch", ((language == "C") ? ".h" : ".hxx"));
const std::string filename_tmp = cmStrCat(filename, ".tmp");
{
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;
}
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";
}
}
cmSystemTools::CopyFileIfDifferent(filename_tmp, filename);
cmSystemTools::RemoveFile(filename_tmp);
}
return inserted.first->second;
}
std::string cmGeneratorTarget::GetPchSource(const std::string& config,
const std::string& language) const
{
if (language != "C" && language != "CXX") {
return std::string();
}
const auto inserted =
this->PchSources.insert(std::make_pair(language + config, ""));
if (inserted.second) {
const std::string pchHeader = this->GetPchHeader(config, language);
if (pchHeader.empty()) {
return std::string();
}
std::string& filename = inserted.first->second;
filename = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(),
"/CMakeFiles/", this->GetName(), ".dir/cmake_pch");
// For GCC the source extension will be tranformed into .h[xx].gch
if (!this->Makefile->IsOn("CMAKE_LINK_PCH")) {
filename += ((language == "C") ? ".h.c" : ".hxx.cxx");
} else {
filename += ((language == "C") ? ".c" : ".cxx");
}
const std::string filename_tmp = cmStrCat(filename, ".tmp");
{
cmGeneratedFileStream file(filename_tmp);
file << "/* generated by CMake */\n";
}
cmSystemTools::CopyFileIfDifferent(filename_tmp, filename);
cmSystemTools::RemoveFile(filename_tmp);
}
return inserted.first->second;
}
void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const

View File

@ -458,6 +458,11 @@ public:
std::vector<BT<std::string>> GetPrecompileHeaders(
const std::string& config, const std::string& language) const;
std::string GetPchHeader(const std::string& config,
const std::string& language) const;
std::string GetPchSource(const std::string& config,
const std::string& language) const;
bool IsSystemIncludeDirectory(const std::string& dir,
const std::string& config,
const std::string& language) const;

View File

@ -18,6 +18,7 @@
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocation.h"
#include "cmSourceFileLocationKind.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateTypes.h"
@ -37,6 +38,7 @@
#include <algorithm>
#include <assert.h>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <memory>
@ -2113,6 +2115,82 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
this->AppendFlags(flags, this->EscapeForShell(rawFlag));
}
void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target,
const std::string& config)
{
const std::string lang = target->GetLinkerLanguage(config);
const std::string buildType = cmSystemTools::UpperCase(config);
const std::string pchSource = target->GetPchSource(config, lang);
const std::string pchHeader = target->GetPchHeader(config, lang);
if (pchSource.empty() || pchHeader.empty()) {
return;
}
const std::string createOptVar =
cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_CREATE_PCH");
std::string createOptionList =
this->Makefile->GetSafeDefinition(createOptVar);
const std::string useOptVar =
cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_USE_PCH");
std::string useOptionList = this->Makefile->GetSafeDefinition(useOptVar);
const std::string pchExtension =
this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
if (createOptionList.empty() || useOptionList.empty() ||
pchExtension.empty()) {
return;
}
auto pch_sf = this->Makefile->GetOrCreateSource(
pchSource, false, cmSourceFileLocationKind::Known);
std::string pchFile = pchHeader;
if (!this->GetGlobalGenerator()->IsXcode()) {
// 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());
} 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);
}
}
pch_sf->SetProperty("COMPILE_OPTIONS", createOptionList.c_str());
std::vector<cmSourceFile*> sources;
target->GetSourceFiles(sources, buildType);
for (cmSourceFile* sf : sources) {
if (pch_sf == sf || sf->GetLanguage() != lang) {
continue;
}
if (sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) {
if (this->GetGlobalGenerator()->IsXcode()) {
sf->SetProperty("COMPILE_DEFINITIONS",
"CMAKE_SKIP_PRECOMPILE_HEADERS");
}
continue;
}
if (!this->GetGlobalGenerator()->IsXcode()) {
sf->SetProperty("OBJECT_DEPENDS", pchFile.c_str());
sf->SetProperty("COMPILE_OPTIONS", useOptionList.c_str());
}
}
}
void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
cmGeneratorTarget* target,
const std::string& config,
@ -2705,6 +2783,11 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
}
}
const char* pchExtension = source.GetProperty("PCH_EXTENSION");
if (pchExtension) {
customOutputExtension = pchExtension;
}
// Remove the source extension if it is to be replaced.
if (replaceExt || customOutputExtension) {
keptSourceExtension = false;

View File

@ -124,6 +124,8 @@ public:
virtual void AppendFlags(std::string& flags, const char* newFlags) const;
virtual void AppendFlagEscape(std::string& flags,
const std::string& rawFlag) const;
void AddPchDependencies(cmGeneratorTarget* target,
const std::string& config);
void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);

View File

@ -40,6 +40,8 @@ cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
this->OSXBundleGenerator =
cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
this->LocalGenerator->AddPchDependencies(target, this->ConfigName);
}
cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =

View File

@ -42,6 +42,8 @@ cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
this->OSXBundleGenerator =
cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
this->LocalGenerator->AddPchDependencies(target, this->ConfigName);
}
cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator() =

View File

@ -239,10 +239,15 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
this->GeneratorTarget->GetExtraSources(extraSources, config);
this->OSXBundleGenerator->GenerateMacOSXContentStatements(
extraSources, this->MacOSXContentGenerator);
const char* pchExtension =
this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
std::vector<cmSourceFile const*> externalObjects;
this->GeneratorTarget->GetExternalObjects(externalObjects, config);
for (cmSourceFile const* sf : externalObjects) {
this->ExternalObjects.push_back(sf->GetFullPath());
auto const& objectFileName = sf->GetFullPath();
if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
this->ExternalObjects.push_back(objectFileName);
}
}
std::vector<cmSourceFile const*> objectSources;
this->GeneratorTarget->GetObjectSources(objectSources, config);
@ -1238,7 +1243,14 @@ void cmMakefileTargetGenerator::WriteObjectsVariable(
if (!lineContinue) {
lineContinue = "\\";
}
const char* pchExtension =
this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
for (std::string const& obj : this->Objects) {
if (cmSystemTools::StringEndsWith(obj, pchExtension)) {
continue;
}
*this->BuildFileStream << " " << lineContinue << "\n";
*this->BuildFileStream
<< cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
@ -1331,10 +1343,16 @@ private:
void cmMakefileTargetGenerator::WriteObjectsStrings(
std::vector<std::string>& objStrings, std::string::size_type limit)
{
const char* pchExtension =
this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
cmMakefileTargetGeneratorObjectStrings helper(
objStrings, this->LocalGenerator,
this->LocalGenerator->GetStateSnapshot().GetDirectory(), limit);
for (std::string const& obj : this->Objects) {
if (cmSystemTools::StringEndsWith(obj, pchExtension)) {
continue;
}
helper.Feed(obj);
}
for (std::string const& obj : this->ExternalObjects) {

View File

@ -25,6 +25,8 @@ cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
this->OSXBundleGenerator =
cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
this->LocalGenerator->AddPchDependencies(target, this->ConfigName);
}
cmMakefileUtilityTargetGenerator::~cmMakefileUtilityTargetGenerator() =

View File

@ -59,6 +59,8 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
this->OSXBundleGenerator =
cm::make_unique<cmOSXBundleGenerator>(target, this->GetConfigName());
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
GetLocalGenerator()->AddPchDependencies(target, this->GetConfigName());
}
cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;

View File

@ -790,10 +790,16 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
extraSources, this->MacOSXContentGenerator.get());
}
{
const char* pchExtension =
GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
std::vector<cmSourceFile const*> externalObjects;
this->GeneratorTarget->GetExternalObjects(externalObjects, config);
for (cmSourceFile const* sf : externalObjects) {
this->Objects.push_back(this->GetSourceFilePath(sf));
const auto objectFileName = this->GetSourceFilePath(sf);
if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
this->Objects.push_back(objectFileName);
}
}
}
@ -955,8 +961,12 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"]);
objBuild.Outputs.push_back(objectFileName);
// Add this object to the list of object files.
this->Objects.push_back(objectFileName);
const char* pchExtension =
this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION");
if (!cmSystemTools::StringEndsWith(objectFileName, pchExtension)) {
// Add this object to the list of object files.
this->Objects.push_back(objectFileName);
}
objBuild.ExplicitDeps.push_back(sourceFileName);

View File

@ -23,6 +23,7 @@
# HACK: check whether this can be removed with next iwyu release.
{ include: [ "<bits/shared_ptr.h>", private, "<memory>", public ] },
{ include: [ "<bits/std_function.h>", private, "<functional>", public ] },
{ include: [ "<bits/refwrap.h>", private, "<functional>", public ] },
{ include: [ "<bits/stdint-intn.h>", private, "<stdint.h>", public ] },
{ include: [ "<bits/stdint-uintn.h>", private, "<stdint.h>", public ] },
{ include: [ "<bits/time.h>", private, "<time.h>", public ] },
@ -73,6 +74,7 @@
# Use '-Xiwyu -v7' to see the fully qualified names that need this.
# TODO: Can this be simplified with an @-expression?
#{ symbol: [ "@std::__decay_and_strip<.*>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<char const (&)[1]>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmCommand *&>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmGeneratorTarget *&>::__type", private, "\"cmConfigure.h\"", public ] },
{ symbol: [ "std::__decay_and_strip<cmFindCommon::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },