Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fortran 2008 submodule #4704

Closed
scivision opened this issue Jan 2, 2019 · 14 comments
Closed

Fortran 2008 submodule #4704

scivision opened this issue Jan 2, 2019 · 14 comments

Comments

@scivision
Copy link
Member

scivision commented Jan 2, 2019

Fortran 2008 added submodule, which is quite useful for good structure and fast builds of Fortran programs. The present lack of submodule support in Meson is a key blocker for Fortran use.

Meson does not appear to understand the submodule statement. A self-contained single .f90 file will of course compile correctly, but almost all use cases for submodule are where the submodule is in a different .f90 file from the module containing the submodule.

Here is a simple example consisting of two files.

file basic.f90

module demo
real, parameter :: pi = 4.*atan(1.)
real :: tau

interface
  module subroutine hello(pi,tau)
    real, intent(in) :: pi
    real, intent(out) :: tau
  end subroutine hello
end interface
contains 
end module demo

program sm
use demo
call hello(pi, tau)
print *,'pi=',pi, 'tau=', tau
end program

file basic_sub.f90

submodule (demo) hi
contains
module procedure hello
  tau = 2*pi
end procedure hello
end submodule hi

file meson.build

executable('basic', ['basic.f90', 'basic_sub.f90'])
@scivision
Copy link
Member Author

scivision commented Jan 2, 2019

