multiple definition link error in fortran (ifort - gfortran) - linker

Well, I've this problem (the description is long, but I think it is easy to solve) . I've three files:
nrtype.f90, which have some stupid definitions, but it is used by the following files:
module nrtype
integer, parameter :: I4B = SELECTED_INT_KIND(9)
integer, parameter :: I2B = SELECTED_INT_KIND(4)
integer, parameter :: I1B = SELECTED_INT_KIND(2)
integer, parameter :: SP = KIND(1.0)
integer, parameter :: DP = KIND(1.0D0)
endmodule nrtype
LUd.f90, which makes part of the work:
module descomposicionLU
use nrtype
implicit none
contains
subroutine LUd(A, LU, bk)
implicit none
real(DP), intent (in), dimension(:,:) :: A
real(DP), intent (out), dimension(:,:) :: LU
integer(I2B), dimension(size(A,1),2) :: bk
<more code that doesn't worth to mention>
endsubroutine LUd
<more code that doesn't worth to mention>
endmodule descomposicionLU
A file called FrontBackSub.f90, which does the other part of the work:
module FrontBack
use nrtype
implicit none
contains
function FrontSLU(A,B) result (X)
implicit none
real(DP), dimension(:,:), intent (in) :: A, B
real(DP), dimension(size(B,1),size(B,2)) :: X
<more code>
endfunction FrontSLU
endmodule FrontBack
And finallymain.f90, which is something like this:
program main
use descomposicionLU
use FrontBack
implicit none
integer, parameter :: N=3
real(DP), dimension(N,N) :: MA, MLU
integer(I2B), dimension(N,2) :: Vbk
MA(1,:)=(/1.0, 7.0, 11.0/)
MA(2,:)=(/14.0, 24.0, 19.0/)
MA(3,:)=(/7.0, 8.0, 9.0/)
call LUd(MA, MLU, Vbk)
endprogram main
But, the issue comes during compilation, with ifort nrtype.f90 FrontBackSub.f90 LUd.f90 FrontBackSub.f90 main.f90 i've got:
/tmp/ifortbW2y7D.o: In function `frontback._':
FrontBackSub.f90:(.text+0x0): multiple definition of `frontback._'
/tmp/ifortVQdBCN.o:FrontBackSub.f90:(.text+0x0): first defined here
/tmp/ifortbW2y7D.o: In function `frontback_mp_frontslu_':
FrontBackSub.f90:(.text+0x10): multiple definition of `frontback_mp_frontslu_'
/tmp/ifortVQdBCN.o:FrontBackSub.f90:(.text+0x10): first defined here
/tmp/ifortbW2y7D.o: In function `frontback_mp_backs_':
FrontBackSub.f90:(.text+0x460): multiple definition of `frontback_mp_backs_'
/tmp/ifortVQdBCN.o:FrontBackSub.f90:(.text+0x460): first defined here
Or, more clear, with gfortran nrtype.f90 FrontBackSub.f90 LUd.f90 FrontBackSub.f90 main.f90:
/tmp/ccpZnjOp.o: In function `__frontback_MOD_backs':
FrontBackSub.f90:(.text+0x0): multiple definition of `__frontback_MOD_backs'
/tmp/ccsr4QjQ.o:FrontBackSub.f90:(.text+0x0): first defined here
/tmp/ccpZnjOp.o: In function `__frontback_MOD_frontslu':
FrontBackSub.f90:(.text+0x582): multiple definition of `__frontback_MOD_frontslu'
/tmp/ccsr4QjQ.o:FrontBackSub.f90:(.text+0x582): first defined here
collect2: error: ld returned 1 exit status
So, it says that the functions (it is plural because when I add new functions the issue expand to them) in FrontBackSub.f90 are defined several times which, clearly, the are not.
Where is the problem that I can't see?
Thanks for your time pals.

Why do you have the source FrontBackSub.f90 two times in the compile command? Just don't do that.

Related

how to initialize a large array in Fortran?

