fpm icon indicating copy to clipboard operation
fpm copied to clipboard

Deciding Syntax for MACROS in manifest

Open arteevraina opened this issue 3 years ago • 9 comments

Description

In fpm we currently have the syntax to define macros as a list in the manifest file that is fpm.toml. Something like :

[preprocess]
[preprocess.cpp]
macros = ["FOO", "BAR"]

But, we also want that we can define valued_marcos as well in the manifest. In order, to do that we have to decide the syntax for the manifest for defined macros.

Possible Solution

The possible options for this can be:

Option 1

[preprocess]
[preprocess.cpp]
macros = ["FOO", "BAR"]
[preprocess.cpp.valued_macros]
TESTMACRO1 = 4
TESTMACRO2 = 10

Option 2

[preprocess]
[preprocess.cpp]
defined_macros = ["FOO", "BAR"]
valued_macros = {TESTMACRO1 = 4, TESTMACRO2 = 10}

Option 3

[preprocess]
[preprocess.cpp]
macros = {FOO=5,  BAR=6, DEFINED_MACRO_FOO="somevalue"}

In option1 and option2, we will have two different ways of dealing with macros in manifest and this may not look clean. On the other hand, option3 looks clean but we will have to give some value to a Defined macro like DEFINED_MACRO_FOO which does not in actual needs to be equal to some value but needs to be defined in order for the program to work.

I will also update this thread with more options in the coming days. But, I will require your feedback as well for this UI-based decision and proceed with the Pull Request for reading and setting macros.

Additional Information

cc: @fortran-lang/fpm

arteevraina avatar Jul 14 '22 17:07 arteevraina

I lean towards option 2. Note that (I think) you'll have to deal with integer vs floating-point vs string values when adding the macros to the compile/pre-process command in different ways, due to the type-safe nature of Fortran. Shouldn't be too complicated, depending on how the TOML library we're using deals with that.

everythingfunctional avatar Jul 14 '22 17:07 everythingfunctional

Why make the additional effort to have separate tables for macros with and without values, they are not really that much different.

[preprocess]
cpp.macros = ["FOO", "BAR", "TESTMACRO1=4", "TESTMACRO2=10"]

Having a proper TOML type for the value of the macro other than string seems like an additional hindrance. What do you expect the macro to look like for

[preprocess]
cpp.valued_macros = {"FOO"=1_000, "STRING_VALUE"="\"Some string value\"", "TIMESTAMP"=1979-05-27}

A TOML library respecting types won't downcast the integer 1_000 to a string for you, but provide you with a proper 64bit integer value of 1000, which we than have to serialize again.

awvwgk avatar Jul 14 '22 18:07 awvwgk

[preprocess]
cpp.macros = ["FOO", "BAR", "TESTMACRO1=4", "TESTMACRO2=10"]

That's surprisingly "naive" and smart, I said on the call today that Sebastian would have a good idea.

milancurcic avatar Jul 14 '22 18:07 milancurcic

Another very serious downside in TOML is that inline tables are not allowed to have line breaks, while inline arrays can span multiple lines, which allows for a more readable and diff-friendly package manifest.

My concern is more about accessing values from the manifest in the macro definitions to allow reusing some information from the manifest, like the version number:

[preprocess]
cpp.macros = [
  "PROJECT_VERSION=@version@",  # configure file like, meson uses this
  "PROJECT_VERSION={version}",  # Python and C++ formatter style
  "PROJECT_VERSION=<version>",  # Fortran string interpolation (non-standard extension) 
  # and so on...
]

awvwgk avatar Jul 14 '22 18:07 awvwgk

Why make the additional effort to have separate tables for macros with and without values, they are not really that much different.

[preprocess]
cpp.macros = ["FOO", "BAR", "TESTMACRO1=4", "TESTMACRO2=10"]

@awvwgk , that's oddly brilliant. I'm on board with this.

everythingfunctional avatar Jul 14 '22 20:07 everythingfunctional

I would just comment here that fypp accepts any evaluable Python expression as a preprocessor definition flag. This includes things like: -DINT=42 -DFLOAT=3.14 -DTUPLE=('abc',12) -DDICT={'name'; 'John', 'surname': 'Doe', 'age': 67} -DSTRING=\"String\" -DSTRING2='"String"'. (It might be necessary to quote the tuple and dictionary, but I'd need to double-check.) With string arguments in the command-line you need to "protect" the quotes by escaping them or double-quoting. Otherwise fypp will try to evaluate an "undefined variable".

@urbanjost, what kind of expressions are there in prep (https://urbanjost.github.io/prep/prep.1.html#3)?

ivan-pi avatar Jul 14 '22 21:07 ivan-pi

Fortran integer and logical expressions with a few C-like extensions and names with no spaces. Expressions are evaluated upon definition and are case-insensitive. There are some C-like operators as well. They may precede other command line options or follow the -D parameter. The -D parameter may be repeated, but can contain multiple expressions delimited by semi-colons. The .operator. syntax is supported partly to reduce the need to use characters that are often expanded by shells. A space is required after the -D keyword.

So essentially the same as the $DEFINE directive except no spaces are allowed.

prep REAL64 UNIX -i source.ff
prep A=10/2 B=A+20 L=A.ne.B.and.B+3.ne.22 -i source.ff
prep -D A=10/2 -D B=A+20 -i source.ff
prep -D 'A;B;c=a*b;d=(a+b)/c'
prep
$HELP
EXPRESSIONS
  numeric operators are +,-,*,/,**, (). Logical operators are
   >  | .EQ.| .NE.| .GE.| .GT.| .LE.| .LT.|.NOT.|.AND.| .OR.| .EQV.|.NEQV.|
   >  |  == |  /= |  >= |  >  |  <= |  <  |  !  |  && |  || |  ==  |  !=  |
  $DEFINE variable_name[=expression][;...]
   > Predefined values are "OS", which is set to a guess of the system type, and
   > UNKNOWN=0 LINUX=1 MACOS=2 WINDOWS=3 CYGWIN=4 SOLARIS=5 FREEBSD=6 OPENBSD=7.
   > SYSTEMON is .TRUE. if --system is present on the command line, else .FALSE.

     :
     :
     :

urbanjost avatar Jul 15 '22 00:07 urbanjost

PS: Strings were considered but it was decided to go with a name for defined/undefined, as the most common usage; and mostly NAME=VALUE, but expressions were allowed as well. Strings and string expansion are controlled with $SET, which is a slightly different model. So far no one has found that to be an issue except for passing in a version string; but that might be allowed in future versions. Another version allows much more extensive expressions using the M_calc module as an experiment; but the desire is to keep it as simple as possible so that was not placed in production. "If it is not needed, do not add it".

urbanjost avatar Jul 15 '22 00:07 urbanjost

My concern is more about accessing values from the manifest in the macro definitions to allow reusing some information from the manifest, like the version number:

[preprocess]
cpp.macros = [
  "PROJECT_VERSION=@version@",  # configure file like, meson uses this
  "PROJECT_VERSION={version}",  # Python and C++ formatter style
  "PROJECT_VERSION=<version>",  # Fortran string interpolation (non-standard extension) 
  # and so on...
]

For a key that accepts a list like keywords = ["hdf5", "mpi"]. Should we aim to use them inside the macro definitions or we should only focus on more simpler values that can be reused for macros like version , name, author ?

arteevraina avatar Jul 16 '22 17:07 arteevraina