Cmake 3.27.8 regression with Ninja and Fortran dependencies

I think I found a regression with the dependency generation for Ninja in 3.27.8.

I am one of the developers of CASTEP, a large electronic structure code predominantly in Fortran. CMake builds with cmake 3.20.4 - 3.25.1 appear to work correctly when used with the Ninja backend.
However a user reports a build failure with cmake i 3.27.8 and Ninja 1.11.1 in parallel on the Darwin/macports which I reproduce under OpenSuSE linux. The system is attempting to compile one of the modules before a module on which it depends, and the compile fails because the .mod file it depends on has not yet been created.

I’ll emphasise that this is a regression in a previously-working and well-tested cmake build.

  • Serial builds work, but parallel with “-j” fail.
  • Builds with unix makefile backend always succeed in both serial and parallel. Ninja fails.
  • cmake 3.25.1 and below generate working parallel builds with Ninja
  • cmake 2.37.8 and 3.28.1 fail
  • cmake 3.27.9 succeeds.

Any suggestions as to what might have changed and how to investigate further would be very welcome.

Keith Refson

Cc: @ben.boeckel

3.27 tried to make dependencies for Fortran and C++ modules more exact, but doing so exposed a parade of cases in which the “exact” dependencies were not correctly computed. CMake MR 8996 reverted the change for 3.27.9 to stabilize the 3.27 series, but the 3.28 series continues the effort. See that MR for details.

Please try to narrow your use case down to a simple example, and open an issue to demonstrate the problem.

Ah thank you. This helped a lot to narrow down the issue. The missing dependency was for building an object library:

add_library(MY_OBJ_LIB OBJECT my_obj_lib.f90)
add_dependencies(MY_OBJ_LIB my-dep-lib)

The build was attempting to compile my_obj_lib.f90 before any of the fortran files in my-dep-lib, and failing because the .mod file for the dependent libraries was missing. Curiously, changing the add_dependencies line to

target_link_libraries(MY_OBJ_LIB my-dep-lib)

puts the dependency back and the compile succeeds.

I’m yet to check whether a minimal example can be constructed to display this behaviour.

Keith Refson

If MY_OBJ_LIB depends on modules or symbols from my-dep-lib, then linking the latter via target_link_libraries is correct. add_dependencies is not enough, and worked only by accident before.

Thanks. No bug report necessary in that case, and an easy fix to my CMakelist.txt.

How CMake handles a dependency on a generated Fortran module file is still opaque to me.
As a matter of curiosity, how might such a dependency have been specified before 3.12, when target_link_libraries was not available?

Prior to 3.12, object libraries were referenced in add_library calls as sources by $<TARGET_OBJECTS:...>. That also hooks up the dependencies.