Hmm… I don’t think you’re doing anything wrong here. It seems to me that it’s a gfortran bug in relation to enforcing encapsulation at the object level (maybe others in the forum might correct me and point you in a different direction).
These are the symbols from the a_mod.f90
file you provided:
$ gfortran -c a_mod.f90 && nm ./a_mod.o
0000000000000000 t __a_mod_MOD_do_something
U _gfortran_st_write
U _gfortran_st_write_done
U _gfortran_transfer_character_write
Notice the lowercase “t” before the symbol __a_mod_MOD_do_something
, which means the symbol is in the text section but local to the object file.
If I make do_something
(explicitly) public in the a_mod.f90
, then I get:
$ gfortran -c a_mod.f90 && nm ./a_mod.o
0000000000000000 T __a_mod_MOD_do_something
U _gfortran_st_write
U _gfortran_st_write_done
U _gfortran_transfer_character_write
Notice the uppercase “T” before the symbol, which means the symbol is in the text section and it’s global.
So, gfortran seems to try to enforce encapsulation at the object level, and that makes the linking step fail when submodules are involved —but it’s probably fine for other scenarios.
Using ifx, the split code you provided compiles and runs without issue:
$ ifx -c ./a_mod.f90 ./b_submod.f90 ./test.f90
$ ifx -o test ./test.o ./b_submod.o ./a_mod.o
$ ./test
doing something
So ifx is not trying to enforce encapsulation at the object level:
$ ifx -c a_mod.f90 && nm ./a_mod.o
0000000000000000 T a_mod._
0000000000000010 T a_mod_mp_do_something_
U for_write_seq_lis
0000000000000000 r strlit