7 - Build Tools
CMake
We have already briefly discussed the use of CMake
in the previous section 3 - Compilation Basics. More specifically we have covered:
- Building the project
- Compiling the project
- Building multiple configurations (Debug, Release)
- Passing options to the compiler, e.g. to disable a warning, or a preprocessor macro
In this section we will cover some additional aspects of CMake
- Peeking into the
CMakeLists.txt
andCMake
syntax - Enabling/disabling settings
- Find external libraries
- High level UI using
ccmake
andcmake-gui
Anatomy of CMakeLists.txt
It is now time to peek into the CMakeLists.txt
file and try and understand the syntax.
CMkake
relies on a relatively simple syntax with extensive online documentation, which
you can view here. It is based around the concept
of creating targets and then configuring the properties of the targets.
For example, the diffusion
binary is defined as an executable target.
cmake_minimum_required(VERSION 3.13)
project(diffusion)
enable_language(Fortran)
set(BIN_NAME diffusion) # define a variable with name BIN_NAME
set(SOURCES # define a list with all the source file names
src/Constants.F90
src/Materials.F90
src/Problem.F90
src/Output.F90
src/Matrix_Base.F90
src/CRS.F90
src/Solver.F90
src/MatGen.F90)
# create a target with name BIN_NAME from files SOURCES + main.F90
add_executable(${BIN_NAME} ${SOURCES} app/main.F90)
The above snippet is enough to instruct cmake
to compile the sources into
an executable.
Additional properties to a target e.g. it's output name, output location, etc. can be configured by using the
set_target_properties
command.
# Set additional properties for executable target
set_target_properties(${BIN_NAME} # this is the target's name
PROPERTIES
OUTPUT_NAME ${PROJECT_NAME} # use the project name for the binary
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin # put binary in build/bin/
Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/src) # put .mod in build/src/
Properties can also be set for the installation process.
# by default installs to CMAKE_INSTALL_PREFIX
# you can override the behaviour by setting the variable to something similar to
# set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/install CACHE STRING "")
# which would create an install folder in the root directory of the project.
set(INSTALL_BIN_DIR "bin")
# install the executable: specify the install location
install(TARGETS ${BIN_NAME}
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
ARCHIVE DESTINATION ${INSTALL_BIN_DIR})
Adding and toggling settings
As a project grows in complexity, often times you might want to define some
custom options, that turn on/off certain features, adds a compiler flag, ignores
certain source files etc. This can be done in cmake
by using the option
keyword.
Say that you have certain source files that you want to be able to compile, but you don't want to do so by default, in this case the solutions to the exemplar exercises. You can create the following option
# defines a variable called BUILD_SOLUTIONS
option(BUILD_SOLUTIONS "Build the exemplar's solutions" OFF)
...
if(BUILD_SOLUTIONS)
# compile the solutions only if BUILD_SOLUTIONS is ON
...
endif()
To toggle the settings of cmake
without having to modify the CMakeLists.txt
file,
similarly to building multiple configurations (Debug and Release)
by passing a command line option to cmake
, in a terminal on would do
cmake .. -DBUILD_SOLUTIONS=ON # from within the build/
Finding external libraries
Many times you will want to incorporate an external library into your project
to add certain functionality. For example, you might want to
include a linear algebra library to make mathematical operations on matrices
easier. CMake
offers a way to find these libraries via the
pkg_search_module
find_package(PkgConfig) # enable the pkg_search_module
# look for library called libname and prefix all variables with MY_VAR_PREFIX
pkg_search_module(MY_VAR_PREFIX REQUIRED IMPORTED_TARGET libname)
High level GUI using ccmake
and cmake-gui
ccmake
is a command line User Interface (UI) meant to be used
to interactively toggle project configuration settings. You can launch ccmake
after you have configured your project via
cmake .. # from within build/
ccmake .
From ccmake
you can then toggle settings and even expose all the predefined
cmake
variables (by pressing t),
reconfigure the project (by pressing c),
read the help menus (by pressing h) and much more.
Similarly to the command line interface there is also a graphical interface
cmake-gui
which can perform the identical tasks. You can launch cmake-gui
after you have
configured your project via
cmake .. # from within build/
cmake-gui ..
For more information on cmake
make sure to read the online documentation. You can also try and go through the CMakeLists.txt
file provided
in this project. It is well documented and uses various different features of cmake
.
Feel free to also use it as a template for your own projects.
FPM - Fortran Package Manager
FPM stands for the Fortran Package Manager, and it is meant to be an easy-to-use
build and compilation tool, serving as an alternative to more complicated
build tools like CMake
or Make
.
Automatically, fpm
assumes by default that the Fortran source files are in:
src/
for modules and procedure sourceapp/
main program(s) for applicationstest/
main program(s) and support files for project testsexample/
main program(s) for example programs
Any additional settings can be specified in the fpm.toml
configuration file.
name = "diffusion"
version = "1.0.0"
[build]
auto-tests = false
auto-examples = false
auto-executables = false
external-modules = ["petscsys", "petscksp", "petscvec", "petscmat"]
[library]
source-dir = "src"
[[executable]]
name = "diffusion"
source-dir = "app"
main = "main.F90"
link = ["petsc"]
To demonstrate how simple it is to build using fpm
, we will build this project
alongside cmake
by running:
fpm build
To run the program you can instruct fpm
to do it for you by running:
fpm run
Or install it to a directory by running:
fpm install --prefix=./install
Additional flags to the Fortran compile can be passed with the --flag
option
fpm run --flag "-DDEBUG"
For more information on how to use FPM, see the FPM documentation and the FPM manifest