DEV Community

Minwook Je
Minwook Je

Posted on

CMake Intro

CMake is a configuration program, sometimes called a "meta" build system. CMake generates a build system based on project, environment, and user-provided configuration information.

Step 0

https://cmake.org/cmake/help/latest/guide/tutorial/Before%20You%20Begin.html

  • -D: Define, preprocessing time
  • -l: link time
$ cmake -G # select generator

$ cmake -S # source root dir, default current working dir

$ cmake -B # build dir, output generated build system

$ cmake --build # Build source by generated build system
Enter fullscreen mode Exit fullscreen mode
# make
cmake -B build
cmake --build build && ./build/hello
Enter fullscreen mode Exit fullscreen mode

Step 1

https://cmake.org/cmake/help/latest/guide/tutorial/Getting%20Started%20with%20CMake.html

CMakeLists.txt = CML = lists file

root CML

cmake_minimum_required(VERSION 3.23)

project(MyProjectName)
Enter fullscreen mode Exit fullscreen mode
  • add_executable() or add_library(): output type
  • target_sources(): link input -> output
  • target_link_libraries(): link outputs

add_executable()

This command creates a target.

Targets themselves are simply names, a handle to these collection of properties.

  • The artifact kind (executable, lib, header collection, etc)
  • Source files
  • Include dirs
  • Output File name
  • Dependencies
  • Flags (Compiler, Linker)
add_executable(MyProgram)
Enter fullscreen mode Exit fullscreen mode

target_sources()

Now that we have a name for our target, we can start associating properties with it like source files we want to build and link.

target_sources(MyProgram
  PRIVATE
    main.cxx
)
Enter fullscreen mode Exit fullscreen mode

Above PRIVATE(scope keyword) means main.cxx property only belongs to MyProgram and is not inheritable.

add_library()

We need to know about header files in order to build other parts of a given target.

add_library(MyLibrary)

target_sources(MyLibrary
  PRIVATE
    library_implementation.cxx

  PUBLIC
    FILE_SET myHeaders
    TYPE HEADERS # HEADERS or MODULES
    BASE_DIRS
      include
    FILES
      include/library_header.h
)
Enter fullscreen mode Exit fullscreen mode

PUBLIC: allows consumers of our library to "see" the library's header files.

Notably, if the FILE_SET name is the same as the type, we don't need to provide the TYPE field.

target_sources(MyLibrary
  PRIVATE
    library_implementation.cxx

  PUBLIC
    FILE_SET HEADERS
    BASE_DIRS
      include
    FILES
      include/library_header.h
)
Enter fullscreen mode Exit fullscreen mode

target_link_libraries()

It describes relationships between targets generally.

target_link_libraries(MyProgram
  PRIVATE
    MyLibrary
)
Enter fullscreen mode Exit fullscreen mode

scope

  • PRIVATE
  • INTERFACE
  • PUBLIC
  • The order here is only loosely relevant. That we call target_link_libraries() prior to defining MathFunctions with add_library() doesn't matter to CMake.

add_subdirectory()

allows us to incorporate CMLs located in subdirectories

When a CMakeLists.txt in a subdirectory is being processed by CMake all relative paths described in the subdirectory CML are relative to that subdirectory, not the top-level CML.

add_subdirectory(SubdirectoryName)
Enter fullscreen mode Exit fullscreen mode

Step2

Data type

The only fundamental types in CMakeLang are strings and lists.

set(var "World!")
message("Hello ${var}")
Enter fullscreen mode Exit fullscreen mode

List

Every object in CMake is a string, and lists are themselves strings which contain semicolons as separators.

set(list "A;B")
list(APPEND list "C")

message(${list}) # string
message("${list}") # list(string with ; format)
Enter fullscreen mode Exit fullscreen mode
set(name "Minwook")
message(name) # name
message(${name}) # Minwook
message("${name}") # Minwook


set(arr "A;B;C")
message(arr) # arr
message(${arr}) # ABC
message("${arr}") # A;B;C
Enter fullscreen mode Exit fullscreen mode

Boolean

Conditionals are entirely by convention of which strings are considered true and which are considered false

function() and macro()

In CMakeLang, both function() and macro() can "see" all the variables created in all the frames above them.

But, a macro() acts semantically like a text replacement, so side effects the macro creates are visible in their calling context. If we create or change a variable in a macro, the caller will see the change.

function() creates its own variable scope.

macro(MyMac)
  set(MacVar "GLOBAL")
endmacro()


function(MyFunc)
  set(FuncVar "LOCAL")
endfunction()

MyFunc()
MyMac()
message("${FuncVar}") # x
message("${MacVar}") # GLOBAL
Enter fullscreen mode Exit fullscreen mode

Step3

The names created by -D flags and option() are not normal variables, they are cache variables.

option(COMPRESSION_SOFTWARE_USE_ZLIB "Support Zlib compression" ON)
option(COMPRESSION_SOFTWARE_USE_ZSTD "Support Zstd compression" ON)

if(COMPRESSION_SOFTWARE_USE_ZLIB)
  # Same as before
# ...
Enter fullscreen mode Exit fullscreen mode
$ cmake -B build \
    -DCOMPRESSION_SOFTWARE_USE_ZLIB=OFF
...
I will use Zstd!
Enter fullscreen mode Exit fullscreen mode

set() can also be used to manipulate cache variables, but will not change a variable which has already been created.

set(StickyCacheVariable "I will not change" CACHE STRING "") # Cache 1
set(StickyCacheVariable "Overwrite StickyCache" CACHE STRING "") # Cache 2

message("StickyCacheVariable: ${StickyCacheVariable}")
Enter fullscreen mode Exit fullscreen mode

Because -D flags are processed before any other commands, they take precedence for setting the value of a cache variable.

$ cmake \
  -DStickyCacheVariable="Commandline always wins" \
  -P StickyCacheVariable.cmake
StickyCacheVariable: Commandline always wins
Enter fullscreen mode Exit fullscreen mode

FYI, cache var cannot be changed, they can be shadowed by normal variables by set() and can be unset()

set(ShadowVariable "In the shadows" CACHE STRING "")
set(ShadowVariable "Hiding the cache variable")
message("ShadowVariable: ${ShadowVariable}")

unset(ShadowVariable)
unset(ShadowVariable)
unset(ShadowVariable)
message("ShadowVariable: ${ShadowVariable}")
Enter fullscreen mode Exit fullscreen mode
$ cmake -P ShadowVariable.cmake
ShadowVariable: Hiding the cache variable
ShadowVariable: In the shadows
Enter fullscreen mode Exit fullscreen mode

Top comments (0)