External naming of fortran subroutine inside a module using GCC - gcc

My objectif is to rename a fortran subroutine inside a module to be easily callable by C code (i.e. without the __<modulename>_MOD_ prefix), and using GCC-6.3.0. I cannot use bind(c,name='') even if it works great. I have read that I should use interface, but without any success. Here is the MWE:
module testmodule
interface
subroutine func02
!GCC$ ATTRIBUTES CDECL :: func01
end subroutine
end interface
contains
subroutine func01
print*,"func01"
end subroutine
end module
I compile using command gfortran -c test.f90 and then I check if the subroutine is correctly renamed using nm test.o, but there is no sign of func02.
Any help appreciated.

You can use BIND(C) to rename the subroutine. Whatever you read about INTERFACE seems to be a red herring.
module testmodule
contains
subroutine func01() bind(c, name='func2')
print*,"func01"
end subroutine
end module
With the simple command 'gfortran -c a.f90', I see the following results
nm a.o
U _gfortran_st_write
U _gfortran_st_write_done
U _gfortran_transfer_character_write
00000000 T func2

Related

"Can't open module file 'types.mod'" when compiling a main.f90 program

A quick run down:
I'm new to fortran
I'm on a windows machine
Using sublime to edit an assignment fortran code
The assignment includes a main.f90 file (see the below image of the code for that file)
This main.f90 code calls in 3 different modules: 'types' and 'analytic_functions', and
'euler_formulas'
The following error keeps appearing whenever I try to run the command gfortran main.f90 in my windows command prompt:
Fatal Error: Can't open module file 'types.mod' for reading at (1): No such file or directory compilation terminated.
How do I fix this issue? All help will be greatly appreciated.
Here's the main.f90 code:
module read_write
use types
use analytic_functions, only : second_derivative_f
use euler_formulas, only : euler_3points
implicit none
private
public read_input, write_derivatives
contains
I don't know if this would help but here's the 'types.f90' code:
module types
! The iso_fortran_env is an intrinsic module that should already be
! inside of your compiler
use iso_fortran_env
implicit none
integer, parameter :: sp = REAL32 !< single precision kind
integer, parameter :: dp = REAL64 !< double precision kind
integer, parameter :: qp = REAL128!< quadruple precision kind
real(dp), parameter :: pi=acos(-1.0_dp)!< π = 3.141592...
end module types
Note: these .mod files are more or less like C headers, they allow the compiler to check types at compile time, which was usually not possible in Fortran 77 when compiling from several source files. They are created when you compile the modules.
Hence, you have first to compile the modules. Note that to compile and link main.f90, you also have to pass the object files to gfortran, otherwise the linker won't be able to resolve references to functions from these modules.
gfortran -c types.f90
gfortran -c analytic_functions.f90
gfortran -c euler_formulas.f90
gfortran main.f90 types.obj analytic_functions.obj euler_formulas.obj
The gfortran compiler is also able to compile all files at once, but you must pass the files in a specific order: if program or module B uses module A, then B.f90 must be after A.f90 on the command line. This is necessary for the compiler to find the .mod files when they are used.
gfortran types.f90 analytic_functions.f90 euler_formulas.f90 main.f90

Compile Module and Main Program In the Same File Using GFortran?

I am new to fortran and I have this fortran90 program I am trying to run where the module and the main are in the same file called main.f90:
module real_precision
implicit none
integer, parameter :: sp = selected_real_kind(1)
integer, parameter :: dp = selected_real_kind(15)
end module real_precision
program main_program
use real_precision
implicit none
real(sp) :: a = 1.0_sp
real(dp) :: b = 1.0_dp
print *, a
print *, b
end program main_program
And I compiled it once doing:
gfortran main.f90 -o main.x
Then run it:
./main.x
However I made a change to the module and saved it but compiling and running it this same way provides the same output which leads me to think that the module needs to be compiled? How do I compile both where they're in the same file? I could make the module a separate file but I'd like to know how to do it this way!
selected_real_kind(p) returns the kind parameter of a real with precision at least p digits (if one exists). It does not give a kind parameter for a real with exactly that precision.
If your compiler has does not have a real with precision less than q then selected _real_kind(q) and selected_real_kind(q-1) will not return different kind parameters.

How does using modules that use other modules affect compilation? (gfortran)

I asked a question about some strange behavior from a Fortran compiler here:
gfortran compiler cannot find misspelled full directory
Basically, the compiler sporadically** complains that a file is missing, but the problem is that the printed name of the file (full path, actually) is misspelled, so no wonder it's "missing". I thought that I resolved the problem by using relative paths, but it turns out that the problem was just dormant. Here's an example of one such complaint:
C:\Users\charl\Documents\GitHub\MOONS>gfortran -fopenmp -g -fimplicit-none -cpp
C:/Users/charl/Documents/GitHub/MOONS/code/globals/current_precision.f90
...
C:/Users/charl/Documents/GitHub/MOONS/code/solvers/induction/init_Bfield.f90
C:/Users/charl/Documents/GitHub
gfortran: error:
C:/Users/charl/Documents/GitHubMOONS/code/solvers/induction/init_Sigma.f90: No such file or directory
Notice that the forward slash ('/') is missing between GitHub and MOONS, and instead reads "GitHubMOONS". This path was correctly written in the makefile.
** I say sporadically because changing lines in the code sometimes results in the error disappearing. Similarly, removing some unused modules (that compile just fine) from my compilation list results in the error disappearing.
The compiler I'm using is:
GNU Fortran (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 4.9.2 Copyright (C) 2014 Free Software Foundation, Inc.
But I've seen the same problem with more recent compilers, e.g.:
x86_64-7.1.0-release-posix-seh-rt_v5-rev2
I think I am seeing a trend with when this error occurs, and it seems to occur more frequently when modules pass on public interfaces to other modules.
Question
So, my question is, given the following two modules:
module add_int_mod
implicit none
private
public :: add
interface add; module procedure add_int; end interface
contains
subroutine add_int(a,b)
implicit none
integer,intent(inout) :: a
integer,intent(in) :: b
a = a + b
end subroutine
end module
module add_all_mod
use add_int_mod
implicit none
private
public :: add
end module
What is the difference between these two programs, if any?
Program 1
program main
use add_all_mod ! only difference
implicit none
integer :: a,b
a = 0
b = 1
call add(a,b)
write(*,*) 'a = ',a
write(*,*) 'b = ',b
end program
Program 2
program main
use add_int_mod ! only difference
implicit none
integer :: a,b
a = 0
b = 1
call add(a,b)
write(*,*) 'a = ',a
write(*,*) 'b = ',b
end program
I appreciate any help/suggestions.

Renaming a subroutine in a Fortran module when using iso_c_binding

I am working with two Fortran modules. The first one contains a subroutine foo:
module fmod1
contains
subroutine foo(i)
implicit none
integer, intent(inout) :: i
i=i+1
end subroutine foo
end module fmod1
The second one also contains a subroutine called foo which calls the foo of the first module, renamed as foo_first:
module fmod2
use fmod1, only : foo_first => foo
contains
subroutine foo(i)
implicit none
integer, intent(inout) :: i
i=i+2
call foo_first(i)
end subroutine foo
end module fmod2
When I compile these with gfortran to get two object files and then look inside them with nm, I see the expected result:
fmod1.o:
0000000000000020 s EH_frame1
0000000000000000 T ___fmod1_MOD_foo
fmod2.o:
0000000000000030 s EH_frame1
U ___fmod1_MOD_foo
0000000000000000 T ___fmod2_MOD_foo
I then have no problem in writing a Fortran program which loads the second module and calls the foo within it (___fmod2_MOD_foo, which itself calls ___fmod1_MOD_foo).
My problem comes when I try to do the same thing from a C program using iso_c_binding. I change the second module by adding bind(c) to the subroutine:
module fmod2
use iso_c_binding
use fmod1, only : foo_first => foo
contains
subroutine foo(i) bind(c)
implicit none
integer, intent(inout) :: i
i=i+2
call foo_first(i)
end subroutine foo
end module fmod2
Running nm again on the object files now gives this:
fmod1.o:
0000000000000020 s EH_frame1
0000000000000000 T ___fmod1_MOD_foo
fmod2.o:
0000000000000030 s EH_frame1
0000000000000000 T _foo
i.e., the second module no longer seems to require the first module. When I try experimenting with calling foo from the second module from a C program it becomes apparent that the subroutine, instead of calling foo from the first module, is calling itself in an infinite loop.
Is this a bug, or am I doing something which I shouldn't be doing?
When you add BIND(C) to the procedure, you are specifying (indirectly) the binding name instead of the compiler applying its own rules (that include the module name).
It's not that "the second module no longer seems to require the first module" but that you've changed the binding name of the routine in the second module. You haven't touched the binding name of foo in the first module (which is not its local name due to the rename.)
That said, the compiler ought to know the binding name of foo in the first module, referenced through its local name, and put out the correct name in the object for the call. From what other commenters have said, the version of gfortran you're using may have a bug here. Try a newer one.
This is now GCC Bug 79485. I have already reported very similar and very probably related bugs before (ICE with binding-name equal to the name of a use-associated procedure and Wrong subroutine called, clash of specific procedure name and binding-name). Unfortunately the gfortran developers are only a few and very busy and did not fix this problem yet. If they see other people encountering it they might consider it with a slightly higher priority.

Change of directory in Fortran in a non compiler-specific way

I wish to change the working directory in a Fortran 90 code. Is it possible to do this in a non compiler-specific way? Here is my code:
program change_directory
integer :: ierr
call system("mkdir -p myfolder/")
!call system("cd myfolder/") !doesn't work
ierr = chdir("myfolder")
if (ierr.NE.0) then
write(*,'(A)') "warning: change of directory unsuccessful"
end if
open(unit=33,file="myfile.txt",iostat=ierr)
if (ierr.EQ.0) then
write(unit=33,fmt='(A)') "Test message"
close(unit=33)
end if
end program change_directory
Clearly, using cd myfolder/ in a system call doesn't work. The Intel reference says I need to add 'use ifport'. There's no such mention in the GCC reference, though. Leaving out 'use ifport', I can compile the above code under ifort without any trouble. When I put it in, however, it won't compile with gcc (because gcc doesn't have the ifport module)--and not only that, it won't compile under Intel Fortran either--I'm getting the following error:
$ ifort change_dir.f90 -o change_dir
change_dir.f90(5): error #6552: The CALL statement is invoking a function subprogram as a subroutine. [SYSTEM]
call system("mkdir -p myfolder/")
---------^
compilation aborted for change_dir.f90 (code 1)
So my question is the following: is there a better way to do this? I'd like to keep my code as compiler-independent as possible. At the moment, I primary use gfortran/ifort and mpif90/mpiifort.
See also Is there any way to change directory using C language? . You can make your own interface to the chdir() POSIX call to be independent of the Intel's interface. On Windows it is similar.
module chdir_mod
implicit none
interface
integer function c_chdir(path) bind(C,name="chdir")
use iso_c_binding
character(kind=c_char) :: path(*)
end function
end interface
contains
subroutine chdir(path, err)
use iso_c_binding
character(*) :: path
integer, optional, intent(out) :: err
integer :: loc_err
loc_err = c_chdir(path//c_null_char)
if (present(err)) err = loc_err
end subroutine
end module chdir_mod
program test
use chdir_mod
call chdir("/")
call system("ls -l")
end
and when run
> gfortran chdir.f90
> ./a.out
celkem 120
drwxr-xr-x 2 root root 4096 15. říj 14.42 bin
drwxr-xr-x 5 root root 4096 15. říj 14.43 boot
...
On ifort it works too as it does on sunf90.
(Note: this relies on default character being the same as c_char. That is quite a safe assumption. If it is not the case the compiler will complain and a conversion has to be made.)

Resources