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

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.

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.

Unable to suppress bound checking

Firstly, I wasn't aware that bound checking was automatic when using gfortran. With the following code:
gfortran -Wno-array-bounds initial_parameters.f08 derrived_types.f08 lin_alg.f08 constitutive_models.f08 input_subs.f08 Subprograms.f08 mainprog.f08
I still receive the compile time warnings:
Warning: Array reference at (1) is out of bounds (3 > 2) in dimension 2
I am probably being silly here but from reading this, I thought that -Wno-array-bounds was supposed to suppress this warning? Compiling with -w successfully inhibits all warnings.
I don't know if it's relevant but the source of these warning are "Subprograms.f08" and "constitutive_models.f08" which are both modules containing subroutines and are used in the main program.
The same behaviour occurs if I attempt to compile an individual module with
gfortran -Wno-array-bounds -c constitutive_models.f08
I can confirm that compile warning with gfortran (4.4) with this simple code:
integer,parameter::dim=3
integer :: x(2)
if(dim.eq.1)write(*,*)x(dim)
end
Warning: Array reference at (1) is out of bounds (3 > 2) in dimension 2
this could arguably be considered a bug since one would expect the compiler to optimize out the whole if statement. Note ifort compiles this just fine.
a very simple workaround fixes this example:
integer,parameter::dim=3
integer :: x(2),dimx=dim
if(dim.eq.1)write(*,*)x(dimx)
end
of course since its just a warning, and you know its not a problem, you can choose to ignore it too !
note the use of the parameter in the logical, in case the compiler feels like optimizing it later.
So what I may suggest is to use overloaded subroutines in order to process the data - then you would have generic behavior without the need to pass the dimension argument explicitly to the function(thus getting rid of the warning). And then I would recommend you to follow Holmz's advice regarding using all warnings during testing stage and then completely turning them off during production build (-w). For now I wasn't able to find an efficient way of suppressing this warning (apart from -w) - it seems that the check for array bounds is on by default and is not overridden -fno-bounds-check or -Wno-array-bounds. But overloaded functions can be a better solution to your problem, the implementation should look like this in this case:
module functions
implicit none
interface test_dim
module procedure test_func1d, test_func2d, test_func3d
end interface ! test_dim
contains
subroutine test_func1d(input1d)
real, intent(in) :: input1d(:)
print*, "DOING 1 DIM"
print*, "SHAPE OF ARRAY:", shape(input1d)
end subroutine test_func1d
subroutine test_func2d(input2d)
real, intent(in) :: input2d(:,:)
print*, "DOING 2 DIM"
print*, "SHAPE OF ARRAY:", shape(input2d)
end subroutine test_func2d
subroutine test_func3d(input3d)
real, intent(in) :: input3d(:,:,:)
print*, "DOING 3 DIM"
print*, "SHAPE OF ARRAY:", shape(input3d)
end subroutine test_func3d
end module functions
program test_prog
use functions
implicit none
real :: case1(10), case2(20,10), case3(30, 40, 20)
call test_dim(case1)
call test_dim(case2)
call test_dim(case3)
end program test_prog
And the output produced by this function looks like this:
DOING 1 DIM
SHAPE OF ARRAY: 10
DOING 2 DIM
SHAPE OF ARRAY: 20 10
DOING 3 DIM
SHAPE OF ARRAY: 30 40 20

Fortran strategy to debug compilation errors

