Using modules in Fortran: Undefined reference to `parse_' - c

I am trying to use the parse routine described here to parse a string in Fortran90. When following the link in the document one can download a .zip with two f90-files, which I have done. I have then compiled them gfortran -c precmod.f90 && gfortran -c stringmod.f90. I have also added use strings to my program.
Despite of this, I receive the following error when compiling (gfortran stringmod.o precmod.o calcs.o server.o):
calcs.o: In function `calculate_':
calcs.f90:(.text+0x174): undefined reference to `parse_'
collect2: error: ld returned exit status 1
calcs.f90 is shown below and server.o is a server written in C that should be invoked by calcs.
program name
use strings
use iso_c_binding, only: C_CHAR, C_NULL_CHAR, C_INT
implicit none
! type declaration statements
character(255) query
integer calc, ans, portnum, calculate
interface
subroutine server(portnum) bind(C, name="server")
use iso_c_binding, only: c_int
integer(kind=c_int), value :: portnum
end subroutine server
end interface
! executable statements
print *, "Please provide me with a port number. Plz. <3"
read "(1i9)", portnum
call server(portnum)
end program name
function calculate(query)
implicit none
character(255) query, op
integer length, i, calculate
integer, dimension (:,:), allocatable :: inputarray
call parse(query, ' ', inputarray, length)
do i=1,size(inputarray)
print *, inputarray(i, 1)
end do
calculate = 5
end function calculate
I have tried to add public to the top of stringmod.f90.

When we have something like
program
end program
function func()
end function
then the function func is an external function, even when this is given in the same source code file as the main program. This external function knows nothing about the main program, and in turn the main program knows little about the external function.
Part of this lack of knowledge is that, in the example of the question, the fact that the subroutine parse has an explicit interface (through the module) in the main program is irrelevant to calculate.
That is, the function calculate has its own scope and has no host. To gain access to the module procedure parse it can itself use the module strings:
function calculate(query)
use strings, only : parse
implicit none
end function
There is a hint to this lack of being aware that parse is a module procedure in strings. The name decoration in parse_ (that single trailing underscore) is a common way to mangle an external procedure. Module procedures (without bind(c)) generally have much more elaborate symbol names.
Finally, I'll repeat something from the comments. Earlier, I said that the main program knows little about the external function. In the main program we have the declaration
integer ... calculate
which says that the external function calculate (which has an implicit interface) has a return type of integer. The function, in this case, could instead be made an internal function
program
use strings, only : parse
contains
integer function calculate
end function
end program
and not only does the function calculate have an explicit interface (removing also the need for that return declaration in the main program) but it also has access to parse through host association.

Related

Fortran interface allowing rank-1 arrays and scalars

Background: GCC 10 removed support for calling subroutines with different typed arguments. My aim is to write an interface that respects both integer, dimension(:) and integer.
(Which means I can't use other options such as embedding the scalar in an array. I have to change the interface)
According to GCC docs:
It is possible to provide standard-conforming code which allows different types of arguments by using an explicit interface and TYPE(*).
and:
Note, however, that TYPE(*) only accepts scalar arguments, unless the DIMENSION is explicitly specified. As DIMENSION(*) only supports array (including array elements) but no scalars, it is not a full replacement for C_LOC. On the other hand, assumed-type assumed-rank dummy arguments (TYPE(*), DIMENSION(..)) allow for both scalars and arrays, but require special code on the callee side to handle the array descriptor.
In the interface below I have type(*), dimension(:) :: data. How can I change it according to the text I've emphasized above?
module z
interface
subroutine a(data)
type(*), dimension(:) :: data
end subroutine a
end interface
contains
subroutine b(data)
integer :: data
call a(data)
end subroutine
subroutine c(data)
integer, dimension(:) :: data
call a(data)
end subroutine
end module
Godbolt playground
I am not aware of GCC 10 removing anything (what is your source for that?) but exactly for the reasons you mention, GCC also introduced the directive
!GCC$ attributes no_arg_check::A
(see Procedure for any type of array in Fortran )
which was already used in other compilers that enables the procedure to be called with any arguments, scalars or arrays of any rank, mainly for routines that accept buffers of any type, particularly in MPI libraries.
The new DIMENSION(..) is not really suited for use within Fortran, it requires special code that understands the standard Fortran array descriptor and it is mainly expected that it will be written in C. However, according to the very page you linked https://gcc.gnu.org/onlinedocs/gfortran/Further-Interoperability-of-Fortran-with-C.html#Further-Interoperability-of-Fortran-with-C gfortran does not yet support the standard array descriptor.

Fortran array mismatch in subroutine but no error?

I have a program that seems to work properly,
but I don't understand how it can,
because there seems to be an obvious error.
Main program(which use 'implicit') calls a subroutine:
implicit integer(i-n)
implicit double precision(a-h,o-y)
implicit complex*16(z)
call do_coulomb(zvecs0,zdualvecs0,n_f,n_f,1,
$ nsubfilling,zcorrmatrix,0,aldet01abs,
$ zcoulomb,epsilon)
where arrays, 'zvecs0','zdualvecs0','zcorrmatrix' are declared,
but there is no declaration of 'nsubfilling' anywhere.
(It could be a mistake or remnant of old version.)
Since I could not find
any declaration of array 'nsubfilling' in main program
('grep -i nsubfilling *' ),
I suppose 'nsubfilling' will be treated as an integer variable.
This is a subroutine of question:
subroutine do_coulomb(zvecs,zdualvecs,n_A,n_Ap,n_C,
$ nsubfilling,zcorrmatrix,n1_p0,aldet01abs,
$ zcoulomb,eps)
implicit integer(i-n)
implicit double precision(a-h,o-y)
implicit complex*16(z)
include "input.inc"
dimension zvecs(0:L-1,0:L-1,0:L-1,0:Lt,0:1,0:1,0:n_f-1)
dimension zdualvecs(0:L-1,0:L-1,0:L-1,0:Lt,0:1,0:1,0:n_f-1)
dimension nsubfilling(0:n_Ap-1,0:n_C-1)
dimension zcorrmatrix(0:n_Ap-1,0:n_Ap-1)
('L' 'Lt' are defined in the "input.inc" file.)
Because 'nsubfilling' is defined as an array in the subroutine,
I thought the mismatch between main and subroutine would cause an error.
However, the program seems to run okay even with mismatch.
I tried to print out some variables.('n_f'=4,'n_c'=1 in this run)
This is the output:
Before 1st call in main:
nsubfilling= 1
zcorrmatrix(0,0)= (20.510951695209510,0.13579118691198364)
zcorrmatrix(0,1)= (-1.0490102491588316,0.59453967445518319)
zcorrmatrix(1,0)= (-1.3791781667351797,-0.26247624491732802)
zcorrmatrix(n_f-1,n_f-1)= (20.510951695209513,-0.13579118691198364)
Inside do_coulomb subroutine:
nsubfilling= 1 0 1 1
zcorrmatrix(0,0)= (20.510951695209510,0.13579118691198364)
zcorrmatrix(0,1)= (-1.0490102491588316,0.59453967445518319)
zcorrmatrix(1,0)= (-1.3791781667351797,-0.26247624491732802)
zcorrmatrix(n_f-1,n_f-1)= (20.510951695209513,-0.13579118691198364)
n1p0= 0
After 1st call in main:
nsubfilling= 1
zcorrmatrix(0,0)= (20.510951695209510,0.13579118691198364)
zcorrmatrix(0,1)= (-1.0490102491588316,0.59453967445518319)
zcorrmatrix(1,0)= (-1.3791781667351797,-0.26247624491732802)
zcorrmatrix(n_f-1,n_f-1)= (20.510951695209513,-0.13579118691198364)
The output shows that 'nsubfilling' is treated as an integer in main routine,
but considered as an array in the subroutine and also
the subroutine recognizes 'zcorrmatrix' correctly
even with mismatch.
But, how this can be possible? I think there should be an error.
Could you let me understand how it work?
Thank you.
The main program does not have an explicit interface to subroutine do_coulomb. This means that the main program cannot check at compilation time whether the ranks of the actual arguments in the main program match the ranks of the dummy arguments in the subroutine.
An explicit interface can be provided in a number of ways:
having subroutine do_coulomb as an internal subprogram of the main program (subroutine after main subprogram, after a CONTAINS statement and before the END statement of the main program), this is called host association;
via an interface block in the main program (provide name of subroutine, list of dummy arguments, their types and attributes); or
by including the subroutine inside of a module (foo) and adding a use statement (use module foo) before the implicit declarations, this is called use association.
Why is your program not crashing? Well, because subroutine do_coulomb thinks it has access to a chunk of memory corresponding to nsubfilling of the size specified inside of the subroutine, and it happens to not do anything otherwise illegal when manipulating it - the chunk of memory happens to be in use by the same application. If the declared size of nsubfilling was very very big, and/or you had fewer arrays declared, it is likely that access to nsubfilling led to a segmentation fault.
Note that, even if you have an explicit interface, the ranks and the dimensions may not match - and that can be legal, as long as the total size of the dummy argument in the subroutine is not larger than the total size of the actual argument in the main program.

Fortran and C Mixed Programming (Shared Memory)

I have an existing Fortran codebase I'm working with and it's quite large. I am no Fortran programmer so I know that I'm not doing everything correctly here.
I'm trying to create and initialize an array of 1.6 million integers. I cannot get this to initialize in Fortran (using ifort or gfort) as I either would have too many line continuations or too long of lines.
So naturally, I switched to C and wrote a function to just initialize an array and it compiles in seconds with no problem. Now I'm trying to link the two together properly. I created a small test case here to simplify things. Here are the three files I'm working with:
init.c
void c_init_()
{
static const int f_init_g[1600000] =
{
3263, 322, 3261, 60, 32249, 32244, 3229, 23408, 252407, 25326,
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806,
---------------------------------------------------------------------
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806
};
}
init_mod.f90
MODULE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
SAVE
TYPE :: INIT_TYPE
INTEGER (C_INT), DIMENSION(1600000) :: INIT
END TYPE INIT_TYPE
TYPE (C_PTR), BIND(C,NAME="f_init_g") :: INIT_CP
TYPE (INIT_TYPE), POINTER :: INIT_FP
END MODULE INIT_MOD
main.f90
PROGRAM INIT
USE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
TYPE (INIT_TYPE) :: INIT_T
CALL c_init()
CALL C_F_POINTER(INIT_CP,INIT_FP)
INIT_T = INIT_FP
END PROGRAM INIT
I compile this using the following commands:
icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o
I get a segmentation fault when running because INIT_CP points to nothing as far as I can tell. I know I'm not successfully getting INIT_CP to point at the array in my C function. So I'm trying to figure out how to do that.
I would like if someone has a suggestion on how to initialize this array natively in Fortran. My final option that I'll do is make a small initialization of this array in assembly and write a script to generate the assembly code to initialize this array myself (based off the assembly from the small initialization I can mimic the same thing for any size array). I'm not as excited to do that, but it may be the easiest and most reliable solution.
Most importantly I want other Fortran subroutines that use this array to see that it is static in shape and value so that appropriate inter procedural optimizations can be done.
Fortran-C Interoperable variables must have external linkage. As suggested by others in the comments, move the C declaration to file scope and lose the static specifier.
There is no need for an intermediate C_PTR - a Fortran array variable is directly interoperable with the appropriate C array.
Reducing the size of the array slightly:
/* C File scope */
const int f_init_g[3] = { 101, 102, 103 };
! Fortran
MODULE m
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT
IMPLICIT NONE
INTEGER(C_INT), BIND(C, NAME='f_init_g') :: f_init_g(3)
END MODULE m
PROGRAM p
USE m
IMPLICIT NONE
PRINT *, f_init_g(2)
END PROGRAM p
Note that the starting premise - that it is impossible to define or initialize such an array from within Fortran only - is false. The rules around constant expressions in Fortran permit reference to existing named constants, including named constants that are arrays. If you decide to persist with this madness, and assuming that the value of the initializer cannot be described by some sort of expression, consider:
INTEGER, PARAMETER :: first(10) &
= [ 3263, 322, 3261, 60, 32249, &
32244, 3229, 23408, 252407, 25326 ]
INTEGER, PARAMETER :: second(10) &
= [ 25805, 25723, 25562, 25787, 4549, &
32248, 32244, 32243, 253207, 21806]
...
INTEGER, PARAMETER :: f_init_g(1600000) = [ first, second, ... ]
You will probably need intermediate named constant arrays before the final array constructor.
In the immediate above, f_init_g is a named constant, which is very visible to the compiler, and more likely to result in the optimisations that you seek.
However, you may run into compiler complexity limits, that defeat this latter approach.
When f_init_g is a variable initialized by C, you are basically reliant on the inter-language and inter-procedural optimisation capabilities of your tool set - and if those capabilities even exist, I wouldn't expect much from them for this case. I expect that you aren't going to lose much performance wise, beyond the one-off time for IO, if you read the value of the array in from a file at runtime.

Does the Intel Fortran 95 compiler allow module arrays to be of non-constant size?

I have downloaded a Fortran 90/95 adaptive mesh refinment library (Paramesh), and now I'm trying to compile an example program that came with it. In the process I modified the Makefile to use gfortran instead of the Intel Fortran compiler.
In the library code, there is a module containing this snippet:
module physicaldata
! Many many lines of variable definitions here
!....
Public :: nfluxvar
Integer,Save :: nfluxvar
! Many many lines of variable definitions here
!....
end module physicaldata
Elsewhere there is
module flux_assign
use physicaldata
integer :: iflux_target(nfluxvar)
end module flux_assign
which is causing this error:
advance_soln_vdt.F90:16.40:
Included at amr_main_prog.F90:29:
integer :: iflux_target(nfluxvar)
1
Error: The module or main program array 'iflux_target' at (1) must have constant shape
Would that code work if compiled using another compiler? I know that with standard Fortran, or at least the one used by gfortran, requires that integer variables which are used to denote array sizes should have the parameter keyword attached to them. Is that not the case for other Fortran compilers? Do other compiler include non-standard features such as this?
Current Intel Fortran issues an error for this code.
The standard language requires that non-allocatable, non-pointer arrays declared in the specification part of a module (or main program or block data or submodule, and arrays used in a few other places) must have constant array bounds.
iflux_target is such an array.
A program with such an array is non-conforming, and will not be accepted without diagnostics by a standard conforming Fortran processor. If portability is your goal, then do not use this sort of feature. Lack of a diagnostic from previous versions of Intel Fortran was presumably an oversight.
Module arrays that need to have their size specified by a variable should be made allocatable, with the array allocated in an "initialise" procedure or similar before the operations proper provided by the module are used.
The integer used to specify a statically allocated array cannot have the save attribute in fortran as this implies it will change during the run (otherwise why use save). As the array is statically allocated, its bounds cannot change. Check out this answer for more details.
This flags the following error on the intel compiler too,
An automatic object must not appear in the specification part of a module
Note that specifying the value of nfluxvar, e.g.
integer :: nfluxvar=5
does not mean you can use it to define an array size unless you explicitly tell the compiler that it's a parameter.
There is no need to use a parameter statement for the array size nfluxvar if you use a dynamically allocated array. If you want to avoid this problem, using dynamic allocation is the best solution as it explicitly sets the array size to the current value of nfluxvar. You can even reallocate if this changes, for example,
module physicaldata
! Many many lines of variable definitions here
!....
Public :: nfluxvar
Integer,Save :: nfluxvar
! Many many lines of variable definitions here
!....
end module physicaldata
module flux_assign
use physicaldata
integer, allocatable, dimension(:) :: iflux_target
end module flux_assign
program main
use flux_assign
if (.not. allocated(iflux_target)) then
allocate(iflux_target(nfluxvar))
elseif (size(iflux_target) .ne. nfluxvar) then
deallocate(iflux_target)
allocate(iflux_target(nfluxvar))
endif
end program main
In a way this isn't truly an answer. However, any compliant Fortran compiler must have the ability to detect and report violations of specified constraints within the Fortran language specification. The constraint you come up against in the code is indeed one of those. So, does there exist a Fortran compiler which has the ability to detect this but chooses not to? I don't know. But I'd think not.
So, what is the constraint? Unless nfluxvar is a constant expression iflux_target will be an automatic object. Such an automatic object is not allowed in the scoping unit of a module - see C554 and surrounding text in Fortran 2008.
To answer the question in the title: ifort will complain loudly about such attempts.

Different number parameters calling C routine from FORTRAN 90

I am calling a C routine from a FORTRAN 90 code. All works fine, but I am wondering why and how when I call the C routine with less parameters that I should the compiler does not complain. What is the compiler doing here? I am using a Cray compiler.
test.c
extern "C" void test_(double* x, double* y, double* z){
// do some work
}
driver.F90
MODULE DRIVER
! declare arrays
DOUBLE PRECISION, DIMENSION(dim, dim), INTENT(IN) :: x
DOUBLE PRECISION, DIMENSION(dim, dim), INTENT(IN) :: y
! call C subroutine
CALL test(x, y)
END MODULE DRIVER
Fortran is a lot different than C when it comes to function calls. When passing arguments to a C routine, the compiler must know the type of each argument, so that it can generate the appropriate calling sequence - either put the arguments on the stack in the correct order and with the correct padding or put them in the expected registers. C compilers usually gather this information when then compile the code if the callee is defined before the caller. In all other cases, a function declaration in the form of a prototype should be provided.
In Fortran all arguments are typically (with some exceptions) passed by address, which means that what actually gets passed to the callee is a set of memory pointers. Pointers look the same - they are always of the same type and hence passed the same way. Therefore a Fortran compiler can generate a function call without knowing what arguments the callee is actually expecting. This greatly simplifies the Fortran compilers but is then a source of myriads of possible errors, like calling a function with the wrong argument types or even with the wrong number of arguments, to name a few. Special programs, called linters (from the name of the C programs verification utility lint), usually have to be used in order to guarantee that no such errors are present. Modern Fortran compilers also try to be much stricter than the older ones and try their best to detect errors whenever possible.
Modern Fortran versions provide the INTERFACE construct that allows explicit declaration of function interfaces, very much similar to function prototypes in C. Module subroutines and functions get their interfaces generated automatically and made available to the callers that USE the module. When calling a subroutine/function with an explicit interface, the compiler is able to verify the validity of the call, i.e. it checks if the number of arguments and their types matches the one in the interface.
You should provide an interface for the external routine and then the compiler would be able to perform the checks. One usually uses the ISO_C_BINDING method in order to interface to C code:
INTERFACE
SUBROUTINE test(x, y, z) BIND(C, NAME="test")
USE, INTRINSIC :: ISO_C_BINDING
REAL(KIND=C_DOUBLE), INTENT(...) :: x ! Put the proper intents
REAL(KIND=C_DOUBLE), INTENT(...) :: y
REAL(KIND=C_DOUBLE), INTENT(...) :: z
END SUBROUTINE test
END INTERFACE
With this interface in place, CALL test(x, y) would result in compile-time error because of argument count mismatch.

Resources