fortran-lang / fpm

Fortran Package Manager (fpm)
https://fpm.fortran-lang.org
MIT License
870 stars 97 forks source link

Optional dependencies #84

Open certik opened 4 years ago

certik commented 4 years ago

It is extremely common to have optional dependencies in Fortran projects (see the examples section at the end of this description).

The way Cargo handles it is described in here: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html

[dependencies]
foo = { version = "1.0", optional = true }
bar = { version = "1.0", optional = true }

[features]
fancy-feature = ["foo", "bar"]

it seems it is somehow tied to "features" that one can enable somehow, but I don't yet understand the full mechanism. Also there must be some way to propagate this "feature" on/off status inside the code using some macros or something.

In Fortran, I can see at least two ways to implemented it, are there more?

  1. We can define some pre-processor definitions and use #ifdef to enable certain code if an optional dependency is used. We can support multiple pre-processors (cpp, fypp, ...).

  2. One can do it at the module level: I sometimes have two files, say, openmp.f90 and openmp.dum.f90 both of which implement the openmp module, so the rest of the Fortran code just use openmp no matter what, and only one of the two files is compiled and linked in the buildsystem:

    # OPENMP
    if(WITH_OPENMP)
        set(SRC ${SRC}
            openmp.f90
        )
    else()
        set(SRC ${SRC}
            openmp.dum.f90
        )
    endif()

The advantage of 2. is that you do not have to use any pre-processor, which I try to avoid in my codes. The advantage of 1. is that it's simpler in some ways, you just put a few ifdefs in your code. I think fpm can support either one, or both.

fpm could for example create some module, say optional_dependencies and export some variable or a function such as openmp_enabled for the "openmp" feature, that you can call in your code and make some decisions.

Either way, we should figure out how to make fpm support optional dependencies and features that the user can configure.

Examples

Example 1

A typical example is a large electronic structure code, that provides its own default exchange correlation functional, but optionally allows to link against the libxc library, in which case one must enable and link against it and some code paths are different (typically some Fortran modules are enabled / disabled) and it allows the code to use functionals from the libxc library.

Example 2

There are many linear and eigensolver libraries, and there is typically some default, but if the user installs a particular 3rd party solver, it can optionally enable it in the Fortran program to use it instead.

everythingfunctional commented 4 years ago

I would lean towards option 1 as being easier to implement in fpm. It just doesn't fetch and build optional dependencies unless specified, and only defines the environment variables for the ones specified.

With option 2, the build process has to be able to make decisions about which source file gets used to satisfy a given module. This requires us to modify/extend our current naming conventions with regards to source file name and module name.

I definitely see the need for such a feature, and I think we should definitely try and tackle this at some point.

certik commented 2 weeks ago

See a recent discussion about this feature: https://fortran-lang.discourse.group/t/optional-dependencies-with-fpm/8538.