Using find_package, we have identified the correct libraries to link to. As in the previous recipe, we need to make sure that our program can correctly call the functions they define. As in Chapter 3, Detecting External Libraries and Programs, Recipe 4, Detecting the BLAS and LAPACK math libraries, we face the problem of compiler-dependent name mangling of symbols. We use the FortranCInterface CMake module to check the compatibility of the selected C and C++ compilers with the Fortran compiler. We also use the FortranCInterface_HEADER function to generate a header file with macros to take care of name mangling of Fortran subroutines. This was achieved with the following code:
FortranCInterface_HEADER(
fc_mangle.h
MACRO_NAMESPACE "FC_"
SYMBOLS DSCAL DGESV
)
This command will generate the fc_mangle.h header file with name-mangling macros, as inferred from the Fortran compiler, and save it into the current binary directory, CMAKE_CURRENT_BINARY_DIR. We were careful to set CMAKE_CURRENT_BINARY_DIR as an include path for our math target. Consider the following generated fc_mangle.h:
#ifndef FC_HEADER_INCLUDED
#define FC_HEADER_INCLUDED
/* Mangling for Fortran global symbols without underscores. */
#define FC_GLOBAL(name,NAME) name##_
/* Mangling for Fortran global symbols with underscores. */
#define FC_GLOBAL_(name,NAME) name##_
/* Mangling for Fortran module symbols without underscores. */
#define FC_MODULE(mod_name,name, mod_NAME,NAME) __##mod_name##_MOD_##name
/* Mangling for Fortran module symbols with underscores. */
#define FC_MODULE_(mod_name,name, mod_NAME,NAME) __##mod_name##_MOD_##name
/* Mangle some symbols automatically. */
#define DSCAL FC_GLOBAL(dscal, DSCAL)
#define DGESV FC_GLOBAL(dgesv, DGESV)
#endif
The compiler in this example uses underscores for mangling. Since Fortran is case-insensitive, the subroutine might appear in either lowercase or uppercase, justifying the need to pass both cases to the macro. Notice that CMake will also generate macros for mangling symbols hidden behind Fortran modules.
Since we have carefully organized the sources into a library target and an executable target, we should comment on the use of the PUBLIC, INTERFACE, and PRIVATE visibility attributes for the targets. These are essential for a clean CMake project structure. As with sources, include directories, compile definitions, and options, the meaning of these attributes remains the same when used in conjunction with target_link_libraries:
- With the PRIVATE attribute, libraries will only be linked to the current target, but not to any other targets consuming it.
- With the INTERFACE attribute, libraries will only be linked to targets consuming the current target as a dependency.
- With the PUBLIC attribute, libraries will be linked to the current target and to any other target consuming it as a dependency.