- CMakeLists.txt Composition
- CMake Commands
- Targets
- Propagating Target Properties
- Target Prefix/Suffix
- Library Folder Structure
command1(arg_a1, arg_a2, arg_a3 ...)
command2(arg_b1, arg_b2, arg_b3 ...)
command3(arg_a1,
arg_a2,
...)
command4(arg_d1, arg_d2, arg_d3)
- This command is used when we want an executable at the end of the process.
- We have to provide the name of the final executable and the source files required to build the executable.
- The naming sequence of the source files does not matter, BUT the name of the executable must be the first argument.
- This command states the name of the project, e.g. 'calculator'
- The version of the project is stated using 'VERSION ', e.g. 1.0.0
- This command states the minimum required CMake version.
- We are telling CMake that all the features in the CMakeLists.txt are supported by that version.
- It is important to test with other versions of CMake to ensure the most amount of people can use it.
- This command links a library to an executable.
- Modes of Message Display
- message("Hello World")
- message(STATUS "Hello World")
- message(DEBUG "Hello World")
- message(WARNING "Hello World")
- message(FATAL ERROR "Hello World")
Message Command | Output |
---|---|
message(NAME ${NAME} ${${NAME}} |
NAMELiamJames |
message(NAME${NAME}${${NAME}}) |
NAMELiamJames |
message("NAME ${NAME} ${${NAME}}") |
AME Liam James |
-
NOTE: All the variables in CMake are of string type
- Variable De-referencing:
${variable_name}
- If you try to de-reference a variable that has not been set, it will give you an empty string
- Variable De-referencing:
-
Strings & Lists:
set(NAME "Liam Ross")
-> String 'NAME' = Liam Rossset(NAME Liam Ross)
-> List 'NAME' = Liam;Ross
-
Quoted & Unquoted Arguments
Set Commands | Value of VAR | message(${VAR}) | message("${VAR}") |
---|---|---|---|
set(VAR aa bb cc) |
aa;bb;cc | aabbcc | aa;bb;cc |
set(VAR aa;bb;cc) |
aa;bb;cc | aabbcc | aa;bb;cc |
set(VAR "aa" "bb" "cc") |
aa;bb;cc | aabbcc | aa;bb;cc |
set(VAR "aa bb cc") |
aa bb cc | aa bb cc | aa bb cc |
set(VAR "aa;bb;cc") |
aa;bb;cc | aabbcc | aa;bb;cc |
-
The subcommand tells CMake which operation is to be performed
APPEND
INSERT
FILTER
GET
JOIN
-
Setting a List variable:
set(VAR a b c;d "e;f" 2.718 "Hello There")
# 0 1 2 3 4 5 6 7 (Indexes)
# -8-7-6-5 -4-3 -2 -1 (Indexes Reversed)
- List Commands:
APPEND
REMOVE_ITEM
REMOVE_AT
INSERT
REVERSE
REMOVE_DUPLICATES
SORT
set(VAR a b c;d "e;f" 2.718 "Hello There")
List Commands | Output |
---|---|
list(APPEND VAR 1.6 XX) |
abcdef2.7Hello There1.6XX |
list(REMOVE_AT VAR 2 -3) |
abdef2.71.6XX |
list(REMOVE_ITEM VAR a 2.7) |
bdef1.6XX |
list(INSERT VAR 2 XX 2.7) |
bdXX2.7ef1.6XX |
list(REVERSE VAR) |
XX1.6fe2.7XXdb |
list(REMOVE_DUPLICATES VAR) |
XX1.6fe2.7db |
list(SORT VAR) |
1.62.7XXbdef |
- Current List: 1.6; 2.7; XX; b; d; e; f
- These set of subcommands return a value
- NOTE: The
FIND
subcommand will return -1 if the specified element was not found
List Commands | Output |
---|---|
list(LENGTH VAR len_var) |
len_var = 7 |
list(GET VAR 2 5 7 sub_list) |
sub_list = XX;e;f |
list(SUBLIST VAR 2 3 sub_list2) |
sub_list2 = XX;b;d |
list(JOIN VAR 0 str_var) |
str_var = 1.6++2.7+XX++b++d++e++f |
list(FIND VAR find_var) |
find_var = 2 |
FIND
REPLACE
PREPEND
APPEND
TOLOWER
TOUPPER
COMPARE
set(VAR "CMake for Cross-Platform C++ Projects")
string(FIND ${VAR} "for" find_var)
message(${find_var}) # Outputs -> 5 (Returns -1 if the substring is not found)
string(REPLACE "Projects" "Project" replaced_var ${VAR})
message(${replaced_var}) # Outputs -> CMake for Cross-Platform C++ Project
string(PREPEND replaced_var "Master")
message(${replaced_var}) # Outputs -> Master CMake for Cross-Platform C++ Project
string(APPEND replaced_var "Building")
message(${replaced_var}) # Outputs -> Master CMake for Cross-Platform C++ Project Building
set(UPPER_CASE_VAR "MASTER CMAKE FOR CROSS-PLATFORM C++ PROJECT BUILDING")
string(COMPARE ${UPPER_CASE_VAR} "MASTER CMAKE FOR CROSS-PLATFORM C++ PROJECT BUILDING" equality_check_var)
message(${equality_check_var}) # Outputs 1
READ
WRITE
RENAME
REMOVE
COPY
DOWNLOAD
LOCK
if(<condition>)
<command1>
<command2>
endif()
if(<condition>)
<commands>
elseif(<condition)
<commands>
else()
<commands>
endif()
-
Constants:
1
,ON
,YES
,TRUE
,Y
, a non-zero number: TRUE0
,OFF
,NO
,FALSE
,IGNORE
,NOTFOUND
, empty string, string ending with-NOTFOUND
: FALSE
-
Using variables with
if()
:
# Constant:
if(YES)
<commands>
endif()
# Variable:
if(YE)
<commands>
endif()
-
if()
Conditions:- Unary tests
- Binary tests
- Boolean operators
-
if()
Conditions | Unary testsDEFINED
- Used to check if a variable is set or not set.COMMAND
- Used to check if a command exists or not.EXISTS
- Used to check if a file or directory exists or not.
-
if()
Conditions | Boolean operatorsif(NOT DEFINED VAR)
if(NOT(VAR STREQUAL "test" OR VAR2 STREQUAL "test2"))
if(NOT(VAR STREQUAL "test" AND VAR2 STREQUAL "test2"))
- Name is the loop variable; Liam, Erin & Gerard are the items that are being looped through
foreach(Name Liam Erin Gerard)
<commands>
endforeach()
foreach(Name Liam;Erin;Gerard)
<commands>
endforeach()
- Start value and end value is always inclusive
foreach(x RANGE 10) # -> Range[0 -> 10]
<commands>
endforeach()
foreach(x RANGE 10 20) # -> Range[10 -> 20]
<commands>
endforeach()
foreach(x RANGE 10 20 3) # -> Range[10 -> 20] (Step size of 3)
<commands>
endforeach()
- Looping over a list of lists
foreach(x IN LISTS <list1> <list2> <list3>)
<commands>
endforeach()
- Every target in CMake has come properties and dependencies associated with it.
- Target Properties
INTERFACE_LINK_DIRECTORIES
INCLUDE_DIRECTORIES
VERSION
SOURCES
- The properties can be modified or retrieved using these commands:
set_target_properties
set_property
get_property
get_target_property
- Targets can also have dependencies with one another.
- This means that if targetB is a dependency of targetA, then targetA can only be build after targetB has been build successfully.
target_link_libraries(myapp PUBLIC <item1> <item2>)
- Property:
INTERFACE_LINK_LIBRARIES
target_link_libraries(myapp INTERFACE <item1> <item2>)
- Property:
INTERFACE_LINK_LIBRARIES
target_include_directories(my_math PUBLIC include)
target_include_directories(my_math INTERFACE include)
-
Property:
INTERFACE_INCLUDE_DIRECTORIES
-
Of Target: my_math
-
Example: Calculator's Dependencies
target_link_libraries(calculator my_math my_print)
- Property Propagation:
- Properties of my_math:
- Property A = aaa
- Property B = bbb
- Property C = ccc
- Properties of my_print:
- Property A = xxx
- Property B = yyy
- Property C = zzz
- Properties of my_math:
-
PUBLIC
,PRIVATE
orINTERFACE
:target_include_directories(my_print PRIVATE include)
- Property:
INTERFACE_INCLUDE_DIRECTORIES
- Of Target: my_print
- Property set to:
- Property:
-
Calculator Example:
Question | Answer | Answer | Answer |
---|---|---|---|
Does 'my_math' need the directory? | Yes | No | Yes |
Are the other targets, depending upon 'my_math' going to need this include directory? | Yes | Yes | No |
PUBLIC | INTERFACE | PRIVATE |
- Commands that frequently require scope:
Command | Property set by the command |
---|---|
target_compile_definitions |
INTERFACE_COMPILE_DEFINITIONS |
target_sources |
INTERFACE_SOURCES |
target_compile_features |
INTERFACE_COMPILE_FEATURES |
target_compile_options |
INTERFACE_COMPILE_OPTIONS |
target_link_directories |
INTERFACE_LINK_DIRECTORIES |
target_link_libraries |
INTERFACE_LINK_LIBRARIES |
target_link_options |
INTERFACE_LINK_OPTIONS |
target_precompile_headers |
INTERFACE_PRECOMPILE_HEADERS |
- If a target has both public requirements and private requirements:
target_include_directories(target PRIVATE xxx PUBlIC yyy)
# OR
target_include_directories(target PRIVATE xxx)
target_include_directories(target PUBlIC yyy)
- Example:
- my_math
- my_math.lib
- my_math.dll
- my_math.a
- my_math.so
- libmy_mathso (lib prefix is OS dependent)
- my_math
---> include/ ---> libraryName/ ---> *.h
|
|
libraryName/ ----> src/ ---> *.cpp
|
|
---> CMakeLists.txt