FPM: Platform-specific instructions to linker on fpm.toml

Hi.

I’m using fpm v0.10.0 and writing code that utilizes C interoperability to use OS APIs. To support cross-platform compatibility, I’m switching build code using preprocessor directives, which works fine in general. However, I’ve noticed that I need to add specific instructions to the linker only for Windows.

I attempt to address this in the fpm.toml file with the following:

[build]
auto-executables = true
auto-tests = true
auto-examples = true
module-naming = false
link = ["iphlpapi", "ws2_32"]

Specifically, adding link = ["iphlpapi", "ws2_32"] to fpm.toml for successful Windows builds. However, it seems that this approach isn’t working well, as it causes linker errors on other operating systems (on the premise that iphlpapi and ws2_32 libraries are specific to Windows).

How can I add platform-specific instructions to fpm.toml for successful builds on Windows without affecting builds on the other operating systems?

Had similar issue with other libraries, very curious to know if there could be a workaround!

The workaround would be to incorporate this into fpm:

2 Likes

Thank you, @ivanpribec, for directing me to a place where this issue is being discussed.
I understood that I need to make some additional changes to fpm to achieve my goal.

In the discussion there, I find the first suggestion from @awvwgk to be nice and concise. i.e. assuming fpm accepts a manifest like:

[build]
link = ["..."]
link.linux = ["..."]
link.windows = ["iphlpapi", "ws2_32"]

First of all, I started by reading the files in the src/manifest directory and CONTRIBUTING.md of the fpm repository.

2 Likes

I proposed my idea for fpm.toml on the page above.

The problem is more general, it is not just the linker arguments that would need to be aware of platform/processor. Include directories and compiler flags would also need to be exposed.

This would be closer to a ready-made solution, however it has fallen out of sync with the main branch and is in conflict with other design decisions that were made in the manifest.

Does it mean that at the moment it’s not possible to define OS/compiler dependent flags?

If you wish to include them in the manifest, yes, that would be accurate. You can use response files, a feature of the CLI module fpm uses (M_CLI2 GitHub - urbanjost/M_CLI2: Fortran commandline-interface using a simple prototype command) but those files would be in addition to the fpm manifest (fpm.toml).

The solution thus far has been setting either the cli args every time you run fpm, response files or setting the environmental variables.

I would think that a viable solution is one that includes platform-specific settings (at least for the three major platforms aka unix, Mac, windows). Two ways to structure it would be:

  1. replicate the package tree as a “target” node, so that all options can be made platform-specific (at least supported in the manifest…)
[[target]]
[target.windows]
link = ["lib1","lib2","lib3"]
[target.windows.dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[target.windows.dev-depencencies]
etc = {git = "..."}
  1. create a “platform” node that can support string arrays for the three major platforms. Support now only for linking libraries, but later extendable to other features
[[executable]]
name = "my-app"
link = ["x","y","z"]
link.platform.windows = ["win_lib1","win_lib2"]
link.platform.unix = "mesa"

Rust basically employs option #1, although it does so via a meta-language. I personally don’t like that and think a very good first iterate would be to only allow the 3/major OS platform that fpm can already deal with.

not having conditionals in TOML files is problematic.

In addition to the possible approaches above, you can create a plugin command like ‘fpm-config’ that, using any method would generate the fpm.toml file. If no fpm.toml exists the next time the fpm command runs it could run it. This would be similar to the config(1) command and related tools used to create custom make files, for example.

You could look for fpm.linux.gfortran.toml first; then fpm.linux; then fpm.toml. So there could be system-specific and compiler-specific names that would be automatically searched for from most specific to least specific, somewhat like the response files can do.

The fpm.toml file could support conditionals. A simple Fortran example in GitHub - urbanjost/general-purpose-fortran: General Purpose Fortran Cooperative called M_logic.f90 shows a (originally F77, which still shows) a module that can be used to add if/else/elseif/endif logic to input files, for example.

The conditional processing could be done via a pre-processor such as cpp or m4. Having one supported for the fpm.toml file as well as the code would be most useful; although a pre-processor that can make decisions based on file information such as what libraries are available, what compilers, what OS can be difficult to do both generically and portably across systems.
I have used each of these approaches. The config one is the most flexible, but it is easy to construct a fpm-config that is not portable to all platforms, which would make placing a package in a public space such as the in-progress fpm repository.

Thank you for providing various workarounds on the command line.

I also realize that this is more complex than I initially thought.

The project containing this issue that I am dealing with almost assumes dependencies from another project. Unfortunately, none of the methods are convenient in requiring special actions from the user. I hope that the issue will be resolved in the future…

1 Like

I cant guarantee that the following is correct, but it might be worth considering.
To add platform-specific instructions to your fpm.toml file for successful builds on Windows without affecting builds on other operating systems, you can utilize conditional compilation supported by Fortran Package Manager (fpm). This approach allows you to specify different settings for different platforms.

In fpm, conditional settings can be specified using profile sections in the fpm.toml file. Each profile can include conditions based on the operating system, compiler, or build mode, which allows you to tailor the build process for different environments.

Here’s how you can modify your fpm.toml file to include Windows-specific linker instructions:

toml

[build]
auto-executables = true
auto-tests = true
auto-examples = true
module-naming = false

# Default linker settings for non-Windows platforms
link = []

# Windows-specific settings
[profiles.windows-x86_64]
link = ["iphlpapi", "ws2_32"]

In this example, the [profiles.windows-x86_64] section is used to specify settings that should only apply when building on a 64-bit Windows platform. The link = ["iphlpapi", "ws2_32"] line within this section adds the iphlpapi and ws2_32 libraries to the linker settings, but only for Windows builds. The default link = [] in the [build] section ensures that no additional libraries are linked for non-Windows platforms.

This approach should help you avoid linker errors on other operating systems while still including the necessary libraries for Windows builds. Remember to adjust the profile name and conditions according to your specific needs and the platforms you are targeting.