|
|
@@ -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
|