FPM and preprocessor: how to pass path strings

Hello,

I am new here and this is my first message in the forum, which already helped me when I was stuck in writing some Fortran lines and made me curious about this language, so I would like to thank the community.

I am writing a small library for an atomic potential to be used in a molecular dynamics code, which will probably be the object of other questions, but for now I restrict myself to the potential. Despite this being a small part of a larger project, I took it as an opportunity to learn about Fortran Package Manager and unit testing for the very first time.

The potential relies on importing some external coefficients stored in a huge text file; also, when I do the tests, I import few atomic configurations from an external modified .xyz file, which is just a plain text file.

Since I don’t know in principle where the code will be placed (well I know, either in my workstation or in some subpath of my $WORKDIR on some cluster, still, different ones), I pass the path to these files through the C preprocessor, using for example the following in the Makefile:

CPPFLAGS = -Ddata_path=‘“$(CURDIR)/tests/data/’ -cpp

I don’t know if this is the best solution, but it works. How can I achieve this using fpm?
In particular I have two problems:

  1. I tried different versions of what I found in the documentation:
  [preprocess] 
cpp.macros=[“data_path=‘tests/data/'"]  

But I don’t get any substitution of the string data_path with “tests/data” in the code, instead I get an Error: Invalid character in name at (1) compilation terminated due to -fmax-errors=1.
What is the right way to substitute a word with a string through the preprocessor? Or, is there a better way this is achieved?
2. In the Makefile I am relying on the environment variable $CURDIR, but I can’t use it in the fpm. The relative path that I put as an example in the point 1 is relative to the fpm.toml file, but I’m still not sure if it would work when I call the executable from any place (for example, from a subpath of $SCRATCH in a cluster).

Thanks in advance for guidance!

1 Like

Welcome to Discourse @pera!

The syntax you’re using is exactly right (assuming the canted quotes in your example that replaced the simple ones are due to autocorrect).

However, you’re assuming that the cpp preprocessor can pass a string as a macro, which is unfortunately not true because gfortran only implements a subset of the cpp preprocessor, called “traditional mode”.

With this preprocessor, you cannot pass a string as a macro directly. We’ve had this problem in fpm too, and we’ve eventually implemented what suggested here: some additional steps are necessary.

See fpm’s internal implementation at:

This would provide a solution. However, I think in your case you don’t want to hardcode a path to your input files in the code at compilation time. So, I suggest you use command line arguments instead, which you can then append at the end of the fpm run command.

There is a simple way to make it works with fpm.

With gfortran, you can pass a string using "'/u/toto'" (double quote, single quote, the string, single quote, double quote). For instance, this simple code works:

gfortran -c -cpp -D__PATH=“‘/u/toto’” SRC/Util_m.f90
gfortran APP/App_cpp.f90 Util_m.o
./a.out

The Util_m.f90 file:

MODULE Util_m
  IMPLICIT NONE

  character (len=*), parameter :: path   =                         &
#if defined(__PATH)
      __PATH
#else
      '~/Lib'
#endif

END MODULE Util_m

The main App.f90

PROGRAM App_cpp
  USE Util_m
  IMPLICIT NONE


  write(*,*) 'path: ',path

END PROGRAM App_cpp

Then with fpm, you need to protect the second and the third double quote with a backslash.
cpp.macros = ["__PATH=\"'/u/toto'\""]

1 Like