diff options
-rw-r--r-- | Help/prop_sf/Fortran_PREPROCESS.rst | 5 | ||||
-rw-r--r-- | Help/prop_tgt/Fortran_PREPROCESS.rst | 5 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 64 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.h | 2 | ||||
-rw-r--r-- | Tests/FortranOnly/CMakeLists.txt | 46 |
5 files changed, 88 insertions, 34 deletions
diff --git a/Help/prop_sf/Fortran_PREPROCESS.rst b/Help/prop_sf/Fortran_PREPROCESS.rst index 92542d9..25ea827 100644 --- a/Help/prop_sf/Fortran_PREPROCESS.rst +++ b/Help/prop_sf/Fortran_PREPROCESS.rst @@ -8,5 +8,10 @@ should be preprocessed. If explicitly set to ``OFF`` then the file does not need to be preprocessed. If explicitly set to ``ON``, then the file does need to be preprocessed as part of the compilation step. +When using the :generator:`Ninja` generator, all source files are +first preprocessed in order to generate module dependency +information. Setting this property to ``OFF`` will make ``Ninja`` +skip this step. + Consider using the target-wide :prop_tgt:`Fortran_PREPROCESS` property if all source files in a target need to be preprocessed. diff --git a/Help/prop_tgt/Fortran_PREPROCESS.rst b/Help/prop_tgt/Fortran_PREPROCESS.rst index 069d04a..47a15c0 100644 --- a/Help/prop_tgt/Fortran_PREPROCESS.rst +++ b/Help/prop_tgt/Fortran_PREPROCESS.rst @@ -9,6 +9,11 @@ should be preprocessed. If explicitly set to ``OFF`` then the file does not need to be preprocessed. If explicitly set to ``ON``, then the file does need to be preprocessed as part of the compilation step. +When using the :generator:`Ninja` generator, all source files are +first preprocessed in order to generate module dependency +information. Setting this property to ``OFF`` will make ``Ninja`` +skip this step. + Use the source-specific :prop_sf:`Fortran_PREPROCESS` property if a single file needs to be preprocessed. If the variable :variable:`CMAKE_Fortran_PREPROCESS` is set when a target is created its diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 63e95ee..a499bc8 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -106,7 +106,16 @@ std::string cmNinjaTargetGenerator::LanguagePreprocessRule( std::string const& lang, const std::string& config) const { return cmStrCat( - lang, "_PREPROCESS__", + lang, "_PREPROCESS_SCAN__", + cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), + '_', config); +} + +std::string cmNinjaTargetGenerator::LanguageDependencyRule( + std::string const& lang, const std::string& config) const +{ + return cmStrCat( + lang, "_SCAN__", cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), '_', config); } @@ -671,6 +680,22 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, // Remove preprocessor definitions from compilation step vars.Defines = ""; } + + // Just dependency scanning for files that have preprocessing turned off + const auto scanCommand = + GetScanCommand(cmakeCmd, tdi, lang, "$in", needDyndep, "$out"); + + auto scanRule = GetPreprocessScanRule( + this->LanguageDependencyRule(lang, config), vars, "", flags, launcher, + rulePlaceholderExpander.get(), scanCommand, this->GetLocalGenerator()); + + // Write the rule for generating dependencies for the given language. + scanRule.Comment = cmStrCat("Rule for generating ", lang, + " dependencies on non-preprocessed files."); + scanRule.Description = + cmStrCat("Generating ", lang, " dependencies for $in"); + + this->GetGlobalGenerator()->AddRule(scanRule); } if (needDyndep) { @@ -1091,8 +1116,12 @@ cmNinjaBuild GetPreprocessOrScanBuild( // Tell dependency scanner where to store dyndep intermediate results. std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); - ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; - ppBuild.ImplicitOuts.push_back(ddiFile); + if (ppFileName.empty()) { + ppBuild.Outputs.push_back(ddiFile); + } else { + ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; + ppBuild.ImplicitOuts.push_back(ddiFile); + } } return ppBuild; } @@ -1237,19 +1266,34 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( bool const explicitPP = this->NeedExplicitPreprocessing(language); if (explicitPP) { - bool const compilePP = this->UsePreprocessedSource(language); + // If source/target has preprocessing turned off, we still need to + // generate an explicit dependency step + const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS"); + cmOutputConverter::FortranPreprocess preprocess = + cmOutputConverter::GetFortranPreprocess(srcpp); + if (preprocess == cmOutputConverter::FortranPreprocess::Unset) { + const auto& tgtpp = + this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS"); + preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp); + } + + bool const compilePP = this->UsePreprocessedSource(language) && + (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded); bool const compilePPWithDefines = compilePP && this->CompilePreprocessedSourceWithDefines(language); - std::string const ppFileName = - this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config)); + std::string const ppFileName = compilePP + ? this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config)) + : ""; - std::string const buildName = - this->LanguagePreprocessRule(language, config); + std::string const buildName = compilePP + ? this->LanguagePreprocessRule(language, config) + : this->LanguageDependencyRule(language, config); + const auto depExtension = compilePP ? ".pp.d" : ".d"; const std::string depFileName = this->GetLocalGenerator()->ConvertToOutputFormat( - cmStrCat(objectFileName, ".pp.d"), cmOutputConverter::SHELL); + cmStrCat(objectFileName, depExtension), cmOutputConverter::SHELL); cmNinjaBuild ppBuild = GetPreprocessOrScanBuild( buildName, ppFileName, compilePP, compilePPWithDefines, objBuild, vars, @@ -1276,7 +1320,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } if (firstForConfig && needDyndep) { - const std::string& ddiFile = ppBuild.ImplicitOuts.back(); + std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); this->Configs[config].DDIFiles[language].push_back(ddiFile); } diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 8678dc3..2e0a511 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -70,6 +70,8 @@ protected: const std::string& config) const; std::string LanguagePreprocessRule(std::string const& lang, const std::string& config) const; + std::string LanguageDependencyRule(std::string const& lang, + const std::string& config) const; bool NeedExplicitPreprocessing(std::string const& lang) const; std::string LanguageDyndepRule(std::string const& lang, const std::string& config) const; diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt index 59f139b..d24df2d 100644 --- a/Tests/FortranOnly/CMakeLists.txt +++ b/Tests/FortranOnly/CMakeLists.txt @@ -135,29 +135,27 @@ if(test_pp_flags) set_property(SOURCE preprocess3.f PROPERTY Fortran_PREPROCESS ON) endif() -if(NOT CMAKE_GENERATOR MATCHES "Ninja") - # Test that neither the compiler nor CMake performs unnecessary preprocessing. - add_library(no_preprocess_target_lower STATIC no_preprocess_target_lower.f) - target_compile_options(no_preprocess_target_lower PRIVATE -DINTEGER=nonsense) - set_property(TARGET no_preprocess_target_lower PROPERTY Fortran_PREPROCESS OFF) - add_library(no_preprocess_source_lower STATIC no_preprocess_source_lower.f) - target_compile_options(no_preprocess_source_lower PRIVATE -DINTEGER=nonsense) - set_property(SOURCE no_preprocess_source_lower.f PROPERTY Fortran_PREPROCESS OFF) - - # Test that we can explicitly not preprocess a target or source. - # This will not work on certain compilers due to either missing a - # "don't preprocess" flag, or due to choice of file extension. - if(test_pp_flags AND NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|SunPro|XL)") - add_library(no_preprocess_target STATIC no_preprocess_target_upper.F) - target_compile_options(no_preprocess_target PRIVATE -DINTEGER=nonsense) - add_library(no_preprocess_source STATIC no_preprocess_source_upper.F) - target_compile_options(no_preprocess_source PRIVATE -DINTEGER=nonsense) - if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "Cray" - AND NOT "${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" STREQUAL "Intel;MSVC") - target_sources(no_preprocess_target PRIVATE no_preprocess_target_fpp.fpp) - target_sources(no_preprocess_source PRIVATE no_preprocess_source_fpp.fpp) - endif() - set_property(TARGET no_preprocess_target PROPERTY Fortran_PREPROCESS OFF) - set_property(SOURCE no_preprocess_source_upper.F no_preprocess_source_fpp.fpp PROPERTY Fortran_PREPROCESS OFF) +# Test that neither the compiler nor CMake performs unnecessary preprocessing. +add_library(no_preprocess_target_lower STATIC no_preprocess_target_lower.f) +target_compile_options(no_preprocess_target_lower PRIVATE -DINTEGER=nonsense) +set_property(TARGET no_preprocess_target_lower PROPERTY Fortran_PREPROCESS OFF) +add_library(no_preprocess_source_lower STATIC no_preprocess_source_lower.f) +target_compile_options(no_preprocess_source_lower PRIVATE -DINTEGER=nonsense) +set_property(SOURCE no_preprocess_source_lower.f PROPERTY Fortran_PREPROCESS OFF) + +# Test that we can explicitly not preprocess a target or source. +# This will not work on certain compilers due to either missing a +# "don't preprocess" flag, or due to choice of file extension. +if(test_pp_flags AND NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|SunPro|XL)") + add_library(no_preprocess_target STATIC no_preprocess_target_upper.F) + target_compile_options(no_preprocess_target PRIVATE -DINTEGER=nonsense) + add_library(no_preprocess_source STATIC no_preprocess_source_upper.F) + target_compile_options(no_preprocess_source PRIVATE -DINTEGER=nonsense) + if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "Cray" + AND NOT "${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" STREQUAL "Intel;MSVC") + target_sources(no_preprocess_target PRIVATE no_preprocess_target_fpp.fpp) + target_sources(no_preprocess_source PRIVATE no_preprocess_source_fpp.fpp) endif() + set_property(TARGET no_preprocess_target PROPERTY Fortran_PREPROCESS OFF) + set_property(SOURCE no_preprocess_source_upper.F no_preprocess_source_fpp.fpp PROPERTY Fortran_PREPROCESS OFF) endif() |