Build fails if gcc version != gfortran version

I am attempting to build a mixed Fortran/C project on OpenSUSE Leap 14.5 with gcc
gcc (SUSE Linux) 7.5.0
and
GNU Fortran (SUSE Linux) 11.3.0

This is a supported installation from the OpenSUSE main package repo, which allows “update-alternatives” to select between the available versions of GNU Fortran.

When building the main executable, the link fails with a symbol error

undefined reference to `_gfortran_os_error_at’

because the cmake link line includes the wrong version of libgfortran - version 7 not version 11 - both are installed.

/usr/lib64/gcc/x86_64-suse-linux/7/libgfortran.a
/usr/lib64/gcc/x86_64-suse-linux/7/libgfortran.so
/usr/lib64/gcc/x86_64-suse-linux/7/libgfortran.spec

/usr/lib64/gcc/x86_64-suse-linux/11/libgfortran.a
/usr/lib64/gcc/x86_64-suse-linux/11/libgfortran.so
/usr/lib64/gcc/x86_64-suse-linux/11/libgfortran.spec

/usr/bin/cmake -E cmake_link_script CMakeFiles/castep.serial.dir/link.txt --verbose=1
/usr/bin/gfortran -static-libgfortran -fconvert=big-endian -fno-realloc-lhs -Wno-argument-mismatch -fallow-argument-mismatch CMakeFiles/castep.serial.dir/main.f90.o -o …/bin/castep.serial -L/usr/lib
64/gcc/x86_64-suse-linux/7 -Wl,-rpath,/usr/local/lib64 …/lib/libfunctional.a …/lib/libfundamental.a …/lib/libdispersion.a …/lib/libotfg.a …/lib/libutility.a /usr/local/lib64/libflexiblas.so -lpth
read -lm -ldl /usr/lib64/libfftw3.so …/dl_mg/lib/libdlmg.a …/lib/libfundamental.a …/lib/libotfg.a …/lib/libs-dftd3.a …/lib/libdftd4.a …/lib/libmulticharge.a …/lib/libmctc-lib.a -lpthread -lm -ld
l /usr/local/lib64/libflexiblas.so /usr/lib64/gcc/x86_64-suse-linux/11/libgomp.so /usr/lib64/libpthread.so …/lib/libutility.a …/lib/libsymspg.a

The problem is the erroneous library search path -L/usr/lib64/gcc/x86_64-suse-linux/7 . As the linker is invoked via the “gfortran” command this is unnecessary, as gfortran knows perfectly well where it’s runtime library lives, and removing it and linking by hand works perfectly.

Can someone please help me to identify why CMake is including it? This directory does not appear anywhere in CMakeCache.txt. I am a newbie to CMake, so please be specific with any diagnostics required.

Thanks for any help

Keith Refson

I’d also search under the root CMakeFiles/. CMake stores its detected compiler information there.

The best way might be to write a toolchain file to skip some of CMake’s builtin information extraction that seems to be getting confused here.

OK, according from the log this originates from the C compiler characteristics determination, it is in the C compiler ABI determination:

3.20.4/CMakeCCompiler.cmake

contains

set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES “/usr/lib64/gcc/x86_64-suse-linux/7;/usr/lib64;/lib64;/usr/x86_64-suse-linux/lib”)

Can I just set this manually for the project as I know that the link stage always works without it? (Indeed setting to the empty string works on this machine) But is there a general and portable solution which will not break the build on other setups?

Hmm. Why is the Fortran compiler explicitly adding it then? That sounds weird to me…

Could it be the BLAS or LAPACK libraries adding it?

grep -d skip CMAKE_C_IMPLICIT_LINK_DIRECTORIES /usr/share/cmake//
/usr/share/cmake/Modules/CMakeCCompiler.cmake.in:set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES “@CMAKE_C_IMPLICIT_LINK_DIRECTORIES@”)
/usr/share/cmake/Modules/FindBLAS.cmake: list(APPEND _extaddlibdir “${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}”)
/usr/share/cmake/Modules/FindLAPACK.cmake: list(APPEND _extaddlibdir “${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}”)

If they live there, yes, CMake might add them? Though CMake vastly prefers full paths for libraries when possible.

I do call FindLAPACK, so that’s what must be dragging it in. It’s not obvious to me why anyone would think it necessary to include the C implicit directory when linking against LAPACK when the original and current LAPACK would have to be compiles from Fortran. (Yes, there is such a thing as clapack but that is not what is being found or used here).

I think I must consider this a bug in FindLAPACK.

@brad.king Any insight?

For reference, CMake detects CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES for each enabled language, and when the compiler for <LANG> is used to drive linking, those directories are filtered out to avoid generating explicit -L flags for them.

Normally we don’t expect find modules to search in CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES. If it is expected that a library comes with the toolchain, then find modules can use IMPORTED_LIBNAME instead of finding the actual file on disk.

It looks like explicit searching of implicit link directories was added by CMake commit d5f691be0b to help find one of the dependencies of Intel MKL. I’d welcome an update to the BLAS/LAPACK modules to avoid that.