Fortran: Is there a way to conditionally use modules? - module

Assume I have two Fortran modules called modA and modB. Is there a way to use one or the other in a program based on a conditional statement? Does this require some type of preprocessing? For example, I want to be able to do something like the following code:
if (condition)
use modA
else
use modB
end
I am using the GNU Fortran compiler.

Yes, you must do some kind of preprocessing. The most common is the C preprocessor included in GNU Fortran.
#if (condition)
use modA
#else
use modB
#endif
The preprocessor does not understand your Fortran code, it is only a text for it. It has it's own set of directives and it's own set of variables. Only the preprocessor variables can be used in the condition, not your Fortran variables.
Another common directive is #ifdef which is a variant of #if defined. See the manual for more https://gcc.gnu.org/onlinedocs/cpp/Traditional-Mode.html (gfortran runs the preprocessor in the traditional mode).
To enable the preprocessor use the -cpp flag or in Unix you can use capital F in the file suffix.

Related

How can I define an executable that has different compiler command-line arguments?

I have a C++ project and I want to test the compatibility of library headers with different compiler versions. I have a simple source file (that includes said headers) and I want to change the compiler argument to std=gnu++11 for this one target. How do I do that?
executable('old_compiler_test', ['octest.cxx']
# override ARGS here ??? how
)
Note that I have
add_global_arguments(
['-std=gnu++17',
....
rather than the dedicated option for this, in spite of the warning to prefer the special option, because the special option simply doesn't work. (Why is a question I've never tracked down)
update
To clarify: I'm not trying to make additional configurations in the same way that debug and release are configurations. I want a different compiler argument to be applied to a single target within the configuration.
From the Meson documentation, you can use the argument <languagename>_args to pass additional compiler arguments. In your case, since you use C++, it would give something like
executable('old_compiler_test', ['octest.cxx'],
cpp_args: ['std=gnu++11']
)
However the documentation also specify that there are no way to disable an argument added by add_global_argument(), so you will end up with both -std=gnu++17 and -std=gnu++11 passed to the compiler. I don't know how your compiler will behave, but I tried to pass both arguments to GCC 10.2 and it uses c++17 (not what you want).
Workaround
It seems that if you define the C++ version in the project() statement, Meson will removes it if an other version is specified in compiler arguments, giving the behaviour you expect.
Here is the sample I used:
meson.build
project('project-name', 'cpp',
default_options: ['cpp_std=c++17']
)
executable('old_compiler_test', ['octest.cxx'],
cpp_args: ['-std=gnu++11']
)
octest.cxx
#include <iostream>
int main() {
std::cout << __cplusplus << std::endl;
}
After compilation, running the executable will print 201103, which means that the compiler used c++11 as desired.

what is $(-*-command-variables-*-)) in gnu make

