Oh No More Modern CMake
Oh No More Modern CMake
✉ cmake@deniz.bahadir.email
@DenizThatMenace
https://github.com/Bagira80/More-Modern-CMake/
1 / 50
Deniz Bahadir
✉ cmake@deniz.bahadir.email
@DenizThatMenace
https://github.com/Bagira80/More-Modern-CMake/
1 / 50
source: http://gph.is/1fvlBsY
2 / 50
A '
https://youtu.be/y7ndUhdQuU8
3 / 50
A '
https://youtu.be/y7ndUhdQuU8
Who has seen last year's talk?
3 / 50
A
4 / 50
W (M ) CM ?
CMake
Modern CMake
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
Modern CMake
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
supports generating build-system input files for multiple languages.
C/C++ , FORTRAN, C#, CUDA...
Modern CMake
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
supports generating build-system input files for multiple languages.
C/C++ , FORTRAN, C#, CUDA...
Modern CMake
it is called since version 3.0,
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
supports generating build-system input files for multiple languages.
C/C++ , FORTRAN, C#, CUDA...
Modern CMake
it is called since version 3.0,
or since 2.8.12, to be precise
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
supports generating build-system input files for multiple languages.
C/C++ , FORTRAN, C#, CUDA...
Modern CMake
it is called since version 3.0,
or since 2.8.12, to be precise
is the target-centric approach
Each target carries its own build- and usage-requirements.
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
supports generating build-system input files for multiple languages.
C/C++ , FORTRAN, C#, CUDA...
Modern CMake
it is called since version 3.0,
or since 2.8.12, to be precise
is the target-centric approach
Each target carries its own build- and usage-requirements.
Each new version improves CMake
5 / 50
W (M ) CM ?
CMake
is a portable build-system generator,
generates input files for build-systems (Make, Ninja, Visual Studio, ...),
supports generating build-system input files for multiple languages.
C/C++ , FORTRAN, C#, CUDA...
Modern CMake
it is called since version 3.0,
or since 2.8.12, to be precise
is the target-centric approach
Each target carries its own build- and usage-requirements.
Each new version improves CMake
and provides new features and simplifications .
5 / 50
T
6 / 50
T
B
6 / 50
T
B
"Everything that is needed to (successfully) build that target."
U
"Everything that is needed to (successfully) use that target,
as a dependency of another target."
6 / 50
T
B
"Everything that is needed to (successfully) build that target."
U
"Everything that is needed to (successfully) use that target,
as a dependency of another target."
source-files
include search-paths
pre-processor macros
link-dependencies
compiler/linker-options
compiler/linker-features
(e.g. support for a C++-standard)
6 / 50
C
Traditional CMake Modern CMake
on environment (mainly)
build-requirements are set on? on targets*
e.g. directory scope
keeping track of via targets
via (cache-)variables
usage-requirements (keep track themselves)
usage-requirements propagation
explicit propagation
from dependency (by using automatic propagation
by hand**
target_link_libraries command)
Less error-prone!
More error-prone! Allows for more fine-
grained configuration.
* Or already on dependencies.
** Only paths to library-files are propagated by default. 7 / 50
M CM
B U
01 # Adding build-requirements
02
03 target_include_directories( <target> PRIVATE <include-search-dir>... )
04 target_compile_definitions( <target> PRIVATE <macro-definitions>... )
05 target_compile_options( <target> PRIVATE <compiler-option>... )
06 target_compile_features( <target> PRIVATE <feature>... )
07 target_sources( <target> PRIVATE <source-file>... )
08 target_precompile_headers( <target> PRIVATE <header-file>... )
09 target_link_libraries( <target> PRIVATE <dependency>... )
10 target_link_options( <target> PRIVATE <linker-option>... )
11 target_link_directories( <target> PRIVATE <linker-search-dir>... )
01 # Adding usage-requirements
02
03 target_include_directories( <target> INTERFACE <include-search-dir>... )
04 target_compile_definitions( <target> INTERFACE <macro-definitions>... )
05 target_compile_options( <target> INTERFACE <compiler-option>... )
06 target_compile_features( <target> INTERFACE <feature>... )
07 target_sources( <target> INTERFACE <source-file>... )
08 target_precompile_headers( <target> INTERFACE <header-file>... )
09 target_link_libraries( <target> INTERFACE <dependency>... )
10 target_link_options( <target> INTERFACE <linker-option>... )
11 target_link_directories( <target> INTERFACE <linker-search-dir>... )
8 / 50
M CM
B U
01 # Adding build-requirements
02
03 target_include_directories( <target> PRIVATE <include-search-dir>... )
04 target_compile_definitions( <target> PRIVATE <macro-definitions>... )
05 target_compile_options( <target> PRIVATE <compiler-option>... )
06 target_compile_features( <target> PRIVATE <feature>... )
07 target_sources( <target> PRIVATE <source-file>... )
08 target_precompile_headers( <target> PRIVATE <header-file>... )
09 target_link_libraries( <target> PRIVATE <dependency>... )
10 target_link_options( <target> PRIVATE <linker-option>... )
11 target_link_directories( <target> PRIVATE <linker-search-dir>... )
01 # Adding usage-requirements
02
03 target_include_directories( <target> INTERFACE <include-search-dir>... )
04 target_compile_definitions( <target> INTERFACE <macro-definitions>... )
05 target_compile_options( <target> INTERFACE <compiler-option>... )
06 target_compile_features( <target> INTERFACE <feature>... )
07 target_sources( <target> INTERFACE <source-file>... )
08 target_precompile_headers( <target> INTERFACE <header-file>... )
09 target_link_libraries( <target> INTERFACE <dependency>... )
10 target_link_options( <target> INTERFACE <linker-option>... )
11 target_link_directories( <target> INTERFACE <linker-search-dir>... )
8 / 50
M CM
B U
01 # Adding build-requirements
02
03 target_include_directories( <target> PRIVATE <include-search-dir>... )
04 target_compile_definitions( <target> PRIVATE <macro-definitions>... )
05 target_compile_options( <target> PRIVATE <compiler-option>... )
06 target_compile_features( <target> PRIVATE <feature>... )
07 target_sources( <target> PRIVATE <source-file>... )
08 target_precompile_headers( <target> PRIVATE <header-file>... )
09 target_link_libraries( <target> PRIVATE <dependency>... )
10 target_link_options( <target> PRIVATE <linker-option>... )
11 target_link_directories( <target> PRIVATE <linker-search-dir>... )
01 # Adding usage-requirements
02
03 target_include_directories( <target> INTERFACE <include-search-dir>... )
04 target_compile_definitions( <target> INTERFACE <macro-definitions>... )
05 target_compile_options( <target> INTERFACE <compiler-option>... )
06 target_compile_features( <target> INTERFACE <feature>... )
07 target_sources( <target> INTERFACE <source-file>... )
08 target_precompile_headers( <target> INTERFACE <header-file>... )
09 target_link_libraries( <target> INTERFACE <dependency>... )
10 target_link_options( <target> INTERFACE <linker-option>... )
11 target_link_directories( <target> INTERFACE <linker-search-dir>... )
8 / 50
M CM
B U
01 # Adding build-requirements
02
03 target_include_directories( <target> PRIVATE <include-search-dir>... )
04 target_compile_definitions( <target> PRIVATE <macro-definitions>... )
05 target_compile_options( <target> PRIVATE <compiler-option>... )
01 # Adding
06 build- and usage-requirements
target_compile_features( <target> PRIVATE <feature>... )
02 07 target_sources( <target> PRIVATE <source-file>... )
03 08 target_precompile_headers(
target_include_directories( <target>PUBLIC
<target> PRIVATE <header-file>... )
<include-search-dir>... )
09 target_link_libraries( <target> PRIVATE <dependency>... )
04 target_compile_definitions(
10 target_link_options(
<target> PUBLIC
<target> PRIVATE
<macro-definitions>...
<linker-option>... )
)
05 target_compile_options(
11 target_link_directories(<target>
<target>PUBLIC
PRIVATE <compiler-option>...
<linker-search-dir>... ) )
06 target_compile_features( <target> PUBLIC <feature>... )
07 target_sources( <target> PUBLIC <source-file>... )
01 # Adding usage-requirements
08 target_precompile_headers(
02
<target> PUBLIC <header-file>... )
09 target_link_libraries( <target>
03 target_include_directories( <target>PUBLIC <dependency>...
INTERFACE )
<include-search-dir>... )
10 04 target_compile_definitions(
target_link_options( <target>PUBLIC
<target> INTERFACE <macro-definitions>... ))
<linker-option>...
05 target_compile_options( <target> INTERFACE <compiler-option>... )
11 target_link_directories( <target> PUBLIC <linker-search-dir>... )
06 target_compile_features( <target> INTERFACE <feature>... )
07 target_sources( <target> INTERFACE <source-file>... )
08 target_precompile_headers( <target> INTERFACE <header-file>... )
09 target_link_libraries( <target> INTERFACE <dependency>... )
10 target_link_options( <target> INTERFACE <linker-option>... )
11 target_link_directories( <target> INTERFACE <linker-search-dir>... )
8 / 50
M CM
B U
01 # Adding build-requirements
02
03 target_include_directories( <target> PRIVATE <include-search-dir>... )
04 target_compile_definitions( <target> PRIVATE <macro-definitions>... )
05 target_compile_options( <target> PRIVATE <compiler-option>... )
06 target_compile_features( <target> PRIVATE <feature>... )
01 07# Adding
target_sources( <target> PRIVATE <source-file>... )
build- and usage-requirements
02 08 target_precompile_headers( <target> PRIVATE <header-file>... )
03 09target_include_directories(
target_link_libraries( <target>
<target> PRIVATE
PUBLIC <dependency>... )
<include-search-dir>... )
04 10target_compile_definitions(
target_link_options( <target>
<target> PRIVATE
PUBLIC <linker-option>... ))
<macro-definitions>...
05 11target_compile_options(
target_link_directories( <target>
<target> PRIVATE
PUBLIC <linker-search-dir>...
<compiler-option>... ) )
06 target_compile_features( <target> PUBLIC <feature>... )
07 target_sources( <target> PUBLIC <source-file>... )
08 01target_precompile_headers( <target> PUBLIC <header-file>... )
# Adding usage-requirements
09 02target_link_libraries( <target> PUBLIC <dependency>... )
10 03target_link_options( <target>
target_include_directories( PUBLIC
<target> <linker-option>...
INTERFACE )
<include-search-dir>... )
11 04target_link_directories( <target>
target_compile_definitions( PUBLIC
<target> <linker-search-dir>...
INTERFACE )
<macro-definitions>... )
05 target_compile_options( <target> INTERFACE <compiler-option>... )
06 target_compile_features( <target> INTERFACE <feature>... )
07 target_sources( <target> INTERFACE <source-file>... )
08 target_precompile_headers( <target> INTERFACE <header-file>... )
09 target_link_libraries( <target> INTERFACE <dependency>... )
Warning: Although target_link_libraries can be used without
10 target_link_options( <target> INTERFACE <linker-option>... )
11 target_link_directories( <target> INTERFACE <linker-search-dir>... )
these keywords, you should never forget to use these keywords in
Modern CMake! 8 / 50
I
9 / 50
.
S target_sources ├──
├──
CMakeLists.txt
𝘀𝗿𝗰/
│ ├── A.cpp
│
├──
└── B.cpp
𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
│
│
├── A.hpp
├── B.hpp
Last year's recommendation: 01 # ./CMakeLists.txt
│
└──
└── C.hpp
𝘀𝘂𝗯𝗱𝗶𝗿/
Always use target_sources to add all sources.
02
├── CMakeLists.txt
03 add_library( MyTarget SHARED )
├── 𝗲𝘅𝘁𝗿𝗮_𝘀𝗿𝗰/
Use target_sources to add header-files, too!
04 # Add some sources to target.
│ └── D.cpp
05 target_sources( MyTarget
└── 𝗲𝘅𝘁𝗿𝗮_𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
06 PRIVATE src/A.cpp
└── D.hpp
07 src/B.cpp
08 headers/B.hpp
09 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers/A.hpp
10 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/headers/C.hpp
11 )
01 # ./subdir/CMakeLists.txt
02
03 # Add further sources to target.
04 target_sources( MyTarget
05 PRIVATE subdir/extra_src/D.cpp
06 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/extra_headers/D.cpp
07 )
10 / 50
.
S target_sources ├──
├──
CMakeLists.txt
𝘀𝗿𝗰/
│ ├── A.cpp
│
├──
└── B.cpp
𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
│
│
├── A.hpp
├── B.hpp
Last year's recommendation: 01 # ./CMakeLists.txt
│
└──
└── C.hpp
𝘀𝘂𝗯𝗱𝗶𝗿/
Always use target_sources to add all sources.
02
├── CMakeLists.txt
03 add_library( MyTarget SHARED )
├── 𝗲𝘅𝘁𝗿𝗮_𝘀𝗿𝗰/
Use target_sources to add header-files, too!
04 # Add some sources to target.
│ └── D.cpp
05 target_sources( MyTarget
└── 𝗲𝘅𝘁𝗿𝗮_𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
Helps IDEs to show all sources.
06 PRIVATE src/A.cpp
└── D.hpp
07 src/B.cpp
01 # ./subdir/CMakeLists.txt
02
03 # Add further sources to target.
04 target_sources( MyTarget
05 PRIVATE subdir/extra_src/D.cpp
06 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/extra_headers/D.cpp
07 )
10 / 50
.
S target_sources ├──
├──
CMakeLists.txt
𝘀𝗿𝗰/
│ ├── A.cpp
│
├──
└── B.cpp
𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
│
│
├── A.hpp
├── B.hpp
Last year's recommendation: 01 # ./CMakeLists.txt
│
└──
└── C.hpp
𝘀𝘂𝗯𝗱𝗶𝗿/
Always use target_sources to add all sources.
02
├── CMakeLists.txt
03 add_library( MyTarget SHARED )
├── 𝗲𝘅𝘁𝗿𝗮_𝘀𝗿𝗰/
Use target_sources to add header-files, too!
04 # Add some sources to target.
│ └── D.cpp
05 target_sources( MyTarget
└── 𝗲𝘅𝘁𝗿𝗮_𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
Helps IDEs to show all sources.
06 PRIVATE src/A.cpp
└── D.hpp
07 src/B.cpp
01 # ./subdir/CMakeLists.txt
02
03 # Add further sources to target.
04 target_sources( MyTarget
05 PRIVATE subdir/extra_src/D.cpp
06 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/extra_headers/D.hpp
07 )
10 / 50
.
S target_sources ├──
├──
CMakeLists.txt
𝘀𝗿𝗰/
│ ├── A.cpp
│
├──
└── B.cpp
𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
│
│
├── A.hpp
├── B.hpp
Last year's recommendation: 01 # ./CMakeLists.txt
│
└──
└── C.hpp
𝘀𝘂𝗯𝗱𝗶𝗿/
Always use target_sources to add all sources.
02
├── CMakeLists.txt
03 add_library( MyTarget SHARED )
├── 𝗲𝘅𝘁𝗿𝗮_𝘀𝗿𝗰/
Use target_sources to add header-files, too!
04 # Add some sources to target.
│ └── D.cpp
05 target_sources( MyTarget
└── 𝗲𝘅𝘁𝗿𝗮_𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
Helps IDEs to show all sources.
06 PRIVATE src/A.cpp
└── D.hpp
07 src/B.cpp
01 # ./subdir/CMakeLists.txt
02
03 # Add further sources to target.
04 target_sources( MyTarget
05 PRIVATE subdir/extra_src/D.cpp
06 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/extra_headers/D.hpp
07 )
10 / 50
.
S target_sources ├──
├──
CMakeLists.txt
𝘀𝗿𝗰/
│ ├── A.cpp
│
├──
└── B.cpp
𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
│
│
├── A.hpp
├── B.hpp
Last year's recommendation: 01 # ./CMakeLists.txt
│
└──
└── C.hpp
𝘀𝘂𝗯𝗱𝗶𝗿/
Always use target_sources to add all sources.
02
├── CMakeLists.txt
03 add_library( MyTarget SHARED )
├── 𝗲𝘅𝘁𝗿𝗮_𝘀𝗿𝗰/
Use target_sources to add header-files, too!
04 # Add some sources to target.
│ └── D.cpp
05 target_sources( MyTarget
└── 𝗲𝘅𝘁𝗿𝗮_𝗵𝗲𝗮𝗱𝗲𝗿𝘀/
Helps IDEs to show all sources.
06 PRIVATE src/A.cpp
└── D.hpp
07 src/B.cpp
11 / 50
OBJECT
11 / 50
OBJECT
11 / 50
OBJECT
include-search-path (./headers)
04 src/source2.cpp
05 src/source3.cpp
06 )
07 target_include_directories( obj INTERFACE ./headers ) preprocessor-definition (IS_EXAMPLE=1)
08 target_compile_definitions( obj INTERFACE "IS_EXAMPLE=1" )
object files
generated from its private sources
11 / 50
OBJECT
P /
OBJECT libraries only on right-hand-side of target_link_libraries
12 / 50
OBJECT
P /
OBJECT libraries only on right-hand-side of target_link_libraries
01 add_library( obj OBJECT )
01 add_library( obj OBJECT ) 09 ... 01 add_library( obj OBJECT )
09 ... 09 ...
10 add_library( lib SHARED )
10 add_library( lib SHARED ) 10 add_library( lib SHARED )
11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp )
12 target_link_libraries( lib PRIVATE obj ) 12 target_link_libraries( lib INTERFACE obj )12 target_link_libraries( lib PUBLIC obj )
13 13
13
14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp )
14 add_executable( exe ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE lib ) 15 target_sources( exe PRIVATE main.cpp ) 16 target_link_libraries( exe PRIVATE lib )
16 target_link_libraries( exe PRIVATE lib )
12 / 50
OBJECT
P /
OBJECT libraries only on right-hand-side of target_link_libraries
12 / 50
OBJECT
P /
OBJECT libraries only on right-hand-side of target_link_libraries
12 / 50
OBJECT
P /
OBJECT libraries on le - and right-hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT )
11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp )
12 target_link_libraries( obj2 PRIVATE obj ) 12 target_link_libraries( obj2 INTERFACE obj ) 12 target_link_libraries( obj2 PUBLIC obj )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj2 ) 16 target_link_libraries( exe PRIVATE obj2 ) 16 target_link_libraries( exe PRIVATE obj2 )
13 / 50
OBJECT
P /
OBJECT libraries on le - and right-hand-side of target_link_libraries
01 add_library( obj OBJECT )
01 add_library( obj OBJECT ) 09 ... 01 add_library( obj OBJECT )
09 ... 09 ...
10 add_library( obj2 OBJECT )
10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT )
11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp )
12 target_link_libraries( obj2 PRIVATE obj )12 target_link_libraries( obj2 INTERFACE obj 12
) target_link_libraries( obj2 PUBLIC obj )
13 13
13
14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp )
14 add_executable( exe ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj2 )15 target_sources( exe PRIVATE main.cpp ) 16 target_link_libraries( exe PRIVATE obj2 )
16 target_link_libraries( exe PRIVATE obj2 )
13 / 50
OBJECT
P /
OBJECT libraries on le - and right-hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT )
11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp )
12 target_link_libraries( obj2 PRIVATE obj ) 12 target_link_libraries( obj2 INTERFACE obj ) 12 target_link_libraries( obj2 PUBLIC obj )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj2 ) 16 target_link_libraries( exe PRIVATE obj2 ) 16 target_link_libraries( exe PRIVATE obj2 )
13 / 50
OBJECT
P /
OBJECT libraries on le - and right-hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT ) 10 add_library( obj2 OBJECT )
11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp ) 11 target_sources( obj2 PRIVATE src.cpp )
12 target_link_libraries( obj2 PRIVATE obj ) 12 target_link_libraries( obj2 INTERFACE obj ) 12 target_link_libraries( obj2 PUBLIC obj )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj2 ) 16 target_link_libraries( exe PRIVATE obj2 ) 16 target_link_libraries( exe PRIVATE obj2 )
13 / 50
OBJECT
P /
OBJECT libraries only on le -hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( lib SHARED ) 10 add_library( lib SHARED ) 10 add_library( lib SHARED )
11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp )
12 target_link_libraries( obj PRIVATE lib ) 12 target_link_libraries( obj INTERFACE lib ) 12 target_link_libraries( obj PUBLIC lib )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj )
14 / 50
OBJECT
P /
OBJECT libraries only on le -hand-side of target_link_libraries
01 add_library( obj OBJECT )
01 add_library( obj OBJECT ) 09 ... 01 add_library( obj OBJECT )
09 ... 09 ...
10 add_library( lib SHARED )
10 add_library( lib SHARED ) 10 add_library( lib SHARED )
11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp )
12 target_link_libraries( obj PRIVATE lib ) 12 target_link_libraries( obj INTERFACE lib )12 target_link_libraries( obj PUBLIC lib )
13 13
13
14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp )
14 add_executable( exe ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj ) 15 target_sources( exe PRIVATE main.cpp ) 16 target_link_libraries( exe PRIVATE obj )
16 target_link_libraries( exe PRIVATE obj )
14 / 50
OBJECT
P /
OBJECT libraries only on le -hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( lib SHARED ) 10 add_library( lib SHARED ) 10 add_library( lib SHARED )
11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp )
12 target_link_libraries( obj PRIVATE lib ) 12 target_link_libraries( obj INTERFACE lib ) 12 target_link_libraries( obj PUBLIC lib )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj )
14 / 50
OBJECT
P /
OBJECT libraries only on le -hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( lib SHARED ) 10 add_library( lib SHARED ) 10 add_library( lib SHARED )
11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp )
12 target_link_libraries( obj PRIVATE lib ) 12 target_link_libraries( obj INTERFACE lib ) 12 target_link_libraries( obj PUBLIC lib )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj )
14 / 50
OBJECT
P /
OBJECT libraries only on le -hand-side of target_link_libraries
01 add_library( obj OBJECT ) 01 add_library( obj OBJECT ) 01 add_library( obj OBJECT )
09 ... 09 ... 09 ...
10 add_library( lib SHARED ) 10 add_library( lib SHARED ) 10 add_library( lib SHARED )
11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp ) 11 target_sources( lib PRIVATE src.cpp )
12 target_link_libraries( obj PRIVATE lib ) 12 target_link_libraries( obj INTERFACE lib ) 12 target_link_libraries( obj PUBLIC lib )
13 13 13
14 add_executable( exe ) 14 add_executable( exe ) 14 add_executable( exe )
15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp ) 15 target_sources( exe PRIVATE main.cpp )
16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj ) 16 target_link_libraries( exe PRIVATE obj )
14 / 50
OBJECT
P / /
PRIVATE INTERFACE PUBLIC
usage-requirements obj ➡ lib ➡ exe obj ( ➡ lib ) ➡ exe obj ➡ lib ➡ exe
usage-requirements obj ➡ obj2 ➡ exe obj ( ➡ obj2 ) ➡ exe obj ➡ obj2 ➡ exe
usage-requirements lib ➡ obj ➡ exe lib ( ➡ obj ) ➡ exe lib ➡ obj ➡ exe
object files obj ➡ lib ➡ exe obj ➡ lib ➡ exe obj ➡ lib ➡ exe
object files obj ➡ obj2 ➡ exe obj ➡ obj2 ➡ exe obj ➡ obj2 ➡ exe
link-dependencies lib ( ➡ obj ) ➡ exe lib ( ➡ obj ) ➡ exe lib ( ➡ obj ) ➡ exe
15 / 50
source: https://rich1698.wordpress.com/2018/10/05/monty-pythons-flying-circus
16 / 50
source: https://rich1698.wordpress.com/2018/10/05/monty-pythons-flying-circus
16 / 50
L
17 / 50
B CMAKELISTS.TXT
cmake_minimum_required
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
18 / 50
B CMAKELISTS.TXT
cmake_minimum_required
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
18 / 50
B CMAKELISTS.TXT
cmake_minimum_required
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call cmake_minimum_required
required: at begin of top-level CMakeLists.txt file.
easier: at begin of all CMakeLists.txt files.
18 / 50
B CMAKELISTS.TXT
cmake_minimum_required
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call cmake_minimum_required
required: at begin of top-level CMakeLists.txt file.
easier: at begin of all CMakeLists.txt files.
Sets CMake policies to defaults of specific CMake version.
cmake_policy allows to modify policies again.
(Policy-scopes exist, too.)
18 / 50
B CMAKELISTS.TXT
cmake_minimum_required
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call cmake_minimum_required
required: at begin of top-level CMakeLists.txt file.
easier: at begin of all CMakeLists.txt files.
Sets CMake policies to defaults of specific CMake version.
cmake_policy allows to modify policies again.
(Policy-scopes exist, too.)
The version range <min-version>...<max-version> syntax was introduced in 3.12, but is
backwards-compatible.
18 / 50
B CMAKELISTS.TXT
cmake_minimum_required
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call cmake_minimum_required
required: at begin of top-level CMakeLists.txt file.
easier: at begin of all CMakeLists.txt files.
Sets CMake policies to defaults of specific CMake version.
cmake_policy allows to modify policies again.
(Policy-scopes exist, too.)
The version range <min-version>...<max-version> syntax was introduced in 3.12, but is
backwards-compatible.
Recommendation: At least use version 3.15 as minimal version!
This will allow you to use the shown features.
18 / 50
B CMAKELISTS.TXT
project
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
19 / 50
B CMAKELISTS.TXT
project
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
19 / 50
B CMAKELISTS.TXT
project
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call a er cmake_minimum_required
but as early as possible.
19 / 50
B CMAKELISTS.TXT
project
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call a er cmake_minimum_required
but as early as possible.
Sets variables containing: project-name, version etc.
19 / 50
B CMAKELISTS.TXT
project
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call a er cmake_minimum_required
but as early as possible.
Sets variables containing: project-name, version etc.
😲
Default values for LANGUAGES: C and CXX
Other values: FORTRAN, CUDA, CSharp, ASM, Java ( ) ...
19 / 50
B CMAKELISTS.TXT
project
1. Define the required CMake-version. 01 # CMakeLists.txt
02
03 cmake_minimum_required( VERSION 3.15...3.17 )
Call a er cmake_minimum_required
but as early as possible.
Sets variables containing: project-name, version etc.
😲
Default values for LANGUAGES: C and CXX
Other values: FORTRAN, CUDA, CSharp, ASM, Java ( ) ...
19 / 50
B CMAKELISTS.TXT
include
1. Define the required CMake-version. 01 # CMakeLists.txt
20 / 50
B CMAKELISTS.TXT
include
1. Define the required CMake-version. 01 # CMakeLists.txt
20 / 50
B CMAKELISTS.TXT
include
1. Define the required CMake-version. 01 # CMakeLists.txt
project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )
05 # The description of this project.
06 set( project_description "Description of root-project" )
07 # The homepage of this project.
08 set( project_homepage "https://www.example.com" )
20 / 50
B CMAKELISTS.TXT
include
1. Define the required CMake-version. 01 # CMakeLists.txt
project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )
directory as CMakeLists.txt 07
08
# The homepage of this project.
set( project_homepage "https://www.example.com" )
20 / 50
B CMAKELISTS.TXT
include
1. Define the required CMake-version. 01 # CMakeLists.txt
project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )
directory as CMakeLists.txt 07
08
# The homepage of this project.
set( project_homepage "https://www.example.com" )
20 / 50
B CMAKELISTS.TXT
include
1. Define the required CMake-version. 01 # CMakeLists.txt
project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )
directory as CMakeLists.txt 07
08
# The homepage of this project.
set( project_homepage "https://www.example.com" )
CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt
21 / 50
O CMAKELISTS.TXT
CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt
21 / 50
O CMAKELISTS.TXT
CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt
21 / 50
O CMAKELISTS.TXT
CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt
21 / 50
O CMAKELISTS.TXT
CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt
file. 05
06
# The description of this project.
set( project_description "Description of root-project" )
CMAKE_CURRENT_LIST_DIR! 21 / 50
CMAKELISTS.TXT
VS
01 # subdirectory/CMakeLists.txt 01 # CMakeLists.txt
02 02
03 cmake_minimum_required( VERSION 3.15...3.17 ) 03 cmake_minimum_required( VERSION 3.15...3.17 )
04 04
05 05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06
07 # Define a project for the current CMakeLists.txt.
⇐ 06
07
"${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )
# Define a project for the current CMakeLists.txt.
08 project( MySubProject 08 project( MyRootProject
09 VERSION ${project_version} 09 VERSION ${project_version}
10 DESCRIPTION ${project_description} 10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage} 11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES CXX ) 12 LANGUAGES C CXX CUDA )
22 / 50
CMAKELISTS.TXT
VS
01 # subdirectory/CMakeLists.txt 01 # CMakeLists.txt
02 02
03 cmake_minimum_required( VERSION 3.15...3.17 ) 03 cmake_minimum_required( VERSION 3.15...3.17 )
04 04
05 05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06
07 # Define a project for the current CMakeLists.txt.
⇐ 06
07
"${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )
# Define a project for the current CMakeLists.txt.
08 project( MySubProject 08 project( MyRootProject
09 VERSION ${project_version} 09 VERSION ${project_version}
10 DESCRIPTION ${project_description} 10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage} 11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES CXX ) 12 LANGUAGES C CXX CUDA )
01 # common-project-info.in 01 # common-project-info.in
02
03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )
= 02
03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )
22 / 50
CMAKELISTS.TXT
VS
01 # subdirectory/CMakeLists.txt 01 # CMakeLists.txt
02 02
03 cmake_minimum_required( VERSION 3.15...3.17 ) 03 cmake_minimum_required( VERSION 3.15...3.17 )
04 04
05 05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06
07 # Define a project for the current CMakeLists.txt.
⇐ 06
07
"${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )
# Define a project for the current CMakeLists.txt.
08 project( MySubProject 08 project( MyRootProject
09 VERSION ${project_version} 09 VERSION ${project_version}
10 DESCRIPTION ${project_description} 10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage} 11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES CXX ) 12 LANGUAGES C CXX CUDA )
01 # common-project-info.in 01 # common-project-info.in
02
03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )
= 02
03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )
01 # subdirectory/project-meta-info.in 01 # project-meta-info.in
02 02
03 # The version number of this project. 03 # The version number of this project.
04
05
set( project_version 0.5.8 )
# The description of this project. ⇐ 04
05
set( project_version 1.2.3 )
# The description of this project.
06 set( project_description "Description of sub-project" ) 06 set( project_description "Description of root-project" )
07 # The homepage of this project. 07 # The homepage of this project.
08 set( project_homepage "https://www.example.org" ) 08 set( project_homepage "https://www.example.com" )
22 / 50
F
BOOST
23 / 50
F BOOST
L '
08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
10 set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )
11
12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
14 MODULE
15 REQUIRED COMPONENTS program_options
16 graph )
17
18
19 # Make found targets globally available.
20 if ( Boost_FOUND )
21 set_target_properties( Boost::boost
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
24 / 50
F BOOST
L '
08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
10 set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )
11
12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
14 MODULE
15 REQUIRED COMPONENTS program_options
16 graph )
17
18
19 # Make found targets globally available.
20 if ( Boost_FOUND )
21 set_target_properties( Boost::boost
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
24 / 50
F BOOST
L '
08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
FindBoost.cmake module that comes with CMake. 12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
14 MODULE
15 REQUIRED COMPONENTS program_options
16 graph )
17
18
19 # Make found targets globally available.
20 if ( Boost_FOUND )
21 set_target_properties( Boost::boost
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
24 / 50
F BOOST
L '
08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
FindBoost.cmake module that comes with CMake. 12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
24 / 50
F BOOST
L '
08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
FindBoost.cmake module that comes with CMake. 12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
This is error-prone! 20
21
if ( Boost_FOUND )
set_target_properties( Boost::boost
BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.
25 / 50
F BOOST
N B ≥ . .
BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.
25 / 50
F BOOST
N B ≥ . .
BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.
25 / 50
F BOOST
N B ≥ . .
BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.
needed. 18
19 # Make found targets globally available.
20 if ( Boost_FOUND )
21 set_target_properties( Boost::headers
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
25 / 50
F BOOST
N B ≥ . .
BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.
needed. 18
19 # Make found targets globally available.
25 / 50
F BOOST
N B ≥ . .
BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.
needed. 18
19 # Make found targets globally available.
25 / 50
F BOOST
N B ≥ . .
12
13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
15 REQUIRED COMPONENTS program_options
16 graph )
17
18
19 # Make found targets globally available.
20 if ( Boost_FOUND )
21 set_target_properties( Boost::headers
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
26 / 50
F BOOST
N B ≥ . .
Boost libraries. 08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
⇒ Boost::headers 10
11
12
13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
15 REQUIRED )
16
17
18
19 # Make found targets globally available.
20 if ( Boost_FOUND )
21 set_target_properties( Boost::headers
22
23
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
26 / 50
F BOOST
N B ≥ . .
Boost libraries. 08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
⇒ Boost::headers 10
11
12
13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
Recommendation for Boost versions ≥ 1.70.0: 15 REQUIRED COMPONENTS headers )
16
17
List headers component explicitly! 18
19 # Make found targets globally available.
In particular, if only header-only libraries are need. 20 if ( Boost_FOUND )
21 set_target_properties( Boost::headers
22
23
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
26 / 50
F BOOST
N B ≥ . .
Boost libraries. 08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )
⇒ Boost::headers 10
11
12
13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
Recommendation for Boost versions ≥ 1.70.0: 15 REQUIRED COMPONENTS headers )
16
17
List headers component explicitly! 18
19 # Make found targets globally available.
In particular, if only header-only libraries are need. 20 if ( Boost_FOUND )
21 set_target_properties( Boost::headers
This is more future-proof! 22
23
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()
26 / 50
F BOOST
N B ≥ . .
27 / 50
F BOOST
N B ≥ . .
27 / 50
F BOOST
N B ≥ . .
😧
06 set( Boost_USE_STATIC_LIBS FALSE )
What if you want to import all of Boost? 07 set( Boost_USE_MULTITHREADED TRUE )
08 set( Boost_USE_STATIC_RUNTIME FALSE )
09 set( Boost_COMPILER "-gcc8" )
10
11
12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
15 REQUIRED COMPONENTS headers
16 atomic
17 chrono
18 container
19 context
20 contract
21 coroutine
22 data_time
23 exception
24 fiber
25 fiber_numa
26 filesystem
27 graph
28 graph_parallel 27 / 50
F BOOST
N B ≥ . .
😧
06 set( Boost_USE_STATIC_LIBS FALSE )
What if you want to import all of Boost? 07 set( Boost_USE_MULTITHREADED TRUE )
08 set( Boost_USE_STATIC_RUNTIME FALSE )
09 set( Boost_COMPILER "-gcc8" )
10
11
12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
ALL component 17
18 # Make found targets globally available.
19 if ( Boost_FOUND )
20 set_target_properties( ${Boost_ALL_TARGETS}
21 PROPERTIES IMPORTED_GLOBAL TRUE )
22 endif ()
27 / 50
F BOOST
N B ≥ . .
😧
06 set( Boost_USE_STATIC_LIBS FALSE )
What if you want to import all of Boost? 07 set( Boost_USE_MULTITHREADED TRUE )
08 set( Boost_USE_STATIC_RUNTIME FALSE )
09 set( Boost_COMPILER "-gcc8" )
10
11
12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT
14 CONFIG
ALL component 17
18 # Make found targets globally available.
can be omitted. 21
22 endif ()
PROPERTIES IMPORTED_GLOBAL TRUE )
27 / 50
B
FETCHCONTENT
28 / 50
B FETCHCONTENT
U
Sometimes, using pre-built dependencies is not feasible.
29 / 50
B FETCHCONTENT
U
Sometimes, using pre-built dependencies is not feasible.
The dependency needs custom compiler flags, provided by my project, or
it is not general enough to be of use for more than my project,
...
29 / 50
B FETCHCONTENT
U
Sometimes, using pre-built dependencies is not feasible.
The dependency needs custom compiler flags, provided by my project, or
it is not general enough to be of use for more than my project,
...
Solution: Built the dependency together with your project!
29 / 50
B FETCHCONTENT
U
Sometimes, using pre-built dependencies is not feasible.
The dependency needs custom compiler flags, provided by my project, or
it is not general enough to be of use for more than my project,
...
🤨
Solution: Built the dependency together with your project!
Then I need to checkout the code when building!?
29 / 50
B FETCHCONTENT
U
Sometimes, using pre-built dependencies is not feasible.
The dependency needs custom compiler flags, provided by my project, or
it is not general enough to be of use for more than my project,
...
🤨
Solution: Built the dependency together with your project!
😱
Then I need to checkout the code when building!?
But I want to use its CMake targets before, when configuring my project!!!
29 / 50
B FETCHCONTENT
U
Sometimes, using pre-built dependencies is not feasible.
The dependency needs custom compiler flags, provided by my project, or
it is not general enough to be of use for more than my project,
...
🤨
Solution: Built the dependency together with your project!
😱
Then I need to checkout the code when building!?
But I want to use its CMake targets before, when configuring my project!!!
Introducing:
FetchContent CMake module
29 / 50
B FETCHCONTENT
O
30 / 50
B FETCHCONTENT
O
30 / 50
B FETCHCONTENT
D GOOGLETEST
01 # ./myproject/CMakeLists.txt
02
03 ...
04
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
02
03 ...
04
05 # Load FetchContent module.
06 include( FetchContent )
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
32 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt
33 / 50
P
GOOGLETEST
The CMakeLists.txt files of GoogleTest 1.8.0 are really old, and print this annoying warning.
01 CMake Warning (dev) at .../build-dir/_deps/googletest-src/CMakeLists.txt:3 (project):
02 Policy CMP0048 is not set: project() command manages VERSION variables.
03 Run "cmake --help-policy CMP0048" for policy details. Use the cmake_policy
04 command to set the policy and suppress this warning.
05
06 The following variable(s) would be set to empty:
07
08 PROJECT_VERSION
09 PROJECT_VERSION_MAJOR
10 PROJECT_VERSION_MINOR
11 PROJECT_VERSION_PATCH
12 This warning is for project developers. Use -Wno-dev to suppress it.
13
14 CMake Warning (dev) at .../build-dir/_deps/googletest-src/googlemock/CMakeLists.txt:40 (project):
15 Policy CMP0048 is not set: project() command manages VERSION variables.
25 ...
26 This warning is for project developers. Use -Wno-dev to suppress it.
27
28 CMake Warning (dev) at .../build-dir/_deps/googletest-src/googletest/CMakeLists.txt:47 (project):
29 Policy CMP0048 is not set: project() command manages VERSION variables.
38 ...
39 This warning is for project developers. Use -Wno-dev to suppress it.
34 / 50
P
GOOGLETEST
The CMakeLists.txt files of GoogleTest 1.8.0 are really old, and print this annoying warning.
01 CMake Warning (dev) at .../build-dir/_deps/googletest-src/CMakeLists.txt:3 (project):
02 Policy CMP0048 is not set: project() command manages VERSION variables.
03 Run "cmake --help-policy CMP0048" for policy details. Use the cmake_policy
04 command to set the policy and suppress this warning.
05
06 The following variable(s) would be set to empty:
07
08 PROJECT_VERSION
09 PROJECT_VERSION_MAJOR
10 PROJECT_VERSION_MINOR
11 PROJECT_VERSION_PATCH
12 This warning is for project developers. Use -Wno-dev to suppress it.
13
14 CMake Warning (dev) at .../build-dir/_deps/googletest-src/googlemock/CMakeLists.txt:40 (project):
15 Policy CMP0048 is not set: project() command manages VERSION variables.
25 ...
26 This warning is for project developers. Use -Wno-dev to suppress it.
27
28 CMake Warning (dev) at .../build-dir/_deps/googletest-src/googletest/CMakeLists.txt:47 (project):
29 Policy CMP0048 is not set: project() command manages VERSION variables.
38 ...
39 This warning is for project developers. Use -Wno-dev to suppress it.
34 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
35 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
35 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
🤔
But how to set CMake command-line option -Wno-dev through FetchContent?
That's not possible!
35 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
🤔
But how to set CMake command-line option -Wno-dev through FetchContent?
That's not possible!
OK, then let's set the CMake policy CMP0048:
15 ...
16 # Try to set policy CMP0048 for GoogleTest project.
17 cmake_policy( SET CMP0048 NEW )
18
19 # Fetch GoogleTest and make build scripts available.
20 FetchContent_MakeAvailable( googletest )
35 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
🤔
But how to set CMake command-line option -Wno-dev through FetchContent?
That's not possible!
OK, then let's set the CMake policy CMP0048:
15 ...
16 # Try to set policy CMP0048 for GoogleTest project.
17 cmake_policy( SET CMP0048 NEW )
18
19 # Fetch GoogleTest and make build scripts available.
🤬
20 FetchContent_MakeAvailable( googletest )
35 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
🤔
But how to set CMake command-line option -Wno-dev through FetchContent?
That's not possible!
OK, then let's set the CMake policy CMP0048:
15 ...
16 # Try to set policy CMP0048 for GoogleTest project.
17 cmake_policy( SET CMP0048 NEW )
18
19 # Fetch GoogleTest and make build scripts available.
🤬
20 FetchContent_MakeAvailable( googletest )
😵
Because cmake_minimum_required is called in GoogleTest's CMakeLists.txt setting
compatibility to CMake 2.6.2!
35 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
36 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
01 # .../GoogleTest-helper.cmake
02
03 cmake_policy( SET CMP0048 NEW )
36 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
01 # .../GoogleTest-helper.cmake
02
03 cmake_policy( SET CMP0048 NEW )
36 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
36 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
01 # .../GoogleTest-helper.cmake
02
😎
03 cmake_policy( SET CMP0048 NEW )
That's working!
36 / 50
Q
37 / 50
Q
38 / 50
Q
38 / 50
Q
01 # Load script for each CMakeLists.txt 01 # Load script for each CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <path-to-script>
03 set( CMAKE_PROJECT_INCLUDE <path-to-script>
38 / 50
Q
01 # Load script for each CMakeLists.txt 01 # Load script for each CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <path-to-script> 03 set( CMAKE_PROJECT_INCLUDE <path-to-script>
38 / 50
Q
01 # Load script for each CMakeLists.txt 01 # Load script for each CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <path-to-script> 03 set( CMAKE_PROJECT_INCLUDE <path-to-script>
38 / 50
Q
01 # Load script for each CMakeLists.txt 01 # Load script for each CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <path-to-script> 03 set( CMAKE_PROJECT_INCLUDE <path-to-script>
38 / 50
Q
01 # Load script for each CMakeLists.txt 01 # Load script for each CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <path-to-script> 03 set( CMAKE_PROJECT_INCLUDE <path-to-script>
01 # Load script for a specific CMakeLists.txt 01 # Load script for a specific CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 # (but after CMAKE_PROJECT_INCLUDE_BEFORE). 03 # (but after CMAKE_PROJECT_INCLUDE).
04 set( CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE <path-to-script> 04 set( CMAKE_PROJECT_<project-name>_INCLUDE <path-to-script>
01 # Load script for each CMakeLists.txt 01 # Load script for each CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <path-to-script> 03 set( CMAKE_PROJECT_INCLUDE <path-to-script>
01 # Load script for a specific CMakeLists.txt 01 # Load script for a specific CMakeLists.txt
02 # directly before calling `project` command 02 # directly after calling `project` command
03 # (but after CMAKE_PROJECT_INCLUDE_BEFORE). 03 # (but after CMAKE_PROJECT_INCLUDE).
04 set( CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE <path-to-script> 04 set( CMAKE_PROJECT_<project-name>_INCLUDE <path-to-script>
39 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
01 # .../GoogleTest-helper.cmake
02
😎
03 cmake_policy( SET CMP0048 NEW )
That's working!
40 / 50
P
GOOGLETEST
Let's try to remove that annoying warning.
01 Policy CMP0048 is not set: project() command manages VERSION variables.
11 ...
12 This warning is for project developers. Use -Wno-dev to suppress it.
01 # .../GoogleTest-helper.cmake
02
That's working!
40 / 50
P
GOOGLETEST
Luckily, for policy problems there exists another solution:
Set a default-value of a policy, which will be used if it is unset.
41 / 50
P
GOOGLETEST
Luckily, for policy problems there exists another solution:
Set a default-value of a policy, which will be used if it is unset.
by setting: CMAKE_POLICY_DEFAULT_CMP<NNNN>
41 / 50
P
GOOGLETEST
Luckily, for policy problems there exists another solution:
Set a default-value of a policy, which will be used if it is unset.
by setting: CMAKE_POLICY_DEFAULT_CMP<NNNN>
15 ...
16 # Set default value for policy CMP0048 which will be used by
17 # GoogleTest's CMakeLists.txt scripts.
18 set( CMAKE_POLICY_DEFAULT_CMP0048 NEW )
19
20 # Fetch GoogleTest and make build scripts available.
🤓
21 FetchContent_MakeAvailable( googletest )
41 / 50
M
GOOGLETEST
By the way:
Beware of scripts loaded via CMAKE_PROJECT_INCLUDE[_BEFORE] when building external
libraries.
42 / 50
M
GOOGLETEST
By the way:
Beware of scripts loaded via CMAKE_PROJECT_INCLUDE[_BEFORE] when building external
libraries.
01 CMake Error at .../common-project-include-in:3 (include):
02 include could not find load file:
03
04 .../project-meta-info.in
42 / 50
M
GOOGLETEST
By the way:
Beware of scripts loaded via CMAKE_PROJECT_INCLUDE[_BEFORE] when building external
libraries.
01 CMake Error at .../common-project-include-in:3 (include):
02 include could not find load file:
03
04 .../project-meta-info.in
42 / 50
source: https://uip.me/wp-content/uploads/2013/03/one-more-thing.jpg
43 / 50
M
M GOOGLETEST
GoogleTest targets do
not use namespace syntax and do
not set usage-requirements.
44 / 50
M
M GOOGLETEST
GoogleTest targets do
not use namespace syntax and do
not set usage-requirements.
29 ...
30
31 # Create alias for targets.
32 if (NOT TARGET GTest::gtest)
33 add_library( GTest::gtest ALIAS gtest )
34 endif ()
35 if (NOT TARGET GTest::main)
36 add_library( GTest::main ALIAS gtest_main )
37 endif ()
38 if (NOT TARGET GMock::gmock)
39 target_link_libraries( gmock INTERFACE GTest::gtest )
40 add_library( GMock::gmock ALIAS gmock )
41 endif ()
42 if (NOT TARGET GMock::main)
43 target_link_libraries( gmock_main INTERFACE GTest::gtest )
44 add_library( GMock::main ALIAS gmock_main )
45 endif ()
44 / 50
P
GOOGLETEST
01 CMake Error at CMakeLists.txt:35 (target_link_libraries):
GoogleTest targets do 02
03
The plain signature for target_link_libraries has already been used with
the target "gmock". All uses of target_link_libraries with a target must
08 * .../_deps/googletest-src/googletest/cmake/internal_utils.cmake:159 (targe
29 ...
09
30
10 CMake Error at CMakeLists.txt:40 (target_link_libraries):
31 # Create alias for targets.
11 The plain signature for target_link_libraries has already been used with
32 if (NOT TARGET GTest::gtest)
12 the target "gmock_main". All uses of target_link_libraries with a target
33 add_library( GTest::gtest ALIAS gtest )
13 must be either all-keyword or all-plain.
34 endif ()
14
35 if (NOT TARGET GTest::main)
15 The uses of the plain signature are here:
36 add_library( GTest::main ALIAS gtest_main )
16
37 endif ()
17 * .../_deps/googletest-src/googletest/cmake/internal_utils.cmake:159 (targe
38 if (NOT TARGET GMock::gmock)
39 target_link_libraries( gmock INTERFACE GTest::gtest )
40 add_library( GMock::gmock ALIAS gmock )
41 endif ()
42 if (NOT TARGET GMock::main)
43 target_link_libraries( gmock_main INTERFACE GTest::gtest )
44 add_library( GMock::main ALIAS gmock_main )
45 endif ()
45 / 50
P
GOOGLETEST
GoogleTest targets do
not use namespace syntax and do
not set usage-requirements.
29 ...
30
31 # Create alias for targets.
32 if (NOT TARGET GTest::gtest)
33 add_library( GTest::gtest ALIAS gtest )
34 endif ()
35 if (NOT TARGET GTest::main)
36 add_library( GTest::main ALIAS gtest_main )
37 endif ()
38 if (NOT TARGET GMock::gmock)
39 target_link_libraries( gmock GTest::gtest ) # Note: Cannot use INTERFACE here!
40 add_library( GMock::gmock ALIAS gmock )
41 endif ()
42 if (NOT TARGET GMock::main)
43 target_link_libraries( gmock_main GTest::gtest ) # Note: Cannot use INTERFACE here!
44 add_library( GMock::main ALIAS gmock_main )
45 endif ()
45 / 50
W
?
46 / 50
T
Of course, use Modern CMake!
47 / 50
T
Of course, use Modern CMake!
Use newest CMake version if possible. (Not older than CMake 3.15.)
47 / 50
T
Of course, use Modern CMake!
Use newest CMake version if possible. (Not older than CMake 3.15.)
Use find_package in CONFIG mode to search for pre-built external dependencies.
47 / 50
T
Of course, use Modern CMake!
Use newest CMake version if possible. (Not older than CMake 3.15.)
Use find_package in CONFIG mode to search for pre-built external dependencies.
Use FetchContent to configure/build external dependencies with your project.
47 / 50
T
Of course, use Modern CMake!
Use newest CMake version if possible. (Not older than CMake 3.15.)
Use find_package in CONFIG mode to search for pre-built external dependencies.
Use FetchContent to configure/build external dependencies with your project.
Reduce boiler-plate and set local modifications by using
CMAKE_PROJECT_INCLUDE[_BEFORE] and
CMAKE_PROJECT_<project-name>_INCLUDE[_BEFORE].
Beware of interaction with FetchContent.
47 / 50
T
Of course, use Modern CMake!
Use newest CMake version if possible. (Not older than CMake 3.15.)
Use find_package in CONFIG mode to search for pre-built external dependencies.
Use FetchContent to configure/build external dependencies with your project.
Reduce boiler-plate and set local modifications by using
CMAKE_PROJECT_INCLUDE[_BEFORE] and
CMAKE_PROJECT_<project-name>_INCLUDE[_BEFORE].
Beware of interaction with FetchContent.
Use find_package( Boost ... ) always with components!
47 / 50
source: https://miro.medium.com/max/1920/1*snPNMiveURJSAew7hm5-8A.jpeg
48 / 50
R
CMake's Reference-Documentation
Read/Search at: https://cmake.org/cmake/help/latest/index.html
Craig Scott's "Professional CMake: A Practical Guide" e‑book
Buy it at: https://crascit.com/professional-cmake/
Craig Scott's "Deep CMake for Library Authors" talk
Watch it at: https://youtu.be/m0DwB4OvDXk
Deniz Bahadir's "More Modern CMake" talk
Watch it at: https://youtu.be/y7ndUhdQuU8
49 / 50
T !
Q ?
50 / 50