fortran-lang / fpm

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

use fpm to fill the gap between gcc macros and gfortran to enable seamless cpp preprocessing #1084

Open jalvesz opened 2 weeks ago

jalvesz commented 2 weeks ago

Description

Hi, I would like to propose that fpm fills in the gap left between gcc and gfortran where all defined macros are not available from gfortran without using CMake.

While there are many discussions about preprocessors, most of the defacto preprocessing is being done using cpp/fpp. Simple tasks such as determining on which OS a program is running (which can be set at compile time) either rely on C preprocessing or having to use get_environment_variable at runtime.

Possible Solution

One idea would be to make it such that fpm catches the list of macros from gcc by running (if using gfortran) the commands: Linux

gcc -dM -E - < /dev/null

Windows

gcc -dM -E - <NUL:

And pass them through the preprocess.cpp mechanism by default.

Additional Information

No response

ivan-pi commented 1 day ago

You are referring to the issue also documented here, https://cyber.dabamos.de/programming/modernfortran/preprocessor.html,

As CPP, the preprocessor of GNU Fortran, is not indicating the current operating system, we have to pass the macro through argument -D, in this particular case, -DFreeBSD

Concerning the behaviour of CMake, some material can be found in the discussion https://github.com/fortran-lang/fpm/discussions/730. If I understood you correctly, you are saying the CMake somehow merges the preprocessor environment of gcc and gfortran, and then invokes gfortran on the preprocessed file?

jalvesz commented 1 day ago

Well, I had done some tests in which CMake managed to preprocess for instance the WIN32 definition... I'm testing a single file test anew and I'm not getting the behavior, so I might need to go again through it ...

Now, CMake does have OS definitions which can be used. For instance, one can add the following to a CMakeLists.txt:

# Convert CMAKE_SYSTEM_NAME to uppercase
string(TOUPPER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME_UPPER)

# Pass the uppercase system name as a macro
add_compile_options(-D${SYSTEM_NAME_UPPER})

So any of the system names provided here https://cmake.org/cmake/help/latest/variable/CMAKE_SYSTEM_NAME.html can be used as a definition.

It seems that it would also be necessary to find way to recover gcc definitions with CMake.

perazz commented 1 day ago

One way to identify the OS and save it as a parameter would be to use the compiler_version and compiler_options intrinsic functions. It will certainly need quite some testing and experimenting, but I believe that at least for the major compilers it would be relatively easy to come up with a parameter boolean flag that stores whether the local system is Windows/unix/etc.:

use iso_fortran_env
character(1024), parameter :: opts= compiler_options()
character(1024), parameter :: vers =compiler_version()
logical :: is_windows = index(opts,"C:\")>0 .or. &
                        index(opts,":\")>0 .or. &
                        index(vers,'Windows')>0 .or. &
                        index(vers,'MSYS')>0
print *, opts
print *, vers
print *, 'is_windows = ',is_windows 
end

note that this would not work if we're cross-compiling (i.e. a Windows .exe from a unix machine).

jalvesz commented 7 hours ago

For cross compilation I guess it would be necessary to distinguish between the current build OS and the "target" OS. If the target is different from the build OS then one should pass this as an optional parameter. I'm not familiar with this though, I usually build directly for the target OS and use a virtual machine to build for a different one, which in any case implies that the build system sees it as "native".

I was imagining to maybe print the defined macros from the compiler to a temp file which can be retrieved to pass the macros as definitions, at least for gnu as it seems that intel fortran does the job. But for cross compilation this would not be enough indeed.