CMakeForFortranExample

From KitwarePublic
Jump to: navigation, search

CMake is perfectly capable of handling Fortran code; however, examples are less abundant than for C or C++. In the example below we write a very small CMakeLists.txt to wrap a simple Fortran project.

The motivation for this was to easily compile Fortran code that came with the NORMA package. The distribution NORMA-1.0.tgz was downloaded and unpacked. following CMakeLists.txt was placed into the ./software directory where the NORMA sources are stored.

To build one would typically create a build directory at the same level as software:

mkdir build && cd build
ccmake ../software
make
make install

and then configure, build and install.

The project is very simple:

  • There are only a few fortran source code files in the software directory.
  • There are no library dependencies.
  • Executables are typically installed in a bin directory in the package itself (i.e. NORMA/bin) although the user is free to to change the installation prefix.
  • Two shell scripts are also installed alongside.

The CMakeLists.txt is commented and additional comments can be found after it.

Example CMakeLists.txt

# CMake project file for NORMA

cmake_minimum_required (VERSION 2.6)
project (NORMA)
enable_language (Fortran)

# make sure that the default is a RELEASE
if (NOT CMAKE_BUILD_TYPE)
  set (CMAKE_BUILD_TYPE RELEASE CACHE STRING
      "Choose the type of build, options are: None Debug Release."
      FORCE)
endif (NOT CMAKE_BUILD_TYPE)

# default installation
get_filename_component (default_prefix ".." ABSOLUTE)
set (CMAKE_INSTALL_PREFIX ${default_prefix} CACHE STRING
      "Choose the installation directory; by default it installs in the NORMA directory."
      FORCE)

# FFLAGS depend on the compiler
get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME)

if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
  # gfortran
  set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3")
  set (CMAKE_Fortran_FLAGS_DEBUG   "-fno-f2c -O0 -g")
elseif (Fortran_COMPILER_NAME MATCHES "ifort.*")
  # ifort (untested)
  set (CMAKE_Fortran_FLAGS_RELEASE "-f77rtl -O3")
  set (CMAKE_Fortran_FLAGS_DEBUG   "-f77rtl -O0 -g")
elseif (Fortran_COMPILER_NAME MATCHES "g77")
  # g77
  set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3 -m32")
  set (CMAKE_Fortran_FLAGS_DEBUG   "-fno-f2c -O0 -g -m32")
else (Fortran_COMPILER_NAME MATCHES "gfortran.*")
  message ("CMAKE_Fortran_COMPILER full path: " ${CMAKE_Fortran_COMPILER})
  message ("Fortran compiler: " ${Fortran_COMPILER_NAME})
  message ("No optimized Fortran compiler flags are known, we just try -O2...")
  set (CMAKE_Fortran_FLAGS_RELEASE "-O2")
  set (CMAKE_Fortran_FLAGS_DEBUG   "-O0 -g")
endif (Fortran_COMPILER_NAME MATCHES "gfortran.*")


# build executables
set (NMPROGRAMS "diagstd" "diagrtb" "proj_modes_bin" "pdbmat")
set (EXECUTABLES "NORMA.exe" ${NMPROGRAMS})
set (SCRIPTS "gen_pert.sh" "pert_multi_mode.sh")

add_executable ("NORMA.exe" "NORMA.f")
foreach (p ${NMPROGRAMS})
  add_executable (${p} "${p}.f")
endforeach (p)

# install executables and scripts
install (TARGETS ${EXECUTABLES} 
         RUNTIME DESTINATION "bin")
install (PROGRAMS ${SCRIPTS}
         DESTINATION "bin") 

Comments on CMakeLists.txt

  • Use cmake v2.6 or better for optimum Fortran support.
  • Make sure that we build a RELEASE by default (and let the user know in the GUI); uses example code from the docs.
  • Set the default prefix to the non-standard installation scheme in which one installs all component into the package directory. This directory is assumed to be one above relative the build directory. The full canonical path is obtained with the get_filename_component function.
  • As it is typical for scientific Fortran code, the compiler optimizations are fairly specific. Here we are trying to detect a few common ones (gfortran, Intel ifort, g77) and set the compile options accordingly. If all else fails we use -O2 and hope for the best (but let the user know).
  • The NORMA.exe binary is built from the source NORMA.f so we have to say this explicitly with the
    add_executable ("NORMA.exe" "NORMA.f")
    line but the other binaries are simply built from corresponding .f files and we write this as a simple foreach-loop.
  • Executables are installed in the bin dir (which is relative to the prefix).
  • Finally, scripts are copied to the bin directory, too.