diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index cc6ef9ce5e..fc16f2d266 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -554,6 +554,7 @@ Properties on File Sets /prop_fs/INTERFACE_SOURCES /prop_fs/SCOPE /prop_fs/SKIP_LINTING + /prop_fs/SKIP_PRECOMPILE_HEADERS /prop_fs/SKIP_UNITY_BUILD_INCLUSION /prop_fs/SOURCES /prop_fs/TYPE diff --git a/Help/prop_fs/SKIP_PRECOMPILE_HEADERS.rst b/Help/prop_fs/SKIP_PRECOMPILE_HEADERS.rst new file mode 100644 index 0000000000..cc635d2547 --- /dev/null +++ b/Help/prop_fs/SKIP_PRECOMPILE_HEADERS.rst @@ -0,0 +1,20 @@ +SKIP_PRECOMPILE_HEADERS +----------------------- + +.. versionadded:: 4.4 + +The file set sources will be skipped by :prop_tgt:`PRECOMPILE_HEADERS` feature. + +This property helps with build problems that one would run into +when using the :prop_tgt:`PRECOMPILE_HEADERS` feature. + +One example would be the usage of Objective-C (``*.m``) files, and +Objective-C++ (``*.mm``) files, which lead to compilation failure +because they are treated (in case of Ninja / Makefile generator) +as C, and CXX respectively. The precompile headers are not +compatible between languages. + +See Also +^^^^^^^^ + +* :prop_sf:`SKIP_PRECOMPILE_HEADERS` source file property diff --git a/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst b/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst index 660de3fe40..b92d5c815a 100644 --- a/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst +++ b/Help/prop_sf/SKIP_PRECOMPILE_HEADERS.rst @@ -13,3 +13,8 @@ Objective-C++ (``*.mm``) files, which lead to compilation failure because they are treated (in case of Ninja / Makefile generator) as C, and CXX respectively. The precompile headers are not compatible between languages. + +See Also +^^^^^^^^ + +* :prop_fs:`SKIP_PRECOMPILE_HEADERS` file set property diff --git a/Help/release/dev/FILE_SET-SKIP_PRECOMPILE_HEADERS.rst b/Help/release/dev/FILE_SET-SKIP_PRECOMPILE_HEADERS.rst new file mode 100644 index 0000000000..55097cd744 --- /dev/null +++ b/Help/release/dev/FILE_SET-SKIP_PRECOMPILE_HEADERS.rst @@ -0,0 +1,5 @@ +FILE_SET-SKIP_PRECOMPILE_HEADERS +-------------------------------- + +* File sets gained the support of the :prop_fs:`SKIP_PRECOMPILE_HEADERS` file + set property. diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx index e746430d3e..68a3b0e34a 100644 --- a/Source/cmFastbuildNormalTargetGenerator.cxx +++ b/Source/cmFastbuildNormalTargetGenerator.cxx @@ -490,6 +490,13 @@ void cmFastbuildNormalTargetGenerator::ComputePCH( if (srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS")) { return; } + + cmGeneratorFileSet const* const fileSet = + this->GeneratorTarget->GetFileSetForSource(Config, &srcFile); + if (fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + return; + } + // We have already computed PCH for this node. if (!node.PCHOptions.empty() || !node.PCHInputFile.empty() || !node.PCHOutputFile.empty()) { @@ -1456,10 +1463,10 @@ void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target) cmSourceFile const& srcFile = *source; std::string const pathToFile = srcFile.GetFullPath(); + cmGeneratorFileSet const* const fileSet = + GeneratorTarget->GetFileSetForSource(Config, source); bool fileUsesUnity = useUnity; if (useUnity) { - cmGeneratorFileSet const* fileSet = - GeneratorTarget->GetFileSetForSource(Config, source); // Check if the source should be added to "UnityInputExcludedFiles". if (IsExcludedFromUnity(GeneratorTarget, fileSet, srcFile)) { fileUsesUnity = false; @@ -1518,7 +1525,8 @@ void cmFastbuildNormalTargetGenerator::GenerateObjects(FastbuildTarget& target) std::string const objectListHash = hash.HashString(cmStrCat( compileOptions, staticCheckOptions, objOutDirWithPossibleSubdir, // If file does not need PCH - it must be in another ObjectList. - srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS"), + (fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + srcFile.GetProperty("SKIP_PRECOMPILE_HEADERS"), srcFile.GetLanguage())); LogMessage("ObjectList Hash: " + objectListHash); diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index ad097eb82d..2d8109474b 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -1545,7 +1545,9 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) } } - if (!pchSources.empty() && !sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + sf->GetProperty("SKIP_PRECOMPILE_HEADERS"))) { std::string pchOptions; auto pchIt = pchSources.find(sf->ResolveFullPath()); if (pchIt != pchSources.end()) { diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index b2fd3ffc4c..9346993d6b 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2395,7 +2395,8 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf, std::string pchFlags; // Add precompile headers compile options. - if (!sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!((fileSet && sf->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + sf->GetProperty("SKIP_PRECOMPILE_HEADERS"))) { if (!pchSources.empty()) { std::string pchOptions; auto pchIt = pchSources.find(sf->GetFullPath()); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 0a58f06ce9..0215e346f0 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1141,7 +1141,8 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( } } - if (sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { + if ((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + sf->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { this->AppendDefines(flagsBuild, "CMAKE_SKIP_PRECOMPILE_HEADERS", true); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 5e55942bd6..844046f641 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2746,9 +2746,12 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) for (std::string const& lang : langs) { auto langSources = std::count_if( - sources.begin(), sources.end(), [lang](cmSourceFile* sf) { + sources.begin(), sources.end(), + [&target, &config, &lang](cmSourceFile* sf) { + auto const* const fileSet = target->GetFileSetForSource(config, sf); return lang == sf->GetLanguage() && - !sf->GetProperty("SKIP_PRECOMPILE_HEADERS"); + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + sf->GetProperty("SKIP_PRECOMPILE_HEADERS")); }); if (langSources == 0) { continue; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 0c0fd42c7b..996b1cc1d1 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1531,7 +1531,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( } // Add precompile headers compile options. std::string const pchSource = gt->GetPchSource(config, lang); - if (!pchSource.empty() && !sf.GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSource.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + sf.GetProperty("SKIP_PRECOMPILE_HEADERS"))) { std::string pchOptions; if (sf.GetFullPath() == pchSource) { pchOptions = gt->GetPchCreateCompileOptions(config, lang); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 22600419bb..12c56699d0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -29,7 +29,6 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorFileSet.h" -#include "cmGeneratorFileSets.h" #include "cmGeneratorOptions.h" #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" @@ -665,6 +664,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string const config = this->GetConfigName(); std::string const configUpper = cmSystemTools::UpperCase(config); + // lookup for the associated file set, if any. + auto const* fileSet = + this->GeneratorTarget->GetFileSetForSource(config, &source); + // Add precompile headers dependencies std::vector pchArchs = this->GeneratorTarget->GetPchArchs(config, lang); @@ -682,7 +685,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } } - if (!pchSources.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + source.GetProperty("SKIP_PRECOMPILE_HEADERS"))) { for (std::string const& arch : pchArchs) { std::string const& pchHeader = this->GeneratorTarget->GetPchHeader(config, lang, arch); @@ -751,11 +756,6 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( ispcHeaderRelative, cmOutputConverter::SHELL); } - // lookup for the associated file set, if any. - auto const* fileSet = - this->GeneratorTarget->GetGeneratorFileSets()->GetFileSetForSource( - config, &source); - // Add flags from source file properties. std::string const COMPILE_FLAGS("COMPILE_FLAGS"); if (cmValue cflags = source.GetProperty(COMPILE_FLAGS)) { @@ -794,7 +794,9 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } // Add precompile headers compile options. - if (!pchSources.empty() && !source.GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + source.GetProperty("SKIP_PRECOMPILE_HEADERS"))) { std::string pchOptions; auto const pchIt = pchSources.find(source.GetFullPath()); if (pchIt != pchSources.end()) { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index a8a7713888..f2505de290 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -249,9 +249,11 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( flags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); } - if (auto const* fileSet = - this->GeneratorTarget->GetGeneratorFileSets()->GetFileSetForSource( - config, source)) { + auto const* const fileSet = + this->GeneratorTarget->GetGeneratorFileSets()->GetFileSetForSource(config, + source); + + if (fileSet) { auto options = fileSet->BelongsTo(this->GeneratorTarget) ? fileSet->GetCompileOptions(config, language) : fileSet->GetInterfaceCompileOptions(config, language); @@ -262,7 +264,9 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( } // Add precompile headers compile options. - if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + source->GetProperty("SKIP_PRECOMPILE_HEADERS"))) { std::string pchOptions; auto pchIt = pchSources.find(source->GetFullPath()); if (pchIt != pchSources.end()) { @@ -277,14 +281,13 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS)); } - auto const* fs = this->GeneratorTarget->GetFileSetForSource(config, source); - if (fs && fs->GetType() == cm::FileSetMetadata::CXX_MODULES) { + if (fileSet && fileSet->GetType() == cm::FileSetMetadata::CXX_MODULES) { if (source->GetLanguage() != "CXX"_s) { this->GetMakefile()->IssueMessage( MessageType::FATAL_ERROR, cmStrCat("Target \"", this->GeneratorTarget->Target->GetName(), "\" contains the source\n ", source->GetFullPath(), - "\nin a file set of type \"", fs->GetType(), + "\nin a file set of type \"", fileSet->GetType(), R"(" but the source is not classified as a "CXX" source.)")); } @@ -1678,7 +1681,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } } - if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + source->GetProperty("SKIP_PRECOMPILE_HEADERS"))) { for (std::string const& arch : pchArchs) { depList.push_back( this->GeneratorTarget->GetPchHeader(config, language, arch)); @@ -1832,7 +1837,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->addPoolNinjaVariable("JOB_POOL_COMPILE", config, this->GetGeneratorTarget(), source, vars); - if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) { + if (!pchSources.empty() && + !((fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + source->GetProperty("SKIP_PRECOMPILE_HEADERS"))) { auto pchIt = pchSources.find(source->GetFullPath()); if (pchIt != pchSources.end()) { this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER", config, diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index b12abd8730..8837fc0411 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2743,7 +2743,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) "\nin a \"FILE_SET TYPE ", cm::FileSetMetadata::CXX_MODULES, "\" but it is not scheduled for compilation.")); } - if (si.Source->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { + if ((fs && fs->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + si.Source->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { e2.Element("PrecompiledHeader", "NotUsing"); } if (!isCSharp && !exclude_configs.empty()) { @@ -2965,8 +2966,9 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( this->GeneratorTarget->GetLinkerLanguage(config); std::string const& pchSource = this->GeneratorTarget->GetPchSource(config, lang); - bool const skipPCH = - pchSource.empty() || sf.GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS"); + bool const skipPCH = pchSource.empty() || + (fileSet && fileSet->GetProperty("SKIP_PRECOMPILE_HEADERS")) || + sf.GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS"); bool const makePCH = (sf.GetFullPath() == pchSource); bool const useSharedPCH = !skipPCH && (lang == linkLanguage); bool const useDifferentLangPCH = !skipPCH && (lang != linkLanguage); diff --git a/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake b/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake index 60a93a07fa..2f8d2d4d7d 100644 --- a/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake +++ b/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake @@ -5,10 +5,17 @@ enable_language(CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(pch-test main.cpp non-pch.cpp) +add_executable(pch-test main.cpp non-pch1.cpp) target_precompile_headers(pch-test PRIVATE pch.h) -set_source_files_properties(non-pch.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON) +set_source_files_properties(non-pch1.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON) + +target_sources(pch-test PRIVATE FILE_SET f1 TYPE SOURCES FILES non-pch2.cpp) +set_property(FILE_SET f1 TARGET pch-test PROPERTY SKIP_PRECOMPILE_HEADERS ON) + +target_sources(pch-test PRIVATE FILE_SET f2 TYPE SOURCES FILES non-pch3.cpp) + +set_source_files_properties(non-pch3.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON) enable_testing() add_test(NAME pch-test COMMAND pch-test) diff --git a/Tests/RunCMake/PrecompileHeaders/non-pch.cpp b/Tests/RunCMake/PrecompileHeaders/non-pch1.cpp similarity index 100% rename from Tests/RunCMake/PrecompileHeaders/non-pch.cpp rename to Tests/RunCMake/PrecompileHeaders/non-pch1.cpp diff --git a/Tests/RunCMake/PrecompileHeaders/non-pch2.cpp b/Tests/RunCMake/PrecompileHeaders/non-pch2.cpp new file mode 100644 index 0000000000..df5a79f123 --- /dev/null +++ b/Tests/RunCMake/PrecompileHeaders/non-pch2.cpp @@ -0,0 +1,3 @@ +#ifdef PCH_INCLUDED +# error "PCH must not be included into this file!" +#endif diff --git a/Tests/RunCMake/PrecompileHeaders/non-pch3.cpp b/Tests/RunCMake/PrecompileHeaders/non-pch3.cpp new file mode 100644 index 0000000000..df5a79f123 --- /dev/null +++ b/Tests/RunCMake/PrecompileHeaders/non-pch3.cpp @@ -0,0 +1,3 @@ +#ifdef PCH_INCLUDED +# error "PCH must not be included into this file!" +#endif