I though it would be instructive to see how Ninja approaches the module dependency situation, as one of the CMake backends.
For Brad’s example,
! mod.f90
module mod
implicit none
private
public :: const, show_it
interface
module subroutine show_it() bind(c)
end subroutine
end interface
integer, parameter :: const = 42
end module
! submod.f90
submodule(mod) submod
implicit none
contains
subroutine show_it() bind(C)
print *, const
end subroutine
end submodule
// main.c
extern void show_it();
int main() {
show_it();
}
the Ninja build script would look as follows:
# build.ninja
ninja_required_version = 1.1
fflags = -Wall
cflags = -Wall
fc=gfortran-13
cc=gcc-13
# Rule declarations
rule fcompile
command = $fc $fflags -o $out -c $in
rule ccompile
command = $cc $cflags -o $out $in -lgfortran
# Build edges
build mod.o: fcompile mod.f90 || graph.dd
dyndep = graph.dd
build submod.o: fcompile submod.f90 || graph.dd
dyndep = graph.dd
build main: ccompile main.c mod.o submod.o
default main
# graph.dd
ninja_dyndep_version = 1
build mod.o | mod.mod mod.smod: dyndep
build submod.o | mod@submod.smod: dyndep | mod.smod
In practice the graph.dd file would be generated by a fscan tool that would analyze the source tree for modules and dependencies between them in a preliminary pass. This is what CMake does, and I think a ninja backend for fpm would be a great project. I suppose one could also try to modify makedepf90 (but it’s missing submodule parsing, and probably lacks a few other things), FF08Depends by Ian Harvey, or LFortran. Having this built in to the compiler would be ideal though (no need to install two separate tools).
The ninja tool is then invoked as follows:
/ninja_test$ ninja -v # -v for verbose output
[1/3] gfortran-13 -Wall -o mod.o -c mod.f90
[2/3] gfortran-13 -Wall -o submod.o -c submod.f90
[3/3] gcc-13 -Wall -o main main.c mod.o submod.o -lgfortran