In my project makefile, there is a variable named "--command-variables--". I could guess its meaning from the context, but I want to know more about "--command-variables--". No result from google and GNU make manual.
Here is my test makefile,
all:
$(warning $(-*-command-variables-*-))
#$(warning $(.VARIABLES))
#$(foreach v, $(.VARIABLES), $(info $v===>$($v)))
When I type make test=Makefile, it prints out:
Makefile:2: test=Makefile
make: `all' is up to date.
I found this variables is in .VARIABLES variable, but I can not find it in GNU manual.
The version of make I used is GNU make 3.81.
Can anyone tell me where does this variables defined in or more about these variables? Thank you.
It's one internal variable defined in main.c (line 1344),
/* Define an unchangeable variable with a name that no POSIX.2
makefile could validly use for its own variable. */
(void) define_variable ("-*-command-variables-*-", 23,value, o_automatic, 0);

CMake configure_file replace ON/OFF with 1/0

Suppose I have two libraries ABC, XYZ and two variables ABC_FOUND XYZ_FOUND in CMakeLists.txt. In a config.h.in file, I have the following lines
#define __USE_ABC__ #ABC_FOUND#
#define __USE_XYZ__ #XYZ_FOUND#
If I do configure_file(config.h.in config.h), the output config.h file will be changed to
#define __USE_ABC__ ON
#define __USE_XYZ__ OFF
My question is how can I convert the ON/OFF options into 1/0, in other word, my desired output config.h should be
#define __USE_ABC__ 1
#define __USE_XYZ__ 0
Define ABC_FOUND to either 0 or 1 with
#cmakedefine01 #ABC_FOUND#
Use an intermediate variable in either environment to change it to USE_ABC.
Likely, you should use #cmakedefine instead of hard defines (see examples e.g. here)
But please remember that in the case of #cmakedefine you get a configuration header where "enabled features" (in terms of CMake if() command) are #define-d to a supplied value, while "disabled features" are #undef-ined. So you should test them not with #if <something> but rather with #ifdef <something>.

Is it possible to use #ifdef like checks in assembler?

I have tested a bit of assembler on Linux using the AT&T syntax. One thing that struck me was that the book I was reading was written from a 32-bit standpoint. Thus, all sizes would have to be changed to the correct 64-bit versions for me. Or I could (which I did) assemble the code using the --32 flag for as and the -melf_i386 flag for ld when linking. I have also adapted some of the code and to run on Windows under Cygwin.
But that got me thinking. Is there a way to do ifdef like checks in assembler to do one thing if I'm on Windows and another under Linux and also handle 32 vs 64 bit that way? For example to have a .globl _start under Linux and a .globl _main under Windows.
Or is this handled by checking before assembling and having different source files to assemble based on the result of the checks?
I.e. foo_linux.s and foo_windows.s
If so, how do you overcome that fact that you will not know which .s files you will use, and thus have to include, when you are creating your program?
For example, say that we have a socket_linux.s and a socket_windows.s. They both present an identical interface but do the OS specific work associated to sockets. But when I work with the sockets in my program I will not know if I need the Windows or Linux version included. So I would be kinda screwed :)
So how is this handled in Assembler? In C++ for example I could include my socket.h and socket.cpp and wrap all the Linux and Windows specific code in #ifdef statements.
If you use GCC to compile your files and name them .S (with uppercase S) or .sx, it will pass them through the preprocessor before invoking the assembler.
From the docs:
file.s
Assembler code.
file.S
file.sx
Assembler code which must be preprocessed.
You can add -v to the command line to see how the various sub-processes are invoked.
in MASM (.asm), you can use ifdef, ifndef and the likes, as:
ifdef X64
endif
When writing for different platforms you can define some macro for loading target specific files:
FILE target.h
#if defined(__arm__)
#define target "arm"
#elif defined(__x86_64__)
#if defined(_WIN64)
#define target "win64"
#else
#define target "linux64" // all non-Win share the same calling convention
#endif
#else
// 32bit defs
#endif
Then you can include target specific files with the macro, two string literals successively get one single literal:
#include "target.h"
#include "target_specific_code_" target ".h"
It includes one of these files:
target_specific_code_arm.h
target_specific_code_win64.h
target_specific_code_linux64.h
...
EDIT:
Like this, you can also define target specific assembler instructions for later use in inline assembly:
#ifdef ...
#define ASM_PP_LOAD_WORD "movi "
#else
#define ASM_PP_LOAD_WORD "mov "
#endif
or as macro
#ifdef ...
// when using intel assembler there is a different
// order of parameters
#define ASM_PP_LOAD_WORD(a, b) "movi " #b ", " #a
#else
#define ASM_PP_LOAD_WORD(a, b) "mov " #a ", " #b
#endif

gfortran, DLL, underscore

I want to access some subroutines from a third party DLL. The functions use STDCALL as the calling convention.
Running dumpbin /export foo.dll gives me something like:
...
7 6 00004B40 Foo#16
...
I compile my code using:
gfortran test.f90 -o test.exe -Wl,foo.dll
I get an error: undefined reference to '_foo_' (note the underscores).
I have tried adding the -mrtd compilation flag, as well as other flags I googled, all to no avail.
How can I tell fortran to not add the underscores?
edit: A bit of clarification is in order.
I have an existing DLL to which I do not have the source to.
This DLL is written in Visual Basic, if it helps.
I want to call this DLL from fortran.
When I write in test.f90: Foo(1.0d0) I get an undefined reference to '_foo_' linkage error
Did you try -fno-underscoring ?
I found a post by Tobias Burnus (a gfortran developer) at http://www.rhinocerus.net/forum/lang-fortran/604847-fortran-dll-call-excel-2.html (near the end) -- he recommends the use of compiler directives instead of -mrtd.
You need to combine the use of ISO_C_BINDING with compiler attributes. You should really read the Mixed-Language Programming section of the gfortran manual. It gives good advice that can be used with other compilers as well. In particular, in your case you need the stdcall attribute:
interface VisBasSubs
subroutine foo (DoubleArg) bind (C, name="Foo")
!GCC$ ATTRIBUTES stdcall :: foo
use iso_c_binding, only: c_double
real (kind=c_double), intent (inout) :: DoubleArg
end subroutine foo
end interface VisBasSubs
Notice the line with stdcall, it's what should make it work.
Just wanted to expand on M.S.B's -fno-underscoring answer: You may run into issues if using f2c & g77. From the gfortran documentation:
With -funderscoring in effect, GNU
Fortran appends one underscore to
external names with no underscores.
This is done to ensure compatibility
with code produced by many UNIX
Fortran compilers.
Caution: The default behavior of GNU
Fortran is incompatible with f2c and
g77, please use the -ff2c option if
you want object files compiled with
GNU Fortran to be compatible with
object code created with these tools.
Use of -fno-underscoring is not
recommended unless you are
experimenting with issues such as
integration of GNU Fortran into
existing system environments
(vis-à-vis existing libraries, tools,
and so on).
You might need to recompile the DLL with something like -fno-underscoring to remove the underscores from the DLL.
I've run into portability issues related to underscore prefix/suffix by certain Fortran compilers: Some compilers _prefix or suffix_ by default, while others don't! My solution has been preprocessor directives:
#ifdef LC_UNSC
#define GET_DIP_MOMENT get_dip_moment_
#elif LC_NOUNSC
#define GET_DIP_MOMENT get_dip_moment
#endif
...
call GET_DIP_MOMENT()
A different approach is to use the ISO C Binding of Fortran 2003, which is supported by gfortran >= 4.3. This will automatically use the underscoring conventions of C (i.e., probably none), rather those of the Fortran compiler. It will also give you control over the case (capitalization) of the subroutine names, if the Windows linker cares about that. Fortran is case insensitive, and so you can call Fortran subroutines by any case -- probably the linker is converting to lower case.
Including the following "interface" in the declarations of the Fortran routine that calls "Foo" describes Foo to be a C subroutine (void function) with a single argument of double type -- Fortran input/output, or a pointer in C. If Foo has other properties, the interface needs to be changed. The "bind" clause specifies the case-sensitive name to provide to the linker. If you call Foo from several Fortran routines, then it is best to put the interface into a module and "use" it from each Fortran routine.
This is intended for C -- maybe it will work for Visual Basic. The ISO C Binding gives a lot of control, so if this doesn't work, maybe some variation will.
interface VisBasSubs
subroutine foo (DoubleArg) bind (C, name="Foo")
use iso_c_binding, only: c_double
real (kind=c_double), intent (inout) :: DoubleArg
end subroutine foo
end interface VisBasSubs