Compiling Fortran netCDF programs on Ubuntu

lnmaurer picture lnmaurer · Dec 18, 2012 · Viewed 7.4k times · Source

Ok, newb question here.

I'm trying to compile simple_xy_wr.f90 -- a netCDF example program -- using gfortran on Ubuntu, and I must be doing something pretty silly; I don't have much experince compiling Fortran.

First, I've got the libnetcdf-dev package installed, which includes files like

/usr/lib/libnetcdf.a
/usr/lib/libnetcdff.a
/usr/include/netcdf.mod

So, I've tried to compile the code with (various command like)

f95 -o xy -I/usr/include/ -L/usr/lib/ -lnetcdff -lnetcdf simple_xy_wr.f90

and I get the following output

/tmp/ccE6g7sr.o: In function `check.1847':
simple_xy_wr.f90:(.text+0x72): undefined reference to `__netcdf_MOD_nf90_strerror'
/tmp/ccE6g7sr.o: In function `MAIN__':
simple_xy_wr.f90:(.text+0x284): undefined reference to `__netcdf_MOD_nf90_create'
simple_xy_wr.f90:(.text+0x2b6): undefined reference to `__netcdf_MOD_nf90_def_dim'
simple_xy_wr.f90:(.text+0x2e8): undefined reference to `__netcdf_MOD_nf90_def_dim'
simple_xy_wr.f90:(.text+0x432): undefined reference to `__netcdf_MOD_nf90_def_var_manydims'
simple_xy_wr.f90:(.text+0x468): undefined reference to `__netcdf_MOD_nf90_enddef'
simple_xy_wr.f90:(.text+0x4aa): undefined reference to `__netcdf_MOD_nf90_put_var_2d_fourbyteint'
simple_xy_wr.f90:(.text+0x4cb): undefined reference to `__netcdf_MOD_nf90_close'
collect2: error: ld returned 1 exit status

I think that I'm including the right libraries. E.g. it seems that __netcdf_MOD_nf90_strerror should be there:

$ nm /usr/lib/libnetcdff.a | grep __netcdf_MOD_nf90_strerror
000000000004a100 T __netcdf_MOD_nf90_strerror

What am I doing wrong?

(FWIW, a few relevant references I've looked at are below.

  1. undefined reference using netcdf library

  2. Compiling problems with gfortran and NETCDF

  3. Compiling and Running Fortran Programs - a basic guide

)

Answer

Hristo 'away' Iliev picture Hristo 'away' Iliev · Dec 19, 2012

Ordering of object files and archives on the linker command line is very important on Unix systems since the default linker behaviour is to search for symbol definitions only in archives that follow the object file or archive, where an unresolved reference was found, referred to single pass linking.

This means that if your code references __netcdf_MOD_nf90_strerror, then the archive that contains the definition of this symbol (libnetcdff.a) must appear after the list of object files from your program. libnetcdff.a itself references symbols from the C library libnetcdf.a, hence it must be linked after libnetcdff.a. So the correct link order is:

/tmp/ccE6g7sr.o libnetcdff.a libnetcdf.a

where /tmp/ccE6g7sr.o is the temporary object file that the assembler produces from the compiled source file. The correct command line to compile your code is then:

f95 -o xy -I/usr/include/ simple_xy_wr.f90 -lnetcdff -lnetcdf

In this case the linker is not called directly, rather the compiler does it. GCC compilers pass all link-related things in the same order to an intermediate utility called collect2 which then calls the actual linker ld.

Note that if shared object versions of the netCDF library archives are also present (i.e. there are libnetcdff.so and libnetcdf.so), then the linker would prefer them to the static archives (unless static linking is enabled with the -static option) and the final link phase would be handled to the run-time link editor (RTLD) (/lib64/ld-linux-x86-64.so.2 on Ubuntu). In this case the same command line as in your question would actually succeed without link errors, despite the fact that both libraries are positioned before the code that references them, as the missing symbol references would be resolved by the RTLD while it is loading the executable file.