This project mixes C++, which is the language of the main program, Fortran, because this is the language the libraries are written in, and C, which is needed to wrap the Fortran subroutines. In the root CMakeLists.txt file, we need to do the following:
- Declare the project as mixed-language and set the C++ standard:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-02 LANGUAGES CXX C Fortran)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
- We use the GNUInstallDirs module to direct CMake to save static and shared libraries and the executable into standard directories. We also instruct CMake to place Fortran compiled module files under modules:
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
set(CMAKE_Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}/modules)
- We then move on to the next leaf subdirectory:
add_subdirectory(src)
The leaf file src/CMakeLists.txt adds yet another subdirectory, math, which contains the linear algebra wrappers. In src/math/CMakeLists.txt, we need to do the following:
- We invoke find_package to get the location of the BLAS and LAPACK libraries:
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
- We include the FortranCInterface.cmake module and verify that the Fortran, C and, C++ compilers are compatible:
include(FortranCInterface)
FortranCInterface_VERIFY(CXX)
- We also need to generate preprocessor macros to take care of the name mangling of the BLAS and LAPACK subroutines. Once again, FortranCInterface comes to the rescue by generating a header file called fc_mangle.h in the current build directory:
FortranCInterface_HEADER(
fc_mangle.h
MACRO_NAMESPACE "FC_"
SYMBOLS DSCAL DGESV
)
- Next, we add a library with our sources for the BLAS and LAPACK wrappers. We also specify the directories where the header files and libraries are to be found. Notice the PUBLIC attribute, which will allow other targets depending on math to properly get their dependencies:
add_library(math "")
target_sources(math
PRIVATE
CxxBLAS.cpp
CxxLAPACK.cpp
)
target_include_directories(math
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries(math
PUBLIC
${LAPACK_LIBRARIES}
)
Stepping back to src/CMakeLists.txt, we finally add an executable target and link it to our math library of BLAS/LAPACK wrappers:
add_executable(linear-algebra "")
target_sources(linear-algebra
PRIVATE
linear-algebra.cpp
)
target_link_libraries(linear-algebra
PRIVATE
math
)