log output for the above example. Changing the order of the .f90 files in the executable() statement does not change the error/output (the order of files shouldn't matter anyway)

The Meson build system
Version: 0.49.0
Source dir: ~/code/fortran2018-examples
Build dir: ~/code/fortran2018-examples/bin
Build type: native build
Project name: Fortran2018examples
Project version: 1.0.0
Native Fortran compiler: gfortran (gcc 7.3.0 "GNU Fortran (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0")
Build machine cpu family: x86_64
Build machine cpu: x86_64
Build targets in project: 7
Found ninja-1.8.2 at ~/miniconda3/bin/ninja
[1/3] Compiling Fortran object 'submodule/d8566c5@@basic@exe/basic_sub.f90.o'.
FAILED: submodule/d8566c5@@basic@exe/basic_sub.f90.o 
gfortran -Isubmodule/d8566c5@@basic@exe -Isubmodule -I../submodule -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -g  -Jsubmodule/d8566c5@@basic@exe   -o 'submodule/d8566c5@@basic@exe/basic_sub.f90.o' -c ../submodule/basic_sub.f90
f951: Fatal Error: Module file ‘demo.smod’ has not been generated, either because the module does not contain a MODULE PROCEDURE or there is an error in the module.
compilation terminated.
[2/3] Compiling Fortran object 'submodule/d8566c5@@basic@exe/basic.f90.o'.
ninja: build stopped: subcommand failed.

@scivision
Copy link
Member Author

scivision commented Jan 2, 2019

Here is the verbose output of CMake building this executable correctly:

[  8%] Building Fortran object CMakeFiles/basic.dir/basic.f90.o
/usr/bin/gfortran   -c ~/code/fortran2018-examples/submodule/basic.f90 -o CMakeFiles/basic.dir/basic.f90.o
[ 16%] Building Fortran object CMakeFiles/basic.dir/basic_sub.f90.o
/usr/bin/gfortran    -c ~/code/fortran2018-examples/submodule/basic_sub.f90 -o CMakeFiles/basic.dir/basic_sub.f90.o
[ 25%] Linking Fortran executable basic
/usr/bin/gfortran   CMakeFiles/basic.dir/basic.f90.o CMakeFiles/basic.dir/basic_sub.f90.o  -o basic 
[ 25%] Built target basic

@scivision
Copy link
Member Author

scivision commented Jan 2, 2019

Here is how one can build the executable manually. The compiler commands must be issued in this order--the module must be compiled before the submodules.

  1. gfortran -c basic.90 this creates files: basic.o demo.mod demo.smod.
  2. gfortran -c basic_sub.f90 -o basic_sub.o this creates files: basic_sub.o demo@hi.smod.
  3. gfortran basic.o basic_sub.o -o basic creating executable basic

For simplicity, here is a table of the module and submodule files generated by several popular Fortran compilers:

Compiler module files submodule files
gfortran demo.mod demo.smod demo@hi.smod
flang demo.mod demo-hi.mod
pgf90 demo.mod demo-hi.mod
ifort demo.mod demo@hi.smod
xlf2008 demo.mod demo_hi.smod

@jpakkane
Copy link
Member

jpakkane commented Jan 2, 2019

How do modules and submodules behave with respect to each other? Can there be multiple modules and/or submodules in a single file?

Also your post above the table says the output file name is demod.mod rather than demo.mod. Which one of those is correct or does it depend?

@scivision
Copy link
Member Author

it's demo.mod, I made a copy-paste error.
Fortran module can use an arbitrary number of submodule. The interface are defined in the module, and the submodule point back to the module they're used in. In this way, changing the code inside a submodule only requires rebuilding the submodule, since the interface (variables in/out) remains the same.

Yes there can be multiple modules and submodules in a single file, though more often for clarity they are put in separate files.

This gives an excellent description of Fortran submodule hierarchy

The times when you need to use submodule are when the code is complex, hence one looks at the examples and thinks "why is this needed". In the HPC world, say I have a complex program with io.f90 as the "ancestor" module. The children are io_hdf5.f90 io_netcdf.f90, where there are common procedures in io.f90 (say, gathering MPI variables) and then a user selects HDF5 or NetCDF4 at compile time via Meson or CMake command line options.

I put some example code with meson.build and CMakeLists.txt in https://github.com/scivision/fortran-submodule

@ghost
Copy link

ghost commented Mar 9, 2019

I don't think this issue is resolved yet.
When the module and its submodule have the same name (which is allowed) meson throw an error.
child.f90

submodule (mother) mother

contains

  module elemental real function pi2tau
    pi2tau = 2*pi
  end function pi2tau

end submodule mother

parent.f90

module mother
  real, parameter :: pi = 4.*atan(1.)
  real :: tau

  interface
    module elemental real function pi2tau(pi)
      real, intent(in) :: pi
    end function pi2tau
  end interface

contains

end module mother

main.f90

program hier1
  use mother

  tau = pi2tau(pi)

  print *,'pi=',pi, 'tau=', tau

end program

meson.build

project('submodule single level', 'fortran')
hier2 = executable('main', 'main.f90','child.f90','parent.f90')
meson build
...
...
ERROR: Namespace collision: module mother defined in two files child.f90 and parent.f90.
A full log can be found at /meson/build/meson-logs/meson-log.txt

@QuLogic
Copy link
Member

QuLogic commented Mar 10, 2019

Are you testing master? 0.50 isn't out yet.

@ghost
Copy link

ghost commented Mar 10, 2019

@QuLogic yes, I am testing master.

meson --version
0.49.999

@scivision
Copy link
Member Author

fixed by #5039

@ghost
Copy link

ghost commented Mar 13, 2019

meson(built from scivision) failed to build dependencies between source files in this example.
child.f90

SUBMODULE(parent) child
  IMPLICIT NONE

CONTAINS

  MODULE PURE SUBROUTINE mince( a, b )
    REAL, INTENT(IN)  :: a
    REAL, INTENT(OUT) :: b
    b = -a
  END SUBROUTINE mince
  
END SUBMODULE child

parent.f90

MODULE parent
  IMPLICIT NONE

  INTERFACE

    MODULE PURE SUBROUTINE mince( a, b )
      REAL, INTENT(IN)  :: a
      REAL, INTENT(OUT) :: b
    END SUBROUTINE mince

  END INTERFACE

END MODULE parent

main.f90

PROGRAM main
  USE parent

  IMPLICIT NONE
  REAL :: b
  
  CALL mince(1.,b)
  PRINT*, b

END PROGRAM main

meson.build

project('submod', 'fortran')
test = executable('main', 'main.f90', 'parent.f90', 'child.f90')
meson build
...
cd build
ninja
[2/5] Compiling Fortran object 'main@exe/child.f90.o'.
FAILED: main@exe/child.f90.o
gfortran -Imain@exe -I. -I.. -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -g -Jmain@exe  -o 'main@exe/child.f90.o' -c ../child.f90 
f951: Fatal Error: Module file ‘parent.smod’ has not been generated, either because the module does not contain a MODULE PROCEDURE or there is an error in the module.
compilation terminated.
[3/5] Dep hack
ninja: build stopped: subcommand failed. 

I have looked into build/build.ninja and it looks like meson has not built any dependencies between parent.f90 and child.f90

@scivision
Copy link
Member Author

scivision commented Mar 14, 2019

The syntax of the example is incorrect. There should be a space between submodule (parent) child CMake 3.14.0-rc4 cannot compile this example.

I have updated the Meson Fortran submodule regex to allow for this non-standard but unambiguous syntax.

You might be aware that it is not necessary to specify the interface of a submodule procedure in the module and submodule. It could be simplified to:

child1.f90:

SUBMODULE (parent) child
  IMPLICIT NONE

CONTAINS

  MODULE procedure mince
    b = -a
  END procedure mince
  
END SUBMODULE child

@ghost
Copy link

ghost commented Mar 14, 2019

Non-standard! I always enable standard checking flags (-std=f2018, -stand f18 ...) and no compiler complains about my syntax.
I did also search for that rule (put a space) but I didn't find it (that rule).
For cmake it didn't work because it has a bug with procedure declarations. changing declarations from module pure subroutine to pure module subroutine solves the problem. Not because the missing space. I always use cmake and it never faisl because of the missing space!

@ghost
Copy link

ghost commented Mar 14, 2019

Have you tried to build my example?. Because on my side nothing has changed with your last commits, I still get the same problem with dependencies.

@scivision
Copy link
Member Author

scivision commented Mar 14, 2019

06ad37c Now I made sure that both functions use the same submodule-finding pattern, so it works now and as seen by inspection of the build.ninja file. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants