diff options
author | Cristian Adam <cristian.adam@gmail.com> | 2019-10-03 19:53:42 (GMT) |
---|---|---|
committer | Cristian Adam <cristian.adam@gmail.com> | 2019-10-03 20:58:55 (GMT) |
commit | 1144a4fa47d467ac3bd2f70ed2dffd04734d53a7 (patch) | |
tree | 06ccd93a750afc2e28de0d888653f6db93c0e74e | |
parent | 3247506662684003e19d9552ab5ce70643808f4d (diff) | |
download | CMake-1144a4fa47d467ac3bd2f70ed2dffd04734d53a7.zip CMake-1144a4fa47d467ac3bd2f70ed2dffd04734d53a7.tar.gz CMake-1144a4fa47d467ac3bd2f70ed2dffd04734d53a7.tar.bz2 |
PCH: Add multi-language PCH generation support
If the target has C files, it will get a C PCH file.
The same for C++ files. The linker language is no
longer used to determine which language to use for
PCH.
Fixes: #19790
-rw-r--r-- | Source/cmLocalGenerator.cxx | 301 | ||||
-rw-r--r-- | Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake | 17 | ||||
-rw-r--r-- | Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake | 9 | ||||
-rw-r--r-- | Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake | 1 |
4 files changed, 185 insertions, 143 deletions
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 154d509..ae5139a 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2254,185 +2254,200 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags, 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; - } + std::vector<cmSourceFile*> sources; + target->GetSourceFiles(sources, buildType); - const std::string createOptVar = - cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_CREATE_PCH"); - std::string createOptionList = - this->Makefile->GetSafeDefinition(createOptVar); + for (const std::string& lang : { "C", "CXX" }) { + auto langSources = + std::count_if(sources.begin(), sources.end(), [lang](cmSourceFile* sf) { + return lang == sf->GetLanguage(); + }); + if (langSources == 0) { + continue; + } - const std::string useOptVar = - cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_USE_PCH"); - std::string useOptionList = this->Makefile->GetSafeDefinition(useOptVar); + const std::string pchSource = target->GetPchSource(config, lang); + const std::string pchHeader = target->GetPchHeader(config, lang); - const std::string pchExtension = - this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION"); + if (pchSource.empty() || pchHeader.empty()) { + continue; + } - if (createOptionList.empty() || useOptionList.empty() || - pchExtension.empty()) { - return; - } + const std::string createOptVar = + cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_CREATE_PCH"); + std::string createOptionList = + this->Makefile->GetSafeDefinition(createOptVar); - const char* pchReuseFrom = - target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); + const std::string useOptVar = + cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_USE_PCH"); + std::string useOptionList = this->Makefile->GetSafeDefinition(useOptVar); - auto pch_sf = this->Makefile->GetOrCreateSource( - pchSource, false, cmSourceFileLocationKind::Known); - std::string pchFile = pchHeader; + const std::string pchExtension = + this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION"); - if (!this->GetGlobalGenerator()->IsXcode()) { - if (!pchReuseFrom) { - target->AddSource(pchSource, true); + if (createOptionList.empty() || useOptionList.empty() || + pchExtension.empty()) { + continue; } - // Exclude the pch files from linking - if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { + const char* pchReuseFrom = + target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM"); - 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; - }; + auto pch_sf = this->Makefile->GetOrCreateSource( + pchSource, false, cmSourceFileLocationKind::Known); + std::string pchFile = pchHeader; + if (!this->GetGlobalGenerator()->IsXcode()) { if (!pchReuseFrom) { - std::string pchSourceObj = target->GetPchFileObject(config, lang); + target->AddSource(pchSource, true); + } - pchFile = replaceExtension(pchSourceObj, pchExtension); - pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str()); - } else { - auto reuseTarget = - this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom); + // Exclude the pch files from linking + if (this->Makefile->IsOn("CMAKE_LINK_PCH")) { - if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { + 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; + }; - const std::string pdb_prefix = - this->GetGlobalGenerator()->IsMultiConfig() - ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/") - : ""; + if (!pchReuseFrom) { + std::string pchSourceObj = target->GetPchFileObject(config, lang); - const std::string target_compile_pdb_dir = - cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), - "/", target->GetName(), ".dir/"); + pchFile = replaceExtension(pchSourceObj, pchExtension); + pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str()); + } else { + auto reuseTarget = + this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom); - const std::string copy_script = - cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake"); - cmGeneratedFileStream file(copy_script); + if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) { - 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 pdb_prefix = + this->GetGlobalGenerator()->IsMultiConfig() + ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/") + : ""; - const std::string to_dir = cmStrCat( + const std::string target_compile_pdb_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"; - } + 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, - cmCustomCommandType::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()); + 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, + cmCustomCommandType::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()); - } + target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", + target_compile_pdb_dir.c_str()); + } - std::string pchSourceObj = reuseTarget->GetPchFileObject(config, lang); + std::string pchSourceObj = + reuseTarget->GetPchFileObject(config, lang); - // Link to the pch object file - target->Target->SetProperty( - "LINK_FLAGS", - this->ConvertToOutputFormat(pchSourceObj, SHELL).c_str()); + // Link to the pch object file + target->Target->SetProperty( + "LINK_FLAGS", + this->ConvertToOutputFormat(pchSourceObj, SHELL).c_str()); - pchFile = replaceExtension(pchSourceObj, pchExtension); + pchFile = replaceExtension(pchSourceObj, pchExtension); + } + } else { + pchFile += pchExtension; + pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); } - } else { - pchFile += pchExtension; - pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str()); - } - - // Add pchHeader to source files, which will - // be grouped as "Precompile Header File" - auto pchHeader_sf = this->Makefile->GetOrCreateSource( - pchHeader, false, cmSourceFileLocationKind::Known); - std::string err; - pchHeader_sf->ResolveFullPath(&err); - target->AddSource(pchHeader); - for (auto& str : { std::ref(useOptionList), std::ref(createOptionList) }) { - cmSystemTools::ReplaceString(str, "<PCH_HEADER>", pchHeader); - cmSystemTools::ReplaceString(str, "<PCH_FILE>", pchFile); + // Add pchHeader to source files, which will + // be grouped as "Precompile Header File" + auto pchHeader_sf = this->Makefile->GetOrCreateSource( + pchHeader, false, cmSourceFileLocationKind::Known); + std::string err; + pchHeader_sf->ResolveFullPath(&err); + target->AddSource(pchHeader); + + 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()); + 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; - } + 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"); + if (sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { + if (this->GetGlobalGenerator()->IsXcode()) { + sf->SetProperty("COMPILE_DEFINITIONS", + "CMAKE_SKIP_PRECOMPILE_HEADERS"); + } + continue; } - continue; - } - if (!this->GetGlobalGenerator()->IsXcode()) { - sf->AppendProperty("OBJECT_DEPENDS", pchFile.c_str()); - sf->AppendProperty("OBJECT_DEPENDS", pchHeader.c_str()); - sf->SetProperty("COMPILE_OPTIONS", useOptionList.c_str()); + if (!this->GetGlobalGenerator()->IsXcode()) { + sf->AppendProperty("OBJECT_DEPENDS", pchFile.c_str()); + sf->AppendProperty("OBJECT_DEPENDS", pchHeader.c_str()); + sf->SetProperty("COMPILE_OPTIONS", useOptionList.c_str()); + } } } } diff --git a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake new file mode 100644 index 0000000..5a304f5 --- /dev/null +++ b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake @@ -0,0 +1,17 @@ +if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG) + set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/CMakeFiles/foobar.dir/cmake_pch.h") + set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/CMakeFiles/foobar.dir/cmake_pch.hxx") +else() + set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h") + set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.hxx") +endif() + +if (NOT EXISTS ${foobar_pch_h_header}) + set(RunCMake_TEST_FAILED "Generated foobar C pch header ${foobar_pch_h_header} does not exist") + return() +endif() + +if (NOT EXISTS ${foobar_pch_hxx_header}) + set(RunCMake_TEST_FAILED "Generated foobar C++ pch header ${foobar_pch_hxx_header} does not exist") + return() +endif() diff --git a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake new file mode 100644 index 0000000..4face95 --- /dev/null +++ b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) +project(PchMultilanguage C CXX) + +add_executable(foobar + foo.c + main.cpp +) +target_include_directories(foobar PUBLIC include) +target_precompile_headers(foobar PRIVATE "<stddef.h>") diff --git a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake index bd3b1b8..ec13663 100644 --- a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake +++ b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake @@ -18,3 +18,4 @@ run_cmake(PchPrologueEpilogue) run_test(SkipPrecompileHeaders) run_test(PchReuseFrom) run_test(PchReuseFromSubdir) +run_cmake(PchMultilanguage) |