I have a Fortran function in which I would like to initialize a large array at compile time. A simplified working example is below, where the parameter coeff in fill_coefficients has been reduced in size greatly.
How do I write similar code when coeff is large, without exceeding the maximum of 255 continuation lines, or the maximum of 132 characters per line? Here fill_coefficients should really be PURE, which probably makes it impossible to read coeff from a file once during runtime, and then store the result.
The file "main.f03":
PROGRAM main
USE coefficients
IMPLICIT NONE
REAL(dp), ALLOCATABLE, DIMENSION(:,:) :: matrix
CALL fill_coefficients(matrix,2)
PRINT *, "The first row of 'matrix':"
PRINT *, matrix(1,:)
END PROGRAM main
The file "coefficients.f03":
MODULE coefficients
USE iso_fortran_env
IMPLICIT NONE
INTEGER, PARAMETER :: dp = REAL64
CONTAINS
PURE SUBROUTINE fill_coefficients(my_coefficients, n)
IMPLICIT NONE
REAL(dp), ALLOCATABLE, DIMENSION(:,:), INTENT(OUT) :: my_coefficients
INTEGER, INTENT(IN) :: n
! The size of the following array would be roughly 200 x 200 = 40.000.
REAL(dp), DIMENSION(3,3), PARAMETER :: coeff = &
RESHAPE ( &
[ + 10.6770782520313112108115239655957106_dp, &
- 854.166260162504896864921917247656850_dp, &
- 85.4166260162504896864921917247656850_dp, &
+ 16250.5130995916556628551394756366716_dp, &
+ 6747.91345528378868523288314625648912_dp, &
+ 106.770782520313112108115239655957106_dp, &
- 123256.191341449456617608232658836883_dp, &
- 8328.12103658442274443298869316465429_dp, &
+ 500381.272281447399894682070647642979_dp ], &
[3,3] )
IF (ALLOCATED(my_coefficients)) DEALLOCATE(my_coefficients)
ALLOCATE(my_coefficients(n,n))
my_coefficients = coeff(1:n,1:n)
END SUBROUTINE fill_coefficients
END MODULE coefficients
The output:
The first row of 'matrix':
10.677078252031311 16250.513099591655
From a maintenance perspective (and as perhaps suggested in the comments), I would read the data into a module variable in a separate non-pure subroutine that is called once at program start-up. fill_coefficients then becomes a simple assignment from that module variable and can still be PURE.
MODULE coefficients
IMPLICIT NONE
...
! Could be PUBLIC, PROTECTED, then you could directly
! assign from it and dispense with fill_coefficients
! altogether.
REAL(dp), PRIVATE :: coeff(200,200)
CONTAINS
SUBROUTINE init
INTEGER :: unit
OPEN( NEWUNIT=unit, &
FILE='lots-of-numbers.bin', &
FORM='UNFORMATTED', &
! ACCESS='STREAM', & ! Maybe - depending on how you write it.
STATUS='OLD' )
READ (unit) coeff
CLOSE(unit)
END SUBROUTINE init
PURE SUBROUTINE fill_coefficients(my_coefficients, n)
! implicit none already in force due to the statement in
! the specification part of the host module.
! IMPLICIT NONE
REAL(dp), ALLOCATABLE, DIMENSION(:,:), INTENT(OUT) :: my_coefficients
INTEGER, INTENT(IN) :: n
! This test is redundant - my_coefficients is INTENT(OUT) so
! it must be not allocated at this point.
! IF (ALLOCATED(my_coefficients)) DEALLOCATE(my_coefficients)
! This allocate statement is redundant - allocation will
! happen automatically under F2003 with the assignment.
! ALLOCATE(my_coefficients(n,n))
my_coefficients = coeff(1:n,1:n)
END SUBROUTINE fill_coefficients
END MODULE coefficients
If you must have coeff as a compile time parameter, then assemble it in source manageable chunks - perhaps column by column. Your limits per declaration are line length (132) and number of continuation lines (255).
REAL(dp), PARAMETER :: column_1(200) = [ &
+ 10.6770782520313112108115239655957106_dp, &
- 854.166260162504896864921917247656850_dp, &
- 85.4166260162504896864921917247656850_dp, &
... ]
REAL(dp), PARAMETER :: column_2(200) = [ ... ]
...
REAL(dp), PARAMETER :: column_200(200) = [ ... ]
REAL(dp), PARAMETER :: coeff(200,200) = RESHAPE( [ &
column_1, column_2, ..., column_200 ], &
SHAPE=[200,200] )
Things declared with PARAMETER are named constants. Conceptually these only exist at compile time - depending on what you do with a named constant the compiler may or may not set aside storage in the executable image for the constants.
Large named constants may result in the compiler having issues compiling the file.

unknown wrong in a fortran array code

