Installing Fortran module files

Is anyone aware of a clear recommendation for installing Fortran module files?

I usually avoid this issue by not installing mod files at all and just reuse Fortran dependencies within meson or fpm. This works fine when all dependencies are available in the respective build system, but CMake or make based Fortran projects would have a hard time to interface with the library. Here, one strategy is to install the project and find it by some means in the dependent project (pkg-config), for Fortran this requires of course to install the module files as well.

The mod files shouldn’t be installed in the top level include directory because of ABI compatibility issues in Fortran and because not all Fortran compilers handle the system include directories in the same way (this is important because the project could be potentially installed in the system prefix).

A notable reference here might be Python, since it has similar issues with ABI compatibility, therefore compiled extension modules include a lot of information like the Python implementation (CPython, PyPy, …), the version of the Python ABI (37, 38, 39, …), the architecture (x86_64, aarch64, …) and the platform (Linux, …). For an extension module compiled against CPython 3.9 and Linux x86_64 the shared object is suffixed with cpython-39-x86_64-linux-gnu.

Since Fortran has similar ABI issues this seems like a viable strategy for installing mod files as well.


I’m currently experimenting with the directory layout in meson (dftd4/dftd4#95), using the package name as well as the compiler identifier and version as subdirectory in the include directory (include/dftd4/gcc-10.2.0 here):

$PREFIX
β”œβ”€β”€ bin
β”‚   └── dftd4
β”œβ”€β”€ include
β”‚   β”œβ”€β”€ dftd4
β”‚   β”‚   └── gcc-10.2.0
β”‚   β”‚       β”œβ”€β”€ dftd4.mod
β”‚   β”‚       β”œβ”€β”€ ...
β”‚   β”‚       └── dftd4_version.mod
β”‚   └── dftd4.h
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ libdftd4.a
β”‚   β”œβ”€β”€ libdftd4.so -> libdftd4.so.3
β”‚   β”œβ”€β”€ libdftd4.so.3 -> libdftd4.so.3.1.0
β”‚   β”œβ”€β”€ libdftd4.so.3.1.0
β”‚   β”œβ”€β”€ pkgconfig
β”‚   β”‚   └── dftd4.pc
β”‚   └── python3.9
β”‚       └── site-packages
β”‚           └── dftd4
β”‚               β”œβ”€β”€ ...
β”‚               └── _libdftd4.cpython-39-x86_64-linux-gnu.so 
└── share
    └── ...

The module directory is communicated via pkg-config to downstream projects:

prefix=/some/path/to/install
libdir=${prefix}/lib
includedir=${prefix}/include

Name: dftd4
Description: Generally Applicable Atomic-Charge Dependent London Dispersion Correction
Version: 3.1.0
Requires.private: lapack, blas
Libs: -L${libdir} -ldftd4
Libs.private: -fopenmp -fopenmp
Cflags: -I${includedir} -I${includedir}/dftd4/gcc-10.2.0

I recall reading several discussions on this topic in the comp.lang.fortran archives. I’ve tried to filter out some of the ones that might be relevant:

These are just from the period 2016-2021 and there are likely many older threads too.

If we could come up with a good set of guidelines (and publish them at fortran-lang.org) I believe it would go a long way to improve the accessibility/ease of use of Fortran libraries.

When creating pkg-config files for libpardiso I ran into the issue, that when linking into a C executable, the -lgfortran flag was necessary, but is added automatically when gfortran is used to drive the compilation. I was wondering if your library might also have this problem?

From a very Fortran-centric perspective, it seems like all the problems related to packaging and distributing Fortran (modules) using existing tools (make, CMake, pkg-config, ninja…) stem from the fact that the tools were developed by system programmers with C libraries as their primary target. This also holds for the conventions on folders. In all build systems which have some form of Fortran support it has been retrofitted rather than included in the initial design.

2 Likes

True enough, but it is not that they are completely unusable for Fortran at all. You can run into similar problems when mixing different C++ projects which come with different build systems, not to mention precompiled headers and stuff like that.

The question is more, can we find a common exchange format and directory structure that enough build system β€œspeak” to get the job done, relying on tools used by system programmers makes a good starting point in my opinion. pkg-config is not perfect, but there are basically no cross-platform, multi-build system alternatives available.

For the average user linking against the shared object this will be no problem. Things get tricky with real time libraries like mkl_rt which somehow hide the Fortran runtime from ld or if you plan to link the static library in a shared module, e.g. for building Python extension modules which are independent from the shared object,

Not sure if this addresses what you want, but I noticed that programs that I rewrote no longer worked after a computer crash (which had nothing to do with gfortran).

When I reinstalled gfortran they worked. This is where Synaptic put gfortran [Ubuntu-Mate 20.04]:

/usr/bin/gfortran

My programs ran fine afterwards…

Fortran wiki also has a page about precisely this issue: Library distribution in Fortran Wiki

Thanks for those links. I found a good summary on the topic here, concisely summarizing my past experience with this issue.

Looking to the prior discussion the preference is a subdirectory in the lib directory including all the required information (package name, compiler name, compiler version, maybe even platform and architecture), or a separate subdirectory in the installation prefix (like finclude). But not really a consensus on how we can portably install (and find!) module files.

Sounds like a good idea to me. Maybe we can start this by establishing such guidelines in stdlib’s CMake build files?