Detecting your environment

Questions

  • How does CMake interact with the host environment?

Objectives

  • Learn how to discover the operating system.

  • Learn how to discover processor characteristics.

  • Learn how to handle platform- and compiler-dependent source code.

CMake comes pre-configured with sane defaults for a multitude of properties of the environments in which it can be used. Default generator, default compilers, and compiler flags are few and most notable examples of this up-front configuration. Run the following:

$ cmake --system-information | less

if you are curious about what kind of configuration ships for your version of CMake and operating system.

In this episode, we will show how to use CMake to introspect the environment in which we are running. This is very common in build systems, since it allows to customize the creation of artifacts on-the-fly.

Discovering the processor

A common customization is to apply processor-specific compiler flags. We can gain such information on the host system with the built-in cmake_host_system_information command.

Exercise 14: Get to know your host

The scaffold project is based on the previous typealong and can be found in the content/code/day-1/14_host_system_information folder.

  1. Open the help page for cmake_host_system_information. Either in the browser or in the command-line:

    $ cmake --help-command cmake_host_system_information
    
  2. Extend the scaffold code to query all keys listed in the help page and print them out.

A working solution is in the solution subfolder.

Platform- and compiler-dependent source code

It might be more convenient to have a single file containing all these compile-time constants, rather than passing them to preprocessor. This can be achieved by having a scaffold file and then letting CMake configure it after discovering the values for all the necessary compile-time constants.

Exercise 16: Configure a file

Let’s revisit one of the previous exercises. Rather than print the results of querying with cmake_host_system_information, we want to save the results to a header file and then use it to print the results when running an executable.

The source code for this project is in the content/code/day-1/16_configure folder. The header file config.h.in contains placeholders for the values that we will detect using CMake: u number of physical cores, total physical memory, OS name, and OS platform.

  1. Copy-paste the CMakeLists.txt from the content/code/day-1/14_host_system_information folder.

  2. Adapt the CMakeLists.txt to compile processor-info.cpp into an executable with add_executable.

  3. Try building. This should fail, because there is no config.h file anywhere yet!

  4. Open the help page for configure_file. Either in the browser or in the command-line:

    $ cmake --help-command configure_file
    
  5. Query the keys (number of physical cores, total physical memory, OS name, and OS platform) using the corresponding names listed in the help page for cmake_host_system_information and save them to appropriately named variables.

  6. Invoke configure_file to produce config.h from config.h.in. The configured file will be saved in the build folder, i.e. PROJECT_BINARY_DIR.

  7. Try building again. This will fail too, because the header is not in the include path. We can fix this with:

    target_include_directories(processor-info
      PRIVATE
        ${PROJECT_BINARY_DIR}
      )
    

A complete, working example is in the solution subfolder.

Keypoints

  • CMake can introspect the host system.

  • You can build source code differently, based on the OS, the processor, the compiler, or any combination thereof.

  • You can generate source code when configuring the project with configure_file.