I'm having a hard time debugging a compilation error in gfortran. My compiler is:
gfortran -v
Thread model: posix
gcc version 4.9.2 (x86_64-posix-seh-rev4, Built by MinGW-W64 project)
I can't include the real problem because it's too big. Below I'll discuss a model problem of what's happening:
I have one big module, let's call it ops, that I'd like to break down into several modules (e.g. add, subtract, multiply, divide, etc). To do this, I "use" modules "add" and "subtract" in module "ops", make the routines from "add" and "subtract" public, and then call the routines in "add" and "subtract" from the main program, which only uses "ops".
In this simple example (illustrated below in a simple program), using both modules works fine, and there are no errors. But when I do this with my big program, I get an error when trying to use the "subtract" module (I've also included what I mean in the program comments).
Here's the sample of the scenario:
module add_mod
private
public :: add
interface add; module procedure add1; end interface
contains
subroutine add1(a,b,c)
integer,intent(inout) :: a
integer,intent(in) :: b,c
a = b + c
end subroutine
end module
module subtract_mod
private
public :: subtract
interface subtract; module procedure subtract1; end interface
contains
subroutine subtract1(a,b,c)
integer,intent(inout) :: a
integer,intent(in) :: b,c
a = b - c
end subroutine
end module
module ops
use add_mod
! use subtract_mod ! Removing comment causes error...
private
public :: init
public :: add
! public :: subtract ! Removing comment causes error...
contains
subroutine init(a,b,c)
implicit none
integer,intent(inout) :: a,b,c
a = 0; b = 0; c = 0
end subroutine
end module
program test
use ops
implicit none
integer :: a,b,c
b = 1; c = 1
call add(a,b,c)
write(*,*) 'a,b,c = ',a,b,c
! call subtract(a,b,c) ! want to call...
write(*,*) 'a,b,c = ',a,b,c
end program
The error that I'm getting (in terms of the simplified example) is:
\add.o
\subtract.o
\subs.o
\main.o
gfortran: error: main.o: No such file or directory
make: *** [main] Error 1
The error from my big example looks like
C:\\Users\\charl\\Documents\\obj\parametricStudy.o
gfortran: error: C:\\Users\\charl\\Documnts\\obj\parametricStudy.o: No such file or directory
make: *** [C:\\Users\\charl\\Documents\\MOONS] Error 1
Where "parametricStudy" is the main program and "MOONS" is the name of the target/executable.
This really does not look like an error in terms of finding the executable, it looks like the executable is not made because of some other issue, but I don't have enough information to find out why. I've tried including all of the debugging flags I can think of:
fimplicit-none -Wuninitialized -cpp -fopenmp -Wall -Wextra -fbacktrace -fcheck=all -O0 -Og
Sorry for the long introduction, but here's my question: How can I debug this? I'm sorry if this was a poorly conveyed question, but I can't re-produce this error in a simple case, so I'm not sure how else to pose the question. Any help on a solution, debugging advice or improving this question is greatly appreciated!
UPDATE:
After seeing the comment about the compilation error typo, I tried reversing the order of the used modules. That is, now I tried using "subtract" alone, which works fine, but then try using "add" (together) and I get the same error. I'm now beginning to think that this is a compiler bug or something.
UPDATE 2:
I uploaded the code to github. It can be downloaded at
https://github.com/charliekawczynski/MOONS
The makefile is in the directory
\MOONS\makefiles\MOONS
And the output should show up in out_dir. To compile this, the $TARGET_DIR$ and $SRC_DIR$ must be defined. Please note that right now it is defined with the variable $USER$.
After changing the directory, I see a different misspelling (which seems to change when I make small changes in the code, e.g. removing some warnings related to unused variables).
UPDATE 3:
I've been removing more warnings related to un-used routines and variables, and now I see that the error still exists, but (as far as I see) there is no typo. Here is the new output:
gfortran -o
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\MOONS -J"
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\mod" -fimplicit-none -Wuninitialized -cpp -D_DOUBLE_PRECISION_ -D_FFT_RADIX2_ -fopenmp -Wall -Wextra -fbacktrace -fcheck=all -O0 -Og -D_DEBUG_DEL_ -D_DEBUG_INTERP_ -D_DEBUG_APPLYBCS_
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\IO_tools.o
...
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\init_Ufield.o
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\init_Pfield.o
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\energySolver.o
...
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\MOONS.o
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\richardsonExtrapolation.o
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\convergenceRate.o
C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\parametricStudy.o
gfortran: error: C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\obj\init_Pfield.: No such file or directory
make: *** [C:\\Users\\charl\\Documents\\GitHub\\MOONS\\out_dir\\MOONS] Error 1
C:\Users\charl\Documents\GitHub\MOONS\makefiles\MOONS>
I'm going to try a newer compiler and see if this fixes the problem

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