CMake per-language option flags

CMake can set compiler flags with three broad scope categories. We set global and per-language options near the beginning of the top-level CMakeLists.txt, before any targets are declared, to avoid confusion about scope. COMPILE_DEFINITIONS works in a similar fashion.

Note: where using FetchContent, add_compile_options() can only be overridden for the fetched project by using the “negative” option in the fetched project. While the per-language method can be overridden just by setting it again in the fetched project. For example, the main project may desire -Wall but this may cause megabytes of warnings from a legacy Fetched project. In this case, we suggest using the per-language rather than global method.

Example

This example is for a C and Fortran project, where some flags apply to C and Fortran, and other flags are Fortran-specific.

project(Foo
LANGUAGES C Fortran)

if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)

  # options applying to any project language for this compiler
  add_compile_options(-march=native)

  # Fortran-specific, note LEADING space
  string(APPEND CMAKE_Fortran_FLAGS " -fimplicit-none")

  # options for Debug build type
  string(APPEND CMAKE_Fortran_FLAGS_DEBUG " -Werror=array-bounds")

  if(CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER_EQUAL 8)
    string(APPEND CMAKE_Fortran_FLAGS " -std=f2018")
  endif()

endif()


add_library(old OBJECT legacy.f old.f)
# these options apply only to target "old"
target_compile_options(old PRIVATE -w -fno-implicit-none)

add_executable(main main.f90)
target_link_libraries(main old)