How do you generate file dependence when writing Makefile?

Dear all,

May I ask, when writing Makefile, how do you generate file dependence?

For not so many f90 files, I can do it manually, like below.
But if the number of files are big, like 100 files, it becomes very cumbersome.
Is there any tool that can generate file dependence automatically?

I know in windows using Code::Block I can generate a Makefile.
But I would like to hear ideas (in windows or linux) from your guys, many of you are more more experienced and advanced than me.

Thank you very much in advance!

test_CR3BP.o: FLINT.o test_CR3BP.f90
(FC) (FFLAGS) -c test_CR3BP.f90

FLINT.o: FLINT_base.o ERK.o FLINT.f90
(FC) (FFLAGS) -c FLINT.f90

FLINT_base.o: FLINTUtils.o FLINT_base.f90
(FC) (FFLAGS) -c FLINT_base.f90

FLINTUtils.o: FLINTUtils.f90
(FC) (FFLAGS) -c FLINTUtils.f90

ERK.o: FLINT_base.o ButcherTableaus.o StepSz.o ERK.f90
(FC) (FFLAGS) -c ERK.f90

ERKInit.o: ERK.o ERKInit.f90
(FC) (FFLAGS) -c ERKInit.f90

ERKIntegrate.o: ERK.o ERKIntegrate.f90
(FC) (FFLAGS) -c ERKIntegrate.f90

ERKInterp.o: ERK.o ERKInterp.f90
(FC) (FFLAGS) -c ERKInterp.f90

ERKStepInt.o: ERK.o ERKStepInt.f90
(FC) (FFLAGS) -c ERKStepInt.f90

ButcherTableaus.o: FLINT_base.o ButcherTableaus.f90
(FC) (FFLAGS) -c ButcherTableaus.f90

StepSz.o: FLINT_base.o StepSz.f90
(FC) (FFLAGS) -c StepSz.f90

1 Like

A related discussion was Module dependencies , where people recommended some tools.

1 Like

Ultimately you can just make it compile with fpm (which should work out of the box eventually) and then I want fpm to generate such a standalone Makefile that you can use.

1 Like

Having written the logic to do this a couple of times, I’ll give some insights, and why Make is not a good tool for this.

File dependency information is a many-to-many relationship. It’s just that the simple cases most people encounter early in their learning happen to only be one-to-one. The general rule is as follows. Compiling a Fortran source file:

  • produces:
    • an object file containing the compiled code from that source file
    • a module file (typically module_name.mod) for each module in the source file
    • a submodule file (typically module_name@submodule_name.smod) for each submodule in the source file
  • depends on
    • the module file for each module used in the source file
    • the parent module and parent submodule files for any submodule in the source file

Linking to produce an executable depends on all of the object files containing code that is needed by the program, whether that be modules, submodules, or external subprograms, not to mention the main program.

This is why Make is generally not sufficient. You cannot define a rule that produces multiple targets.

module_name.mod module_name.o: module_name.f90
    ...

does not do what you think it does. It says that this rule could produce one or the other files, not that it produces both in a single execution.

This also has the potential to for circular dependencies. I.e. a source file could contain a module, and be used by other code in the source file. The submodule relationship has the same potential issue.

As you can see, it is thus quite difficult to do this generically, and the reason most projects have a convention of one program unit per source file. (i.e. module, submodule, program, or external procedure).

3 Likes

I recommend you not use makefiles. Use fpm or Meson, which can take care of these tricky details for you.

2 Likes

I’m used to CMake, my skeleton for small projects is in GitHub - MarDiehl/fortran-skeleton: Cmake-based fortran skeletons

2 Likes

gmake provides pattern rules which allows multiple targets from a single file.

%.mod %.o : %.f90

The catch is that the stem, % , must be identical. So the file module_name.f90 must contain a module named module_name. This also implies that there is only one module per file. I have not tried this with submodules. It looks like it may not be possible to get a common stem since the submodule name is used – module_name@submodule_name.smod.

3 Likes

I’ve looked into this (maybe I’m still mistaken), but this doesn’t mean what you think it does. It doesn’t mean that executing the rule will produce both files. It means that this rule can produce either of these files. At least that’s what make interprets it as. Of course in this case that it was happens, but make doesn’t necessarily expect that.

1 Like

This seems to work really well, thanks!

Do you know how cmake figures out the file dependencies? (How cmake works is beyond me.)

It seems that there is a software called makedepf90 under Linux that can help generate makefiles, but I can’t find it in Windows-msys2, and I haven’t used it. I just heard people mention this software.

This works very well for me:

2 Likes

I looks like CMake parses the source files and can detect dependencies based on statements like module, submodule, use, and maybe a few more.

fpt generates makefiles (http://simconglobal.com).
It assumes that modules create .mod and .o files and handles the dependencies separately. But the current version doesn’t handle sub-modules. Working on it.

On further exploration, it appears I must retract my earlier statement that you can’t have a rule that produces multiple files. I don’t know if this is a new(er) capability or if I just missed it the last time I was trying to research it, but there is a section in the GNU Make manual: Multiple Targets (GNU make)

Particularly, you’ll want to look at the “Rules with Grouped Targets” which uses &: to separate the targets and dependencies. You’ll almost certainly still need a specific rule for each source file, making this a significant maintenance headache, but it’s apparently possible.

But, it being possible is good news for the desire to have fpm generate Makefiles.

Also, that means I owe @leetaylor an apology for dismissing his contribution. He is correct that it is possible. Sorry.

1 Like

gmake Version 4.3 (19 Jan 2020) introduced a new feature which can be used to help describe module and submodule dependencies. Documented at Multiple-Targets. The summary from the NEWS file.

New feature: Grouped explicit targets
Pattern rules have always had the ability to generate multiple targets with
a single invocation of the recipe. It’s now possible to declare that an
explicit rule generates multiple targets with a single invocation. To use
this, replace the “:” token with “&:” in the rule. To detect this feature
search for ‘grouped-target’ in the .FEATURES special variable.
Implementation contributed by Kaz Kylheku kaz@kylheku.com

I don’t have access to that version of gmake, so I’ve used an intermediate file
for rules which generate multiple output files. This is described at
multiple outputs

%.time : %.f
        $(FC) -c $^
        touch $@

tstsubmodule.time : tstsubmodule.f 
tstsubmodule.o : tstsubmodule.time
$(moduledir)/tstsubmodule.mod : tstsubmodule.time
$(moduledir)/tstsubmodule.smod : tstsubmodule.time

A similar technique is used in the link listed in an earlier reply but calls them anchor files Writing Makefiles for Modern Fortran

One interesting feature of his technique is the use of two pass compiling. We’ve been using a similar technique and documented by the developer at A Note on Compiling Fortran

Some Fortran compilers (Intel - ifort, GNU - gfortran and IBM - xlf,
at least) offer an option to ‘‘verify syntax’’, with the side effect
of also producing any associated Fortran module files. As it happens,
this option usually runs much faster than the object code generation
and optimization phases. For some projects on some machines, it can be
advantageous to compile in two passes: The first pass generates the
module files, quickly; the second pass produces the object files, in
parallel. We achieve a 3.8 x speedup in the case study below.

We’re currently moving from gmake to CMake. I don’t believe CMake supports two pass compiling. Instead I’ve been advocating the use of submodule to prevent parallel build times from going back to pre-two-pass build speeds.

1 Like

A free version of the article is here.

1 Like