Ninja: 3.27.0 regresses Fortran module dependencies
With this CMakeLists.txt
:
cmake_minimum_required(VERSION 3.26)
project(Issue25112 LANGUAGES Fortran)
set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/include)
add_library(objmod OBJECT objmod.f90)
add_executable(main main.f90)
target_link_libraries(main PRIVATE objmod)
with main.f90
:
program main
use objmod, only : hello
implicit none
call hello()
end program
and objmod.f90
:
module objmod
implicit none
contains
subroutine hello()
print '(a)', "hello world"
end subroutine hello
end module objmod
Using CMake 3.27.0's Ninja generator and gfortran
sometimes fails to build:
/usr/bin/f95 -I/.../Issue25112 -Jinclude -fpreprocessed -c CMakeFiles/main.dir/main.f90-pp.f90 -o CMakeFiles/main.dir/main.f90.o
/.../Issue25112/main.f90:2:5:
2 | use objmod, only : hello
| 1
Fatal Error: Cannot open module file `objmod.mod' for reading at (1): No such file or directory
This is due to a race between compiling objmod.f90
and main.f90
due to missing dependencies.
Original Description
The details and minimum working example are at: https://gist.github.com/scivision/89c3221807becac46b629fccafc2255d
In short, with CMake 3.27.0 on macOS or Linux (didn't yet try Windows) and Gfortran or oneAPI (didn't try other compilers) I suddenly experienced failure to build Fortran projects using Fortran module files due to an apparent implicit include in CMake < 3.27 like:
include_directories(${PROJECT_BINARY_DIR}/include)
While the users should explicitly include Fortran module directories, this CMake 3.27.0 can surprise the Ninja Fortran users, especially since GNU Make is still implicitly including that directory with CMake 3.27.
User symptoms
Fortran CMake projects often collect all Fortran modules (.mod file generated at build by the compiler) into a single directory for convenience like:
set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/include)
Prior to CMake 3.27, there appears to be an implicit include of this directory. CMake 3.27.0 with Ninja suddenly no longer makes this implicit include--which is technically more correct behavior, but surprising as CMake 3.27.0 with GNU Make still implicitly includes that directory.
In the Gist example linked above, the compiler building "main.f90" has previously generated ${PROJECT_BINARY_DIR}/include/objmod.mod
from the add_library(objmod ...)
due to the statement module objmod
in "objmod.f90". As the compiler output in following sections show, CMake 3.27 + Ninja gives build error since ${PROJECT_BINARY_DIR}/include
is not implicitly included anymore--which is more correct behavior, if only GNU Make would also not implicitly include that dir.
Desired outcome
We need Ninja and GNU Make to work the same - either (pick one):
- Ninja and Make both not implicitly include
${PROJECT_BINARY_DIR}/include
(CMake 3.27.0 behavior; technically more correct) - Ninja and Make both implicitly include
${PROJECT_BINARY_DIR}/include
(pre-CMake 3.27 behavior)