CMake: How to Inspect and Configure the Compiler

A tutorial on using CMake to configure compilers and their flags for development projects

Introduction

Source Files

$ git clone https://github.com/danebulat/cmake-compiler-flags.git
> root
---> CMakeLists.txt # Initial CMake configuration
---> interpolate.cpp # Source file for 'interp' library
---> interpolate.h # Header file for 'interp' library
---> main.cpp # Source file for the executable
---> steps/
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(BUILD_SHARED_LIBS ON)
add_library(interp interpolate.h interpolate.cpp)
add_executable(main main.cpp)
target_link_libraries(main interp)

1. Inspecting the Default Compiler

$ cd cmake-compiler-flags
$ mkdir build && cd build
$ cmake ..
-| The CXX compiler identification is GNU 10.2.0
... Check for working CXX compiler: /usr/bin/c++ - skipped
# A path is returned if the compiler is installed on your system
$ which c++ g++ gcc
# Check compiler name and version
$ c++ --version
$ gcc --version
$ g++ --version
# Review the help listing
$ g++ --help | less
# Compare file size
$ ls -l $(which c++ g++ gcc)
# Open cache in build directory
$ ccmake .
Inspecting variables in the project’s cache.
# Build project
$ cmake --build .
# Run program
$ ./main
-| Begin...
Result 0: 1 ...

2. Selecting a Compiler and Inspecting its Properties

$ cmake --system-information information.txt
Inspecting system information generated by CMake.

Selecting Another Compiler

# Create CXX environment variable
$ export CXX=clang++
$ echo $CXX
-| clang++
# Overwrite information.txt with updated system information
$ cmake --system-information information.txt
# Enter build directory and remove all files (clean)
$ cd build && rm -fr *
# Read configuration and set g++ compiler
$ cmake -DCMAKE_CXX_COMPILER=clang++ ..
-| The CXX compiler identification is Clang 11.0.0
... Check for working CXX compiler: /usr/bin/clang++ - skipped
$ cmake --build .
$ ./main
-| Begin...
Result 0: 1 ...

Outputting Compiler Information at Configuration Time

   set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)>> if(CMAKE_CXX_COMPILER_LOADED)
message(STATUS "Compiler path: ${CMAKE_CXX_COMPILER}")
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "Compiler version:
${CMAKE_CXX_COMPILER_VERSION}")
message(STATUS "Compiler is part of GCC:
${CMAKE_COMPILER_IS_GNUCXX}")
endif()
$ cmake ..
-| Compiler path: /usr/bin/clang++
Compiler ID: Clang
Compiler version: 11.0.0
Compiler is part of GCC: ...

Outputting Compiler Information at Runtime

   set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

>> option(OUTPUT_COMPILER_INFO
"Output compiler information when launching the main
executable." ON)
   option(OUTPUT_COMPILER_INFO "..." ON)>> if(CMAKE_COMPILER_IS_GNUCXX MATCHES 1)
set(CXX_COMPILER_IS_GNU 1)
else()
set(CXX_COMPILER_IS_GNU 0)
endif()
configure_file(<input> <output>)
#pragma once
#define COMPILER_LOADED @CMAKE_CXX_COMPILER_LOADED@
#define COMPILER_IS_GNU @CXX_COMPILER_IS_GNU@
#define COMPILER_NAME "@CMAKE_CXX_COMPILER@"
#define COMPILER_ID "@CMAKE_CXX_COMPILER_ID@"
#define COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@"
#cmakedefine OUTPUT_COMPILER_INFO
   target_link_libraries(main interp)

>> # generate configuration file
configure_file(config.h.in config.h @ONLY)
# include binary directory to find config.h
target_include_directories(main PRIVATE ${PROJECT_BINARY_DIR})
Updated program that outputs compiler information.
$ cd build && rm -fr *
$ cmake -DCMAKE_CXX_COMPILER=g++ ..
$ cmake --build .
$ ./main
-| Compiler name: /usr/bin/g++
Compiler ID: GNU
Compiler version: 10.2.0
GCC compiler: 1

3. Inspecting the Default Build Types

Compiler flags used by CMakes build types.

Selecting a Build Type

   set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)>> if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
$ cmake -D CMAKE_BUILD_TYPE=Debug ..
>> #ifdef NDEBUG
std::cout << "NDEBUG Defined (Release)"
<< std::endl << std::endl;
#else
std::cout << "NDEBUG Not Defined (Debug)"
<< std::endl << std::endl;
#endif
std::cout << "Begin..." << std::endl;
# Clean generated files
$ cmake --build . --target clean
# Configure a debug build
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ ..
$ cmake --build .
# Run exectuable
$ ./main
-| Compiler name: /usr/bin/clang++
...
NDEBUG Defined (Release)

4. Conditionally Adding Compiler Flags

     message(STATUS "Compiler is part of GCC: ${ ... }")
endif()
>> set(CXX_FLAGS)
set(CXX_FLAGS_DEBUG)
set(CXX_FLAGS_RELEASE)
   set(CXX_FLAGS_RELEASE)>> list(APPEND CXX_FLAGS "-fPIC" "-Wall")
   list(APPEND CXX_FLAGS "-fPIC" "-Wall")

>> if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
list(APPEND CXX_FLAGS "-fno-rtti" "-fno-exceptions")
list(APPEND CXX_FLAGS_DEBUG "-Wsuggest-final-types"
"-Wsuggest-final-methods" "-Wsuggest-override")
list(APPEND CXX_FLAGS_RELEASE "-O3" "-Wno-unused")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES Clang)
list(APPEND CXX_FLAGS "-fno-rtti" "-fno-exceptions"
"-Qunused-arguments" "-fcolor-diagnostics")
list(APPEND CXX_FLAGS_DEBUG "-Wdocumentation")
list(APPEND CXX_FLAGS_RELEASE "-O3" "-Wno-unused")
endif()
>> target_compile_options(interp PRIVATE ${CXX_FLAGS})   add_executable(main main.cpp)
>> target_compile_options(main PRIVATE ${CXX_FLAGS}
"$<$<CONFIG:Debug>:${CXX_FLAGS_DEBUG}>"
"$<$<CONFIG:Release>:${CXX_FLAGS_RELEASE}>")
target_link_libraries(main interp)
$ cd build && rm -fr *
$ cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug ..
$ cmake --build . -- VERBOSE=1

Outputting Selected Compiler Flags

>> include(CMakePrintHelpers)
cmake_print_variables(CXX_FLAGS)
cmake_print_variables(CXX_FLAGS_DEBUG)
cmake_print_variables(CXX_FLAGS_RELEASE)

add_library(interp interpolate.h interpolate.cpp)
$ cmake --help-module CMakePrintHelpers
Building a release configuration of our project.

In Conclusion

Related Articles

MSc. Programmer and fan of open source software.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store