Search code examples
fortran

Calling a subroutine from another file in Fortran


I am trying to write a wrapper code for a simple "Hello World" program on Fortran, but I keep getting linking conflicts whenever I call a subroutine from another file.

These are the codes I used:

file name: helloworld.f90

module hellomod
public
contains
    subroutine printing
        print *, 'Hello World!'
        return
    end subroutine
end module hellomod

program main
    use hellomod, only: printing
    call printing
end program main

file name: hellowrap.f90

subroutine wrapping
    use hellomod, only: printing
    call printing
end subroutine wrapping

program hellowrap
    implicit none
    call wrapping
end program hellowrap

The error I got:

/usr/bin/ld: /tmp/cc5p8TIE.o: in function `wrapping_':
hellowrap.f90:(.text+0x5): undefined reference to `__hellomod_MOD_printing'
collect2: error: ld returned 1 exit status

I am a newbie in Fortran programming, so it would be great if I could know what exactly I might be doing wrong.

P.S: I did go through the other questions which were similar to mine. I tried those fixes, but they simply didn't work. One of the questions I explored was about linking a module, but when I tried to compile them together, I got an error as there are essentially two 'main' functions.

I want to compile these files separately, so this does not work. I do not exactly know if this is exclusively a linking issue.


Solution

  • Compiled languages generate executables in two steps, 1.Compilation and 2.linking

    Compilation step just compiles each block of the program to object files as long as they are syntactically correct. The final executable has to be linked to libraries like standard and external libraries, In this step, the program is put together as a whole. When you directly compile a program, both steps are done one after the other.

    What you are getting is a linker error. The linker is not able to find the object file (compiled machine code but not linked) containing the function wrapping. (Some fortran compilers add an underscore in the binary name for historical reasons to hint it is a fortran function. This can be ignored if you stay within fortran)

    You can approach this in two ways. You can compile both .f90 files separately and then link the resulting binaries or compile them in a single step so both steps are handled as once. The second way is just doing gfortran helloworld.f90 hellowrap.f90 -o programname

    Now the regarding the problem of two main functions, all programs should have an "entrypoint" which is the start of execution. This is the function automatically called on start of a program. There can only be one of this. For binaries on linux this is _start but usually compilers implement a wrapper function like main in C/C++ and the program in fortran. The program can have only one entry point. In terms of binary, the program block is just another function like main and it should be unique.

    TLDR: You can include all the files in the gfortran command but you can have only one program block in all the files you provide. You should remove program wrapping or program main as there can be only one entrypoint for the program.