I checked this code many times and could not figure out how to correct it.
program main
implicit none
real, parameter :: dx=1
real, parameter :: dy=1
real :: a1, a2, a3, a4, a5
a1=dy/dx
a2=dx/dy
a3=-2*(dy/dx+dx/dy)
a4=dx/dy
a5=dy/dx
REAL, DIMENSION(5,1):: a
DATA a/a1,a2,a3,a4,a5/
!write (*,*) a(1),a(2)
pause
endprogram
thank you very much and the error:
error #6236:A specification statement cannot appear in the executable section.
error #6404: This name does not have a type, and must have an explicit type. [A]
error #6211: A symbol must be a defined parameter in this context.
You are mixing specification (data declaration) statements and executable statements. The declaration statements must go first and the executable statements can only follow after them inside each compilation unit or block.
Also, entity used for initialization in the DATA statement must be a constant expression.
One way to fix your code is:
program main
implicit none
real, parameter :: dx=1
real, parameter :: dy=1
real, parameter :: a1=dy/dx
real, parameter :: a2=dx/dy
real, parameter :: a3=-2*(dy/dx+dx/dy)
real, parameter :: a4=dx/dy
real, parameter :: a5=dy/dx
REAL, DIMENSION(5,1):: a
DATA a/a1,a2,a3,a4,a5/
!write (*,*) a(1),a(2)
end program
Don't use the PAUSE statement. It is deleted from modern Fortran and it is not clear (portably) what should it actually do even in the older versions.
You can also initialize the array using an array constructor. You don't need constant expressions in that case:
program main
implicit none
real, parameter :: dx=1
real, parameter :: dy=1
REAL, DIMENSION(5,1) :: a
a = reshape([dy/dx, dx/dy, -2*(dy/dx+dx/dy), dx/dy, dy/dx], [5,1])
end program

How to have generic subroutine to work in fortran with assumed size array

I have an interface block to define a generic subroutine which have an assumed size array as dummy argument (in order to be able to act on 'the middle' of a passed array, like a C pointer) and it does not compile. Here is simple exemple:
module foo
interface sub
module procedure isub
module procedure dsub
end interface
contains
subroutine isub(a,n)
integer, intent(in) :: a(*), n
integer :: i
print*, 'isub'
do i=1,n
print*, a(i)
enddo
end subroutine isub
subroutine dsub(a)
real(8), intent(in) :: a(*)
integer, intent(in) :: n
integer :: i
print*, 'dsub'
do i=1,n
print*, a(i)
enddo
end subroutine dsub
end module foo
program test
use foo
implicit none
integer :: ai(4)
real(8) :: ad(4)
ai=(/1,2,3,4/)
ad=(/1.,2.,3.,4./)
call sub(ai,3)
call sub(ad,3)
call isub(ai(2),3)
!call sub(ai(2),3)
end program test
The commented line does not compile, whereas it is ok when calling directly the subroutine with call isub(ai(2),3) (tested with gfortran and ifort). Why and is it possible to have it to work with call sub(ai(2),3)?
edit: with ifort, it says:
$ ifort overload.f90
overload.f90(37): error #6285: There is no matching specific subroutine for this generic subroutine call. [SUB]
call sub(ai(2),3)
-------^
compilation aborted for overload.f90 (code 1)
Thanks
You are passing a scalar to a function that is expecting an array. Try
call sub(ai(2:2))
which is passing an array of length one. I'm wondering why call isub(ai(2)) is accepted, though...
To answer your new question (partly in the comments):
If you restrict yourself to contiguous arrays, you can use call sub(ai(2:4)) without loss of performance using deferred shape arrays:
subroutine isub(a)
integer,intent(in) :: a(:)
integer :: i
print*, 'isub'
do i=1,size(a)
print*, a(i)
enddo
end subroutine isub
There are no temporary arrays created with ifort or gfortran. You can check for this using:
ifort -check arg_temp_created
gfortran -Warray-temporaries

Access violation error in passing array

Befor finding an answer for the quesion I asked before, I wrote very simple code for very sime mesh(there are just two triangles) as below to call C function in fortran. For the simplicity of code. Neither interface module here nor iso_c_binding(as possible as) isn't used here. It is very similar to this post, There is another error.
program METIS_NoInterface
implicit none
integer :: ne, nn
integer, dimension(:), allocatable :: eptr, eind
integer, pointer :: vwgt=>null(), vsize=>null()
integer :: nparts
real, pointer :: tpwgts=>null()
integer, dimension(0:39) :: opts
integer :: objval
integer, dimension(:), allocatable :: epart, npart
! Input => 2 tri: too small mesh
!ne = 2
!nn = 4
!nparts = 2
!allocate(eptr(0:2), eind(0:5))
!eptr=[0, 3, 4]
!eind=[0,1,3,1,2,3]
! Output
!allocate(epart(0:1), npart(0:4))
! Input => 4 quad : reasonable result
ne = 4
nn = 9
nparts = 2
allocate(eptr(0:ne), eind(0:15))
eptr=[0,4,8,12,16]
eind=[0,1,8,7,1,2,3,8,3,4,5,8,5,6,7,8]
! Output
allocate(epart(0:ne-1), npart(0:nn-1))
! METIS function call
call METIS_SetDefaultOptions(opts)
!call METIS_PartMeshNodal(ne,ne,eptr,eind,vwgt,vsize,nparts,tpwgts,& !<=syntax error
call METIS_PartMeshNodal(ne,nn,eptr,eind,vwgt,vsize,nparts,tpwgts,&
opts,objval,epart,npart)
! Result print
write(*,*) epart
write(*,*) ''
write(*,*) npart
write(*,*) ''
end program
It gives access violation error because of eind. It runs anyway if c_null_ptr are passed instead of eind. The size of array eind and number of elements are coincident. How can it be fixed? => resolved. Thank you!
The problem I had was systax error on calling METIS_PartMeshNodal, the 2nd argument was ne which is the same the 1st argument ne. It should have been nn.
Solution was to replace the 2nd argument to nn. Above code can be compiled and executed.
NOTE: Too small mesh may not have reasonable solution due to METIS' scheme.
Please refer another post in order to use interface module.

Can a input argument of a Fortran subroutine be deallocated and allocated in the body of the subroutine?

UPDATE: My modified code looks like this:
program run_module_test
use module_test
implicit none
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
call update(xyzArray)
write(6,*)'xyzArray',xyzArray
end program run_module_test
module module_test
implicit none
TYPE :: newXYZ
real(4) :: x, u
real(4) :: y, v
real(4) :: z, w
real(4),dimension(3) :: uvw
END TYPE
integer(4) :: shape = 3
contains
subroutine update(xyzArray)
integer(4) :: i
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
allocate( xyzArray(shape) )
do i = 1, shape
xyzArray(i)%x = 0
xyzArray(i)%y = 0
xyzArray(i)%z = 0
xyzArray(i)%u = 0
xyzArray(i)%v = 0
xyzArray(i)%w = 0
xyzArray(i)%uvw = (/0,0,0/)
end do
return
end subroutine update
end module module_test
When they are compiled, they generate a similar error:
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
1
Error: ALLOCATABLE attribute conflicts with DUMMY attribute at (1)
When I eliminate the argument in update() subroutine, I receive a contradictory error:
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
1
Error: Symbol at (1) is not a DUMMY variable
Have I eliminated the sources of error pointed out in the helpful suggestions? Could this be a compiler related error (using mpi90)?
~~~First Edit~~~
I have a subroutine whose input argument is an array of user defined type XYZ. I wish to deallocate xyzArray and allocate/modify it to a different size in the body of the subroutine. I attempted the method suggested by changing array dimensions in fortran, but when I do the following:
subroutine update(xyzArray, ...)
...
TYPE (XYZ), allocatable :: xyzArray(:)
I receive an error message:
Error: ALLOCATABLE attribute conflicts with DUMMY attribute at (1)
When I try:
subroutine update(xyzArray, ...)
...
deallocate( xyzArray(myshape) )
allocate( xyzArray(newshape) )
I receive error messages:
Error: Expression in DEALLOCATE statement at (1) must be ALLOCATABLE or a POINTER
Error: Expression in ALLOCATE statement at (1) must be ALLOCATABLE or a POINTER
What do I need to do to change the size of the array in the subroutine?
To do this:
The dummy argument must be allocatable. Allocatable dummy arguments require a compiler that implements the relevant part of the Fortran 2003 standard (or a Fortran 95 compiler that implements the so called "allocatable" TR).
An explicit interface to the procedure is required (the procedure must be a module procedure, an internal procedure or have an interface block in the calling scope).
The dummy argument must not be intent(in). If you are not using the allocation status or other aspects of the value of the dummy argument at all in the subroutine then intent(out) may be appropriate (if allocated beforehand the dummy argument will be automatically deallocated when the procedure is called), otherwise intent(inout) or no intent.
(Your second block of example code has a syntax error with the deallocate statement - you should simply specify the xyzArray variable, leave off the (myshape) shape specification))
For example, in a module:
subroutine update(xyzArray)
type(xyz), allocatable, intent(inout) :: xyzArray(:)
...
if (allocated(xyzArray)) deallocate(xyzArray)
allocate(xyzArray(newshape))
...
If you are sure, you want to deallocate the array in your subroutine, you can declare the dummy argument being intent(out), so that it is deallocated automatically when the subroutine is entered:
module whatever
implicit none
type :: xyz
:
end type xyz
contains
subroutine update(xyzArray)
type(xyz), allocatable, intent(out) :: xyzArray(:)
:
allocate(xyzArray(someshape))
:
end subroutine update
end module whatever
As already noted by IanH, the process must have an explicit interface (e.g. being enclosed in a module) and in the caller program you must declare the actual argument allocatable:
program test
use whatever
implicit none
type(xyz), allocatable :: array(:)
:
call update(array)
:
end program test

Resources