CMakeLists.txt / CML / lists file

Commands? Commands are directives provided in CML to create executable or library.

Creating executable


$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.23)             #CMake version         #1st 2 are Mandatory commands
project(MyProjectName)                           #project-name

add_executable(MyProgram)                        #(exe_name)
target_sources(MyProgram
  PRIVATE                                        # Scope: See below
    MyProgram/main.cpp                           
)

$ cmake -B build
$ ls build
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake

$ cmake --build build      //Create Executable
$ ls build
CMakeCache.txt  CMakeFiles  Makefile  MyProjectName  cmake_install.cmake
      

Build Static Library *.a


$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.23)              #CMake version         #1st 2 are Mandatory commands
project(MyProjectName)                            #project-name

add_library(MyLibrary)                            #Defines a library name to be created. Does not build library
target_sources(MyLibrary
  PRIVATE                                         #Scope: See below
    main.cxx                                      #Source code

  PUBLIC                                          # Scope: See below
    FILE_SET myHeaders                            #name of SET=myheaders (OPTIONAL)
    TYPE HEADERS                                  #TYPE type: kind of files we are describing headers.
    BASE_DIRS                                     #BASE_DIRS: Location of files
      include
    FILES                                         #FILES: is the list of files
      include/library_header.h
)

$ cmake -B build
$ ls build
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake

$ cmake --build build      //Create Library
$ ls build
CMakeCache.txt  CMakeFiles  Makefile  libMathFunctions.a  cmake_install.cmake
      

cmake_minimum_required(VERSION 3.22.1)            #CMake version          #1st 2 are Mandatory commands
project(Tutorial)                                 #project-name
add_executable(Tutorial Tutorial/Tutorial.cxx)    #(exe_name generate_from_main.cpp)
target_link_libraries(Tutorial                    #Link Library(MathFunctions) to executable(Tutorial)
        PRIVATE
                MathFunctions
)

add_library(MathFunctions)                        #Defines a library name to be created. Does not build library

target_sources(MathFunctions                      #Create target(MathFunctions library) using source(MathFunctions.cxx)
  PRIVATE
    MathFunctions/MathFunctions.cxx

  PUBLIC
    FILE_SET HEADERS
    BASE_DIRS
      MathFunctions
    FILES
      MathFunctions/MathFunctions.h
)

$ cmake -B build
$ ls build
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake

$ cmake --build build      //Create Library
$ ls build/
CMakeCache.txt  CMakeFiles  Makefile  Tutorial  cmake_install.cmake  libMathFunctions.a
$ ./build/Tutorial 34
The square root of 34 is 5.83095
      

Subdirectories(Multiple CMakeLists.txt files)

Top level CMakeLists.txt
Subdirectory(Tutorial) contains commands to build executable(earlier it was in top level CML)

$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1)        #CMake version         #1st 2 are Mandatory commands
project(Tutorial)                             #Project name
add_subdirectory(Tutorial)

$ cat Tutorial/CMakeLists.txt
add_executable(Tutorial Tutorial.cxx)           #(exe_name generate_from_Tutorial.cxx)
target_sources(Tutorial                         #Create target(Tutorial executable) using source(Tutorial.cxx)
  PRIVATE
    Tutorial.cxx
)
target_link_libraries(Tutorial                  #Link Library(MathFunctions) to executable(Tutorial)
  PRIVATE
    MathFunctions
)

          

$ cmake -B build
$ ls build
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake

$ cmake --build build      //Create Library
$ ls build/
CMakeCache.txt  CMakeFiles  Makefile  Tutorial  cmake_install.cmake  libMathFunctions.a
$ ./build/Tutorial 34
The square root of 34 is 5.83095
            

Types / Variables

CMake only has 2 types: strings and lists
CMake Type Description
Strings

$ cat CMakeLists.txt
set (city "delhi")                            # Create a variable using set, provide initial value
message ("${city}")                           # Print value of variable

$ cmake -P CMakeLists.txt                     # -p is script mode. it informs CMake this file is not intended to have a project() command
delhi
            
Lists:
Strings with semicolons
Append to list

$ cat CMakeLists.txt
set (cities "delhi")                  # Create a variable using set, provide initial value
list (APPEND cities "jaipur")         # append to List. 
message ("Cities: ${cities}")

$ cmake -P CMakeLists.txt
Cities: delhi;jaipur
            
Iterating using foreach

$ cat CMakeLists.txt
set (cities "delhi")              # Create a variable using set, provide initial value
list (APPEND cities "jaipur")     # append to List. 

foreach (city IN LISTS cities)    # Iterate over list
        message("city: ${city}")
endforeach()

$ cmake -P CMakeLists.txt
city: delhi
city: jaipur
            

Functions, Macros

Similar to C/C++, functions & macros have statments/commands which can be called later and would be repeated if not done in function
Function Macros
Difference 1. Can see all the variables created in all the frames above them
2. Functions create local copy of variable
1. Can see all the variables created in all the frames above them
2. Macros donot create local copies, work on global variable directly
Creation & Calling

function(name [arg1 ...])
  commands
endfunction()
name
          

macro(name [arg1 ...])
  commands
endmacro()
name
          
1. Can see all the variables created in all the frames above them

$ cat CMakeLists.txt
set (cities "delhi")
list (APPEND cities "jaipur")
function(foo)               # Function
        message ("cities: ${cities}") #Function can see vars declared above
endfunction()
foo()                       # Calling function

$ cmake -P CMakeLists.txt
cities: delhi;jaipur
          

$ cat CMakeLists.txt
set (cities "delhi")
list (APPEND cities "jaipur")
macro(bar)               
        message ("cities: ${cities}") #macro can see vars declared above
bar()                       # Calling macro
$ cmake -P CMakeLists.txt
cities: delhi;jaipur
          
2. Functions create local copy of variable
Macro works on global variable only

$ cat CMakeLists.txt
set (cities "delhi")
list (APPEND cities "jaipur")
function(foo)
        list (APPEND cities "pune")
        message ("Function cities: ${cities}")
endfunction()
foo()

$ cmake -P CMakeLists.txt
Function cities: delhi;jaipur;pune
After fun call cities: delhi;jaipur
            

$ cat CMakeLists.txt
set (cities "delhi")
list (APPEND cities "jaipur")
macro(foo)
        list (APPEND cities "pune")
        message ("macro cities: ${cities}")
endmacro()
foo()
message ("After macro call cities: ${cities}")

$ cmake -P CMakeLists.txt
macro cities: delhi;jaipur;pune
After macro call cities: delhi;jaipur;pune
            
Arguments Arguments are passed in order.
function(my_function ARG1 ARG2)
ARGN(Unnamed Argument): any additional arguments passed beyond ARG2.

$ vim CMakeLists.txt
function(fun ARG1 ARG2)               #fun us function name. ARG1, ARG2 are arguments
    message("ARG1: ${ARG1}")
    message("ARG2: ${ARG2}")
    message("Remaining arguments (ARGN): ${ARGN}")
endfunction()
fun(value_for_arg1 value_for_arg2 extra_arg1 extra_arg2)    #Calling the function

$ cmake -p CMakeLists.txt
ARG1: value_for_arg1
ARG2: value_for_arg2
Remaining arguments (ARGN): extra_arg1 extra_arg2
          
same

Keywords

scope (PUBLIC, PRIVATE, INTERFACE)

1. PRIVATE / non-interface property

only available to the target which owns it for example PRIVATE headers will only be visible to the target they're attached to.

INTERFACE

Only available to targets which link the owning target. A header-only library is an example of a collection of INTERFACE properties

PUBLIC

union of the PRIVATE and INTERFACE properties. PUBLIC are available to both the owning target and consuming targets.

target_sources(MyLibrary
  PRIVATE
    FILE_SET internalOnlyHeaders
    TYPE HEADERS
    FILES
      InternalOnlyHeader.h

  INTERFACE
    FILE_SET consumerOnlyHeaders
    TYPE HEADERS
    FILES
      ConsumerOnlyHeader.h

  PUBLIC
    FILE_SET publicHeaders
    TYPE HEADERS
    FILES
      PublicHeader.h
)
      

Conditionals & Loops

if ()


$ cat test.cmake
set(var True)
if(var)
  message("Defined Variable: True")
else()
  message("Defined Variable: False")
endif()

$ cmake -P test.cmake
Defined Variable: True