From 1f1894af1fb263762c062c55fce28b5f9678dc5e Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 8 May 2023 17:04:46 -0400 Subject: Ninja: Fix Fortran INCLUDE directive dependencies when not preprocessing Since commit b0a6161190 (Fortran: Add Fortran_PREPROCESS property, 2020-04-24, v3.18.0-rc1~116^2~3), if `Fortran_PREPROCESS` is `OFF`, the Ninja generator does not properly detect dependencies on sources loaded via the Fortran INCLUDE directive. Fix this and add a test. --- Source/cmGlobalNinjaGenerator.cxx | 14 +++++++++++--- Source/cmNinjaTargetGenerator.cxx | 15 ++++++++++++--- .../BuildDepends/FortranInclude-build1-stderr.txt | 1 + .../BuildDepends/FortranInclude-build2-stderr.txt | 1 + Tests/RunCMake/BuildDepends/FortranInclude.cmake | 20 ++++++++++++++++++++ .../RunCMake/BuildDepends/FortranInclude.step1.cmake | 2 ++ .../RunCMake/BuildDepends/FortranInclude.step2.cmake | 2 ++ .../BuildDepends/FortranIncludeNoPreprocess.f | 3 +++ .../RunCMake/BuildDepends/FortranIncludePreprocess.F | 3 +++ Tests/RunCMake/BuildDepends/RunCMakeTest.cmake | 4 ++++ Tests/RunCMake/CMakeLists.txt | 4 ++++ 11 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 Tests/RunCMake/BuildDepends/FortranInclude-build1-stderr.txt create mode 100644 Tests/RunCMake/BuildDepends/FortranInclude-build2-stderr.txt create mode 100644 Tests/RunCMake/BuildDepends/FortranInclude.cmake create mode 100644 Tests/RunCMake/BuildDepends/FortranInclude.step1.cmake create mode 100644 Tests/RunCMake/BuildDepends/FortranInclude.step2.cmake create mode 100644 Tests/RunCMake/BuildDepends/FortranIncludeNoPreprocess.f create mode 100644 Tests/RunCMake/BuildDepends/FortranIncludePreprocess.F diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index f3927b41c7..7626fa3ddf 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -2227,7 +2227,7 @@ Compilation of source files within a target is split into the following steps: command = gfortran -cpp $DEFINES $INCLUDES $FLAGS -E $in -o $out && cmake -E cmake_ninja_depends \ --tdi=FortranDependInfo.json --lang=Fortran \ - --src=$out --dep=$DEP_FILE --obj=$OBJ_FILE \ + --src=$out --out=$out --dep=$DEP_FILE --obj=$OBJ_FILE \ --ddi=$DYNDEP_INTERMEDIATE_FILE build src.f90-pp.f90 | src.f90.o.ddi: Fortran_PREPROCESS src.f90 @@ -2304,6 +2304,7 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, { std::string arg_tdi; std::string arg_src; + std::string arg_out; std::string arg_dep; std::string arg_obj; std::string arg_ddi; @@ -2313,6 +2314,8 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, arg_tdi = arg.substr(6); } else if (cmHasLiteralPrefix(arg, "--src=")) { arg_src = arg.substr(6); + } else if (cmHasLiteralPrefix(arg, "--out=")) { + arg_out = arg.substr(6); } else if (cmHasLiteralPrefix(arg, "--dep=")) { arg_dep = arg.substr(6); } else if (cmHasLiteralPrefix(arg, "--obj=")) { @@ -2322,8 +2325,9 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, } else if (cmHasLiteralPrefix(arg, "--lang=")) { arg_lang = arg.substr(7); } else if (cmHasLiteralPrefix(arg, "--pp=")) { - // CMake 3.26 and below used '--pp=' instead of '--src='. + // CMake 3.26 and below used '--pp=' instead of '--src=' and '--out='. arg_src = arg.substr(5); + arg_out = arg_src; } else { cmSystemTools::Error( cmStrCat("-E cmake_ninja_depends unknown argument: ", arg)); @@ -2338,6 +2342,10 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, cmSystemTools::Error("-E cmake_ninja_depends requires value for --src="); return 1; } + if (arg_out.empty()) { + cmSystemTools::Error("-E cmake_ninja_depends requires value for --out="); + return 1; + } if (arg_dep.empty()) { cmSystemTools::Error("-E cmake_ninja_depends requires value for --dep="); return 1; @@ -2374,7 +2382,7 @@ int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, { cmGeneratedFileStream depfile(arg_dep); - depfile << cmSystemTools::ConvertToUnixOutputPath(arg_src) << ":"; + depfile << cmSystemTools::ConvertToUnixOutputPath(arg_out) << ":"; for (std::string const& include : info->Includes) { depfile << " \\\n " << cmSystemTools::ConvertToUnixOutputPath(include); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index f035c1e135..5bf6a2b018 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -545,7 +545,7 @@ std::string GetScanCommand(cm::string_view cmakeCmd, cm::string_view tdi, cm::string_view ddiFile) { return cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, - " --lang=", lang, " --src=", srcFile, + " --lang=", lang, " --src=", srcFile, " --out=$out", " --dep=$DEP_FILE --obj=$OBJ_FILE --ddi=", ddiFile); } @@ -1258,6 +1258,7 @@ namespace { cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, const std::string& ppFileName, bool compilePP, bool compilePPWithDefines, + bool compilationPreprocesses, cmNinjaBuild& objBuild, cmNinjaVars& vars, const std::string& objectFileName, cmLocalGenerator* lg) @@ -1314,6 +1315,13 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, } else { scanBuild.Outputs.push_back(ddiFile); scanBuild.Variables["PREPROCESSED_OUTPUT_FILE"] = ppFileName; + if (!compilationPreprocesses) { + // Compilation does not preprocess and we are not compiling an + // already-preprocessed source. Make compilation depend on the scan + // results to honor implicit dependencies discovered during scanning + // (such as Fortran INCLUDE directives). + objBuild.ImplicitDeps.emplace_back(ddiFile); + } } // Scanning always provides a depfile for preprocessor dependencies. This @@ -1520,8 +1528,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } cmNinjaBuild ppBuild = GetScanBuildStatement( - scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild, - vars, objectFileName, this->LocalGenerator); + scanRuleName, ppFileName, compilePP, compilePPWithDefines, + compilationPreprocesses, objBuild, vars, objectFileName, + this->LocalGenerator); if (compilePP) { // In case compilation requires flags that are incompatible with diff --git a/Tests/RunCMake/BuildDepends/FortranInclude-build1-stderr.txt b/Tests/RunCMake/BuildDepends/FortranInclude-build1-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranInclude-build1-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/BuildDepends/FortranInclude-build2-stderr.txt b/Tests/RunCMake/BuildDepends/FortranInclude-build2-stderr.txt new file mode 100644 index 0000000000..8d98f9debd --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranInclude-build2-stderr.txt @@ -0,0 +1 @@ +.* diff --git a/Tests/RunCMake/BuildDepends/FortranInclude.cmake b/Tests/RunCMake/BuildDepends/FortranInclude.cmake new file mode 100644 index 0000000000..fa9f39912d --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranInclude.cmake @@ -0,0 +1,20 @@ +enable_language(Fortran) + +set(check_pairs "") + +add_executable(preprocess FortranIncludePreprocess.F) +set_property(TARGET preprocess PROPERTY Fortran_PREPROCESS ON) +target_include_directories(preprocess PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +list(APPEND check_pairs "$|${CMAKE_CURRENT_BINARY_DIR}/preprocess.inc") + +# LCC < 1.24 has no way to disable Fortran preprocessor +if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "LCC" OR CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER_EQUAL "1.24.00") + add_executable(no_preprocess FortranIncludeNoPreprocess.f) + set_property(TARGET no_preprocess PROPERTY Fortran_PREPROCESS OFF) + target_include_directories(no_preprocess PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + list(APPEND check_pairs "$|${CMAKE_CURRENT_BINARY_DIR}/no_preprocess.inc") +endif() + +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$>.cmake CONTENT " +set(check_pairs \"${check_pairs}\") +") diff --git a/Tests/RunCMake/BuildDepends/FortranInclude.step1.cmake b/Tests/RunCMake/BuildDepends/FortranInclude.step1.cmake new file mode 100644 index 0000000000..53fdc2fe0f --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranInclude.step1.cmake @@ -0,0 +1,2 @@ +file(WRITE "${RunCMake_TEST_BINARY_DIR}/preprocess.inc" "\tPRINT *, 'FortranIncludePreprocess 1'\n") +file(WRITE "${RunCMake_TEST_BINARY_DIR}/no_preprocess.inc" "\tPRINT *, 'FortranIncludeNoPreprocess 1'\n") diff --git a/Tests/RunCMake/BuildDepends/FortranInclude.step2.cmake b/Tests/RunCMake/BuildDepends/FortranInclude.step2.cmake new file mode 100644 index 0000000000..05a9f11c6b --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranInclude.step2.cmake @@ -0,0 +1,2 @@ +file(WRITE "${RunCMake_TEST_BINARY_DIR}/preprocess.inc" "\tPRINT *, 'FortranIncludePreprocess 2'\n") +file(WRITE "${RunCMake_TEST_BINARY_DIR}/no_preprocess.inc" "\tPRINT *, 'FortranIncludeNoPreprocess 2'\n") diff --git a/Tests/RunCMake/BuildDepends/FortranIncludeNoPreprocess.f b/Tests/RunCMake/BuildDepends/FortranIncludeNoPreprocess.f new file mode 100644 index 0000000000..00b04dc446 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranIncludeNoPreprocess.f @@ -0,0 +1,3 @@ + PROGRAM FortranIncludeNoPreprocess + INCLUDE 'no_preprocess.inc' + END diff --git a/Tests/RunCMake/BuildDepends/FortranIncludePreprocess.F b/Tests/RunCMake/BuildDepends/FortranIncludePreprocess.F new file mode 100644 index 0000000000..680313a806 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/FortranIncludePreprocess.F @@ -0,0 +1,3 @@ + PROGRAM FortranIncludePreprocess +#include "preprocess.inc" + END diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake index b52758045e..dfa4f498e7 100644 --- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake +++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake @@ -68,6 +68,10 @@ if(NOT RunCMake_GENERATOR STREQUAL "Xcode") unset(run_BuildDepends_skip_step_2) endif() +if(CMake_TEST_Fortran) + run_BuildDepends(FortranInclude) +endif() + run_BuildDepends(Custom-Symbolic-and-Byproduct) run_BuildDepends(Custom-Always) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 3007660dee..75f2d3507d 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -292,6 +292,10 @@ if(NOT DEFINED CMake_TEST_BuildDepends_GNU_AS endif() endif() +if(CMAKE_Fortran_COMPILER) + list(APPEND BuildDepends_ARGS -DCMake_TEST_Fortran=1) +endif() + add_RunCMake_test(BuildDepends -DMSVC_VERSION=${MSVC_VERSION} -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} -- cgit v1.2.1