Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function install_modules for Fortran modules #11747

Open
amontoison opened this issue Apr 27, 2023 · 7 comments
Open

Function install_modules for Fortran modules #11747

amontoison opened this issue Apr 27, 2023 · 7 comments

Comments

@amontoison
Copy link

amontoison commented Apr 27, 2023

Describe the bug
When we compile a package developed in Modern Fortran, module files are generated (*.mod / *.smod).
The issue is that Meson doesn't install them and they are required if we want to link our compiled package in another Fortran package.

Expected behavior
It should be great to a have a function similar to install_headers.
It could take as input a library object and install the modules generated during the compilation of this library.

The current workaround for our project is to use meson.add_install_script(script_modules)
where script_modules = files('install_modules.py') and the content of the script is

#!/usr/bin/env python3
# Initially proposed by Sebastian Ehlert (@awvwgk)
from os import environ, listdir, makedirs, walk
from os.path import join, isdir, exists
from sys import argv
from shutil import copy

build_dir = environ["MESON_BUILD_ROOT"]
if "MESON_INSTALL_DESTDIR_PREFIX" in environ:
    install_dir = environ["MESON_INSTALL_DESTDIR_PREFIX"]
else:
    install_dir = environ["MESON_INSTALL_PREFIX"]

include_dir = "modules"
module_dir = join(install_dir, include_dir)

modules = []
# finds $build_dir/**/*.mod and $build_dir/**/*.smod
for root, dirs, files in walk(build_dir):
    modules += [join(root, f) for f in files if f.endswith(".mod") or f.endswith(".smod")]

if not exists(module_dir):
    makedirs(module_dir)

for mod in modules:
    print("Installing", mod, "to", module_dir)
    copy(mod, module_dir)

cc @Volker-Weissmann

@amontoison amontoison changed the title install_modules function for Fortran modules Function install_modules for Fortran modules Apr 27, 2023
@eli-schwartz
Copy link
Member

eli-schwartz commented Apr 27, 2023

Is there some way to know what the .mod / .smod filename is, at the time that meson configures the build? e.g. is it the same as the library name (libfoo.so and foo.mod)?

@amontoison
Copy link
Author

amontoison commented Apr 27, 2023

Yes, you can know the basename of .mod / .smod files at configure time. You just need to analyze the Fortran files compiled for a libfoo.so.
If the Fortran file has a line like

MODULE hsl_zb01_double

, a hsl_zb01_double.mod will be generated.

The module names are different than the library name.
For one shared library libhsl.so, 184 mod files are generated with Meson.

@eli-schwartz
Copy link
Member

Yes, you can know the basename of .mod / .smod files at configure time. You just need to analyze the Fortran files compiled for a libfoo.so.

Ah right, this is just the same problem as the preprocessed #include-changing-the-module-name thing again. :)

However, correct me if I'm wrong... it's valid for the module name to change when editing the Fortran files, without the build system reconfiguring, right? So we have to re-run meson setup --reconfigure every time a Fortran file is edited, if we want to pick up install name changes?

...

I'm (increasingly) of the idea that fortran_modname: 'hsl_zb01_double' should be a kwarg passed to the library target in meson.build. This would allow us to automatically install the .mod file, resolve some annoying nina depscan issues I've discussed with @dcbaker in the past, etc.

@amontoison
Copy link
Author

amontoison commented Apr 28, 2023

Yes, you can know the basename of .mod / .smod files at configure time. You just need to analyze the Fortran files compiled for a libfoo.so.

Ah right, this is just the same problem as the preprocessed #include-changing-the-module-name thing again. :)

However, correct me if I'm wrong... it's valid for the module name to change when editing the Fortran files, without the build system reconfiguring, right? So we have to re-run meson setup --reconfigure every time a Fortran file is edited, if we want to pick up install name changes?

Yes, you're correct.

...

I'm (increasingly) of the idea that fortran_modname: 'hsl_zb01_double' should be a kwarg passed to the library target in meson.build. This would allow us to automatically install the .mod file, resolve some annoying nina depscan issues I've discussed with @dcbaker in the past, etc.

It will also solve the issue with files that are preprocessed.
Meson doesn't generate a correct dependency tree if we have

MODULE hsl_zb01_precision

that is preprocessed with the flag -Dhsl_zb01_precision=hsl_zb01_double for example.

@jpakkane
Copy link
Member

This should not be a standalone function. Instead it should be a kwarg on the build target like install_fortran_modules: true. Commands that start with install_ may only be used to install preexisting data from the source dir, not something that is generated during build.

@dcbaker
Copy link
Member

dcbaker commented Mar 31, 2024

@amonstoison, I was thinking about this recently. My preliminary thought is that my two step dependency scanner would actually make this pretty easy to handle, because we could pass the json files to install, and let it find and install the mod files.

I have a couple of questions around Fortran:

  1. is there any convention on where fortran modules should be installed? since they're compiler and possibly even version dependent, is there some convention on how to handle this?
  2. If a target A links target B, and A sets install_fortran_modules : true, should B's modules be installed as well, or is that something that only the library author can know?

@amontoison
Copy link
Author

amontoison commented Mar 31, 2024

  1. Is there any convention on where Fortran modules should be installed? Since they're compiler and possibly even version dependent, is there some convention on how to handle this?

There is no convention on where Fortran modules should be installed, but the most common folder is include.
When we compile a package with dependencies that have Fortran modules, we need to specify the folder that contains the Fortran modules with -I (similar to C headers).
Because some packages generate a lot of Fortran modules, I prefer to install them in a modules folder and keep the include folder only for the headers related to the C interface.

The main package where we have this issue is GALAHAD.
We need to install the Fortran modules with a Python script.
This was the best solution for portability and it only requires one line in the main meson.build.

  1. If a target A links target B, and A sets install_fortran_modules: true, should B's modules be installed as well, or is that something that only the library author can know?

You don't need to install the modules of B because all the information contained in the B modules is used for linking and generating the A modules.
If a package C depends on A directly, you don't need the B modules unless you directly link to B.
It's analogous to headers; we don't need the B headers if C relies only on A routines.

Regarding your two-step dependency scanner, I recommend trying it on GALAHAD 😃.
We abuse preprocessing to avoid implementing a different file for each integer type (Int32 / Int64) and precision (Float32, Float64, complexF32, ComplexF64).
You have an example here.
The current solution is to use a generator to preprocess the Fortran files and then compile them.

The issue is that we need to specify the flags by hand for various compilers, which was quite problematic on Windows with the Intel compilers. Why do they replace -o with \Fi: (without a space after :)? 🤯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants