diff options
author | Brad King <brad.king@kitware.com> | 2019-08-29 13:37:26 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2019-08-29 13:38:21 (GMT) |
commit | fa36e2151d25358c7946a53c4440f0487210770d (patch) | |
tree | 8909e40db9d7a8c54ea047d5ea6d92f2592a3264 /Source | |
parent | 030570d71ff8b15a7242203f2638d3b77af755b9 (diff) | |
parent | 8da78d4efe0e4d0ef8708ecd94cf886c3f7d9ae4 (diff) | |
download | CMake-fa36e2151d25358c7946a53c4440f0487210770d.zip CMake-fa36e2151d25358c7946a53c4440f0487210770d.tar.gz CMake-fa36e2151d25358c7946a53c4440f0487210770d.tar.bz2 |
Merge topic 'precompile-headers'
8da78d4efe Precompile headers: Update documentation
5772930164 Precompile headers: Add unit tests
519606704e Precompile headers: Add support for Visual Studio generators
28be170fbc Precompile headers: Add support for Xcode generator
b8626261e9 Precompile headers: Add methods to generate PCH sources
375d01c680 PCH: add example/test
9b6797e71d PCH: add target_precompile_headers command
0467a2f91b PCH: add PRECOMPILE_HEADERS to special properties
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Daniel Pfeifer <daniel@pfeifer-mail.de>
Acked-by: Ivan171 <heavenandhell171@gmail.com>
Acked-by: Stanislav Ershov <digital.stream.of.mind@gmail.com>
Acked-by: Steve Mokris <smokris@softpixel.com>
Acked-by: Evgeniy Dushistov <dushistov@mail.ru>
Acked-by: Danila Malyutin <flashmozzg@gmail.com>
Acked-by: Viktor Kirilov <vik.kirilov@gmail.com>
Acked-by: Lucas Zhao <zhaopf6@163.com>
Merge-request: !3553
Diffstat (limited to 'Source')
22 files changed, 462 insertions, 6 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 30bf83a..2ff6c8c 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -654,6 +654,8 @@ set(SRCS cmTargetLinkDirectoriesCommand.h cmTargetLinkLibrariesCommand.cxx cmTargetLinkLibrariesCommand.h + cmTargetPrecompileHeadersCommand.cxx + cmTargetPrecompileHeadersCommand.h cmTargetPropCommandBase.cxx cmTargetPropCommandBase.h cmTargetSourcesCommand.cxx diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 0285525..702b743 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -78,6 +78,7 @@ #include "cmTargetCompileOptionsCommand.h" #include "cmTargetIncludeDirectoriesCommand.h" #include "cmTargetLinkLibrariesCommand.h" +#include "cmTargetPrecompileHeadersCommand.h" #include "cmTargetSourcesCommand.h" #include "cmTryCompileCommand.h" #include "cmTryRunCommand.h" @@ -276,6 +277,9 @@ void GetProjectCommands(cmState* state) state->AddBuiltinCommand("try_compile", cm::make_unique<cmTryCompileCommand>()); state->AddBuiltinCommand("try_run", cm::make_unique<cmTryRunCommand>()); + state->AddBuiltinCommand( + "target_precompile_headers", + cm::make_unique<cmTargetPrecompileHeadersCommand>()); #if !defined(CMAKE_BOOTSTRAP) state->AddBuiltinCommand("add_compile_definitions", diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 8a1a305..9f0396b 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -91,6 +91,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateInterfaceProperty("INTERFACE_COMPILE_OPTIONS", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); + this->PopulateInterfaceProperty("INTERFACE_PRECOMPILE_HEADERS", gte, + cmGeneratorExpression::BuildInterface, + properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", gte, cmGeneratorExpression::BuildInterface, properties, missingTargets); diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index 6d7d6ef..b72a40f 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -29,7 +29,8 @@ class cmGeneratorTarget; SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \ SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \ SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \ - SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS) + SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS) \ + SELECT(F, EvaluatingPrecompileHeaders, PRECOMPILE_HEADERS) #define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \ CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 1d64f1c..cc37232 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -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" @@ -278,6 +279,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) , DebugCompileDefinitionsDone(false) , DebugLinkOptionsDone(false) , DebugLinkDirectoriesDone(false) + , DebugPrecompileHeadersDone(false) , DebugSourcesDone(false) , LinkImplementationLanguageIsContextDependent(true) , UtilityItemsDone(false) @@ -312,6 +314,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) t->GetLinkDirectoriesBacktraces(), this->LinkDirectoriesEntries); + CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(), + t->GetPrecompileHeadersBacktraces(), + this->PrecompileHeadersEntries); + CreatePropertyGeneratorExpressions(t->GetSourceEntries(), t->GetSourceBacktraces(), this->SourceEntries, true); @@ -327,6 +333,7 @@ cmGeneratorTarget::~cmGeneratorTarget() cmDeleteAll(this->CompileDefinitionsEntries); cmDeleteAll(this->LinkOptionsEntries); cmDeleteAll(this->LinkDirectoriesEntries); + cmDeleteAll(this->PrecompileHeadersEntries); cmDeleteAll(this->SourceEntries); cmDeleteAll(this->LinkInformation); } @@ -3312,6 +3319,152 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( return list; } +std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( + const std::string& config, const std::string& language) const +{ + std::unordered_set<std::string> uniqueOptions; + + cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS", + nullptr, nullptr); + + std::vector<std::string> debugProperties; + const char* debugProp = + this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES"); + if (debugProp) { + cmExpandList(debugProp, debugProperties); + } + + bool debugDefines = !this->DebugPrecompileHeadersDone && + std::find(debugProperties.begin(), debugProperties.end(), + "PRECOMPILE_HEADERS") != debugProperties.end(); + + if (this->GlobalGenerator->GetConfigureDoneCMP0026()) { + this->DebugPrecompileHeadersDone = true; + } + + std::vector<EvaluatedTargetPropertyEntry> entries = + EvaluateTargetPropertyEntries(this, config, language, &dagChecker, + this->PrecompileHeadersEntries); + + AddInterfaceEntries(this, config, "INTERFACE_PRECOMPILE_HEADERS", language, + &dagChecker, entries); + + std::vector<BT<std::string>> list; + processOptions(this, entries, list, uniqueOptions, debugDefines, + "precompile headers", OptionsParse::None); + + 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 diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 3874738..4701071 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -455,6 +455,14 @@ public: std::vector<BT<std::string>> GetLinkDepends( std::string const& config, std::string const& language) const; + 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; @@ -867,8 +875,11 @@ private: std::vector<TargetPropertyEntry*> CompileDefinitionsEntries; std::vector<TargetPropertyEntry*> LinkOptionsEntries; std::vector<TargetPropertyEntry*> LinkDirectoriesEntries; + std::vector<TargetPropertyEntry*> PrecompileHeadersEntries; std::vector<TargetPropertyEntry*> SourceEntries; mutable std::set<std::string> LinkImplicitNullProperties; + mutable std::map<std::string, std::string> PchHeaders; + mutable std::map<std::string, std::string> PchSources; void ExpandLinkItems(std::string const& prop, std::string const& value, std::string const& config, @@ -922,6 +933,7 @@ private: mutable bool DebugCompileDefinitionsDone; mutable bool DebugLinkOptionsDone; mutable bool DebugLinkDirectoriesDone; + mutable bool DebugPrecompileHeadersDone; mutable bool DebugSourcesDone; mutable bool LinkImplementationLanguageIsContextDependent; mutable bool UtilityItemsDone; diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index cbab329..e4cd73f 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -110,6 +110,13 @@ public: bool IsIncludeExternalMSProjectSupported() const override { return true; } + /** Get encoding used by generator for generated source files + */ + codecvt::Encoding GetMakefileEncoding() const override + { + return codecvt::ANSI; + } + class TargetSet : public std::set<cmGeneratorTarget const*> { }; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index a204fe0..427ab44 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2374,6 +2374,16 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION", this->CreateString(vso.str())); } + + // Precompile Headers + std::string pchHeader = gtgt->GetPchHeader(configName, llang); + if (!pchHeader.empty()) { + buildSettings->AddAttribute("GCC_PREFIX_HEADER", + this->CreateString(pchHeader)); + buildSettings->AddAttribute("GCC_PRECOMPILE_PREFIX_HEADER", + this->CreateString("YES")); + } + // put this last so it can override existing settings // Convert "XCODE_ATTRIBUTE_*" properties directly. { @@ -2829,6 +2839,8 @@ bool cmGlobalXCodeGenerator::CreateGroups( continue; } + generator->AddPchDependencies(gtgt, ""); + auto addSourceToGroup = [this, mf, gtgt, &sourceGroups](std::string const& source) { cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2e40543..7177694 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -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> @@ -2124,6 +2126,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, @@ -2716,6 +2794,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; diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 455e491..f63fe0f 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -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); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 2c91974..795cee4 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1320,6 +1320,8 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, const std::string& libName, cmGeneratorTarget* target) { + this->AddPchDependencies(target, ""); + std::vector<std::string> configs; this->Makefile->GetConfigurations(configs); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 7bc05b1..bebd5c4 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -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() = diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 252279f..4244402 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -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() = diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index f99fe4e..90d8ea9 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -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) { diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 8ed6be5..556191f 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -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() = diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 17a5527..0e3aa3a 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -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; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 3d3d80d..29e8b74 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -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); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 5311d38..2a09b43 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -190,6 +190,8 @@ public: std::vector<cmListFileBacktrace> CompileFeaturesBacktraces; std::vector<std::string> CompileDefinitionsEntries; std::vector<cmListFileBacktrace> CompileDefinitionsBacktraces; + std::vector<std::string> PrecompileHeadersEntries; + std::vector<cmListFileBacktrace> PrecompileHeadersBacktraces; std::vector<std::string> SourceEntries; std::vector<cmListFileBacktrace> SourceBacktraces; std::vector<std::string> LinkOptionsEntries; @@ -349,6 +351,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("Swift_LANGUAGE_VERSION"); initProp("Swift_MODULE_DIRECTORY"); initProp("VS_JUST_MY_CODE_DEBUGGING"); + initProp("DISABLE_PRECOMPILE_HEADERS"); #ifdef __APPLE__ if (this->GetGlobalGenerator()->IsXcode()) { initProp("XCODE_GENERATE_SCHEME"); @@ -1018,6 +1021,16 @@ cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const return cmMakeRange(impl->CompileDefinitionsBacktraces); } +cmStringRange cmTarget::GetPrecompileHeadersEntries() const +{ + return cmMakeRange(impl->PrecompileHeadersEntries); +} + +cmBacktraceRange cmTarget::GetPrecompileHeadersBacktraces() const +{ + return cmMakeRange(impl->PrecompileHeadersBacktraces); +} + cmStringRange cmTarget::GetSourceEntries() const { return cmMakeRange(impl->SourceEntries); @@ -1069,6 +1082,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) MAKE_STATIC_PROP(COMPILE_DEFINITIONS); MAKE_STATIC_PROP(COMPILE_FEATURES); MAKE_STATIC_PROP(COMPILE_OPTIONS); + MAKE_STATIC_PROP(PRECOMPILE_HEADERS); MAKE_STATIC_PROP(CUDA_PTX_COMPILATION); MAKE_STATIC_PROP(EXPORT_NAME); MAKE_STATIC_PROP(IMPORTED_GLOBAL); @@ -1167,6 +1181,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->LinkDirectoriesBacktraces.push_back(lfbt); } + } else if (prop == propPRECOMPILE_HEADERS) { + impl->PrecompileHeadersEntries.clear(); + impl->PrecompileHeadersBacktraces.clear(); + if (value) { + impl->PrecompileHeadersEntries.emplace_back(value); + cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); + impl->PrecompileHeadersBacktraces.push_back(lfbt); + } } else if (prop == propLINK_LIBRARIES) { impl->LinkImplementationPropertyEntries.clear(); impl->LinkImplementationPropertyBacktraces.clear(); @@ -1283,6 +1305,12 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value, cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); impl->LinkDirectoriesBacktraces.push_back(lfbt); } + } else if (prop == "PRECOMPILE_HEADERS") { + if (value && *value) { + impl->PrecompileHeadersEntries.emplace_back(value); + cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); + impl->PrecompileHeadersBacktraces.push_back(lfbt); + } } else if (prop == "LINK_LIBRARIES") { if (value && *value) { cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); @@ -1394,6 +1422,13 @@ void cmTarget::InsertLinkDirectory(std::string const& entry, impl->LinkDirectoriesBacktraces.insert(btPosition, bt); } +void cmTarget::InsertPrecompileHeader(std::string const& entry, + cmListFileBacktrace const& bt) +{ + impl->PrecompileHeadersEntries.push_back(entry); + impl->PrecompileHeadersBacktraces.push_back(bt); +} + static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, const char* value, cmMakefile* context, @@ -1514,6 +1549,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const MAKE_STATIC_PROP(COMPILE_DEFINITIONS); MAKE_STATIC_PROP(LINK_OPTIONS); MAKE_STATIC_PROP(LINK_DIRECTORIES); + MAKE_STATIC_PROP(PRECOMPILE_HEADERS); MAKE_STATIC_PROP(IMPORTED); MAKE_STATIC_PROP(IMPORTED_GLOBAL); MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES); @@ -1529,6 +1565,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const propCOMPILE_FEATURES, propCOMPILE_OPTIONS, propCOMPILE_DEFINITIONS, + propPRECOMPILE_HEADERS, propLINK_OPTIONS, propLINK_DIRECTORIES, propIMPORTED, @@ -1617,6 +1654,15 @@ const char* cmTarget::GetProperty(const std::string& prop) const output = cmJoin(impl->Utilities, ";"); return output.c_str(); } + if (prop == propPRECOMPILE_HEADERS) { + if (impl->PrecompileHeadersEntries.empty()) { + return nullptr; + } + + static std::string output; + output = cmJoin(impl->PrecompileHeadersEntries, ";"); + return output.c_str(); + } if (prop == propIMPORTED) { return this->IsImported() ? "TRUE" : "FALSE"; } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 2b75879..783c278 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -216,6 +216,8 @@ public: cmListFileBacktrace const& bt, bool before = false); void InsertLinkDirectory(std::string const& entry, cmListFileBacktrace const& bt, bool before = false); + void InsertPrecompileHeader(std::string const& entry, + cmListFileBacktrace const& bt); void AppendBuildInterfaceIncludes(); @@ -237,6 +239,9 @@ public: cmStringRange GetCompileDefinitionsEntries() const; cmBacktraceRange GetCompileDefinitionsBacktraces() const; + cmStringRange GetPrecompileHeadersEntries() const; + cmBacktraceRange GetPrecompileHeadersBacktraces() const; + cmStringRange GetSourceEntries() const; cmBacktraceRange GetSourceBacktraces() const; diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx new file mode 100644 index 0000000..30cf1be --- /dev/null +++ b/Source/cmTargetPrecompileHeadersCommand.cxx @@ -0,0 +1,36 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmTargetPrecompileHeadersCommand.h" + +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmTarget.h" + +bool cmTargetPrecompileHeadersCommand::InitialPass( + std::vector<std::string> const& args, cmExecutionStatus&) +{ + return this->HandleArguments(args, "PRECOMPILE_HEADERS"); +} + +void cmTargetPrecompileHeadersCommand::HandleMissingTarget( + const std::string& name) +{ + const std::string e = + cmStrCat("Cannot specify precompile headers for target \"", name, + "\" which is not built by this project."); + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e); +} + +std::string cmTargetPrecompileHeadersCommand::Join( + const std::vector<std::string>& content) +{ + return cmJoin(content, ";"); +} + +bool cmTargetPrecompileHeadersCommand::HandleDirectContent( + cmTarget* tgt, const std::vector<std::string>& content, bool, bool) +{ + tgt->AppendProperty("PRECOMPILE_HEADERS", this->Join(content).c_str()); + return true; +} diff --git a/Source/cmTargetPrecompileHeadersCommand.h b/Source/cmTargetPrecompileHeadersCommand.h new file mode 100644 index 0000000..1ddf2af --- /dev/null +++ b/Source/cmTargetPrecompileHeadersCommand.h @@ -0,0 +1,41 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmTargetPrecompileHeadersCommand_h +#define cmTargetPrecompileHeadersCommand_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <string> +#include <vector> + +#include "cm_memory.hxx" + +#include "cmCommand.h" + +#include "cmTargetPropCommandBase.h" + +class cmExecutionStatus; +class cmTarget; + +class cmTargetPrecompileHeadersCommand : public cmTargetPropCommandBase +{ +public: + std::unique_ptr<cmCommand> Clone() override + { + return cm::make_unique<cmTargetPrecompileHeadersCommand>(); + } + + bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus& status) override; + +private: + void HandleMissingTarget(const std::string& name) override; + + bool HandleDirectContent(cmTarget* tgt, + const std::vector<std::string>& content, + bool prepend, bool system) override; + + std::string Join(const std::vector<std::string>& content) override; +}; + +#endif diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 44614a3..b4f05c7 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -249,6 +249,8 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() == this->Makefile->GetCurrentBinaryDirectory()); + + this->LocalGenerator->AddPchDependencies(target, ""); } cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() @@ -2148,6 +2150,9 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) { this->OutputSourceSpecificFlags(e2, si.Source); } + if (si.Source->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { + e2.Element("PrecompiledHeader", "NotUsing"); + } if (!exclude_configs.empty()) { this->WriteExcludeFromBuild(e2, exclude_configs); } @@ -2629,6 +2634,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->IPOEnabledConfigurations.insert(configName); } + // Precompile Headers + std::string pchHeader = + this->GeneratorTarget->GetPchHeader(configName, linkLanguage); + if (this->MSTools && vcxproj == this->ProjectType && pchHeader.empty()) { + clOptions.AddFlag("PrecompiledHeader", "NotUsing"); + } + // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); if (this->MSTools) { @@ -2644,7 +2656,6 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // replace this setting with "true" below. clOptions.AddFlag("UseFullPaths", "false"); } - clOptions.AddFlag("PrecompiledHeader", "NotUsing"); clOptions.AddFlag("AssemblerListingLocation", "$(IntDir)"); } } |