What is an undefined reference/unresolved external symbol error and how do I fix it in Fortran?

A link-time error like these messages can be for many of the same reasons as for more general uses of the linker, rather than just having compiled a Fortran program. Some of these are covered in the linked question about C++ linking and in another answer here: failing to specify the library, or providing them in the wrong order.

However, there are common mistakes in writing a Fortran program that can lead to link errors.

Unsupported intrinsics

If a subroutine reference is intended to refer to an intrinsic subroutine then this can lead to a link-time error if that subroutine intrinsic isn't offered by the compiler: it is taken to be an external subroutine.

  implicit none
  call unsupported_intrinsic
end

With unsupported_intrinsic not provided by the compiler we may see a linking error message like

undefined reference to `unsupported_intrinsic_'

If we are using a non-standard, or not commonly implemented, intrinsic we can help our compiler report this in a couple of ways:

  implicit none
  intrinsic :: my_intrinsic
  call my_intrinsic
end program

If my_intrinsic isn't a supported intrinsic, then the compiler will complain with a helpful message:

Error: ‘my_intrinsic’ declared INTRINSIC at (1) does not exist

We don't have this problem with intrinsic functions because we are using implicit none:

  implicit none
  print *, my_intrinsic()
end
Error: Function ‘my_intrinsic’ at (1) has no IMPLICIT type

With some compilers we can use the Fortran 2018 implicit statement to do the same for subroutines

  implicit none (external)
  call my_intrinsic
end
Error: Procedure ‘my_intrinsic’ called at (1) is not explicitly declared

Note that it may be necessary to specify a compiler option when compiling to request the compiler support non-standard intrinsics (such as gfortran's -fdec-math). Equally, if you are requesting conformance to a particular language revision but using an intrinsic introduced in a later revision it may be necessary to change the conformance request. For example, compiling

  intrinsic move_alloc
end

with gfortran and -std=f95:


   intrinsic move_alloc
                      1
Error: The intrinsic ‘move_alloc’ declared INTRINSIC at (1) is not available in the current standard settings but new in Fortran 2003. Use an appropriate ‘-std=*’ option or enable ‘-fall-intrinsics’ in order to use it.

External procedure instead of module procedure

Just as we can try to use a module procedure in a program, but forget to give the object defining it to the linker, we can accidentally tell the compiler to use an external procedure (with a different link symbol name) instead of the module procedure:

module mod
  implicit none
contains
  integer function sub()
    sub = 1
  end function
end module

  use mod, only :
  implicit none

  integer :: sub

  print *, sub()

end

Or we could forget to use the module at all. Equally, we often see this when mistakenly referring to external procedures instead of sibling module procedures.

Using implicit none (external) can help us when we forget to use a module but this won't capture the case here where we explicitly declare the function to be an external one. We have to be careful, but if we see a link error like

undefined reference to `sub_'

then we should think we've referred to an external procedure sub instead of a module procedure: there's the absence of any name mangling for "module namespaces". That's a strong hint where we should be looking.

Mis-specified binding label

If we are interoperating with C then we can specify the link names of symbols incorrectly quite easily. It's so easy when not using the standard interoperability facility that I won't bother pointing this out. If you see link errors relating to what should be C functions, check carefully.

If using the standard facility there are still ways to trip up. Case sensitivity is one way: link symbol names are case sensitive, but your Fortran compiler has to be told the case if it's not all lower:

   interface
     function F() bind(c)
       use, intrinsic :: iso_c_binding, only : c_int
       integer(c_int) :: f
     end function f
  end interface

  print *, F()
end

tells the Fortran compiler to ask the linker about a symbol f, even though we've called it F here. If the symbol really is called F, we need to say that explicitly:

   interface
     function F() bind(c, name='F')
       use, intrinsic :: iso_c_binding, only : c_int
       integer(c_int) :: f
     end function f
  end interface

  print *, F()
end

If you see link errors which differ by case, check your binding labels.

The same holds for data objects with binding labels, and also make sure that any data object with linkage association has matching name in any C definition and link object.

Equally, forgetting to specify C interoperability with bind(c) means the linker may look for a mangled name with a trailing underscore or two (depending on compiler and its options). If you're trying to link against a C function cfunc but the linker complains about cfunc_, check you've said bind(c).

Not providing a main program

A compiler will often assume, unless told otherwise, that it's compiling a main program in order to generate (with the linker) an executable. If we aren't compiling a main program that's not what we want. That is, if we're compiling a module or external subprogram, for later use:

module mod
  implicit none
contains
  integer function f()
    f = 1
  end function f
end module

subroutine s()
end subroutine s

we may get a message like

undefined reference to `main'

This means that we need to tell the compiler that we aren't providing a Fortran main program. This will often be with the -c flag, but there will be a different option if trying to build a library object. The compiler documentation will give the appropriate options in this case.


There are many possible ways you can see an error like this. You may see it when trying to build your program (link error) or when running it (load error). Unfortunately, there's rarely a simple way to see which cause of your error you have.

This answer provides a summary of and links to the other answers to help you navigate. You may need to read all answers to solve your problem.

The most common cause of getting a link error like this is that you haven't correctly specified external dependencies or do not put all parts of your code together correctly.

When trying to run your program you may have a missing or incompatible runtime library.

If building fails and you have specified external dependencies, you may have a programming error which means that the compiler is looking for the wrong thing.


Not linking the library (properly)

The most common reason for the undefined reference/unresolved external symbol error is the failure to link the library that provides the symbol (most often a function or subroutine).

For example, when a subroutine from the BLAS library, like DGEMM is used, the library that provides this subroutine must be used in the linking step.

In the most simple use cases, the linking is combined with compilation:

gfortran my_source.f90 -lblas

The -lblas tells the linker (here invoked by the compiler) to link the libblas library. It can be a dynamic library (.so, .dll) or a static library (.a, .lib).

Note that the name of the library can be different as there are multiple implementations of BLAS (MKL, OpenBLAS, GotoBLAS,...). But it will always be shortened from lib... to l... as in liopenblas.so and -lopenblas.


If the library is in a location where the linker does not see it, you can use the -L flag to explicitly add the directory for the linker to consider, e.g.:

gfortran -L/usr/local/lib -lopenblas

You can also try to add the path into some environment variable the linker searches, such as LIBRARY_PATH, e.g.:

export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/lib

When linking and compilation are separated, the library is linked in the linking step:

gfortran -c my_source.f90 -o my_source.o
gfortran my_source.o -lblas

Not providing the module object file when linking

We have a module in a separate file module.f90 and the main program program.f90.

If we do

gfortran -c module.f90
gfortran program.f90 -o program

we receive an undefined reference error for the procedures contained in the module.

If we want to keep separate compilation steps, we need to link the compiled module object file

gfortran -c module.f90
gfortran module.o program.f90 -o program

or, when separating the linking step completely

gfortran -c module.f90
gfortran -c program.f90
gfortran module.o program.o -o program