0% found this document useful (0 votes)
774 views163 pages

Oh No More Modern CMake

This document discusses the differences between traditional and modern CMake. With modern CMake, build and usage requirements are set on targets rather than globally or by directory. Each target carries its own build and usage requirements. Setting requirements is done using target-specific commands like target_include_directories instead of commands that set properties globally.

Uploaded by

Darth
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
774 views163 pages

Oh No More Modern CMake

This document discusses the differences between traditional and modern CMake. With modern CMake, build and usage requirements are set on targets rather than globally or by directory. Each target carries its own build and usage requirements. Setting requirements is done using target-specific commands like target_include_directories instead of commands that set properties globally.

Uploaded by

Darth
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 163

Deniz Bahadir  

✉ 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

Might have some positive implications in


08 headers/B.hpp
09 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers/A.hpp

the future, too.


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

Might have some positive implications in


08 headers/B.hpp
09 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers/A.hpp

the future, too.


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.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

Might have some positive implications in


08 headers/B.hpp
09 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers/A.hpp

the future, too.


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.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

Might have some positive implications in


08 headers/B.hpp
09 PUBLIC headers/A.hpp

the future, too.


10 INTERFACE headers/C.hpp
11 )

Simplifications/Fixes with CMake 3.13 01 # ./subdir/CMakeLists.txt

target_sources now correctly interprets


02
03 # Add further sources to target.

relative paths as relative to current


04 target_sources( MyTarget
05 PRIVATE extra_src/D.cpp
06 INTERFACE extra_headers/D.hpp
CMAKE_CURRENT_SOURCE_DIR 07 )

Relative paths will be converted to


absolute paths.
10 / 50
OBJECT

11 / 50
OBJECT

OBJECT libraries are like any other CMake targets.

11 / 50
OBJECT

OBJECT libraries are like any other CMake targets...


except when they are not.
 

11 / 50
OBJECT

OBJECT libraries are like any other CMake targets...


except when they are not.
 
01 add_library( obj OBJECT ) OBJECT library obj carries
usage-requirements
02 target_sources( obj
03 PRIVATE src/source1.cpp

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

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( 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 ) 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 lib )   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
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

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( 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 ) 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 lib )   16 target_link_libraries( exe PRIVATE lib )   16 target_link_libraries( exe PRIVATE lib )  

usage-requirements are propagated as always:


obj   ➡   lib   ➡   exe obj   ( ➡   lib )   ➡   exe obj   ➡   lib   ➡   exe

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 )   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( 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 ) 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 lib )   16 target_link_libraries( exe PRIVATE lib )   16 target_link_libraries( exe PRIVATE lib )  

usage-requirements are propagated as always:


obj   ➡   lib   ➡   exe obj   ( ➡   lib )   ➡   exe obj   ➡   lib   ➡   exe
object files are propagated differently:
obj   ➡   lib   ➡   exe obj   ➡   lib   ➡   exe obj   ➡   lib   ➡   exe

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 )  

usage-requirements are propagated as always:


obj   ➡   obj2   ➡   exe obj   ( ➡   obj2 )   ➡   exe obj   ➡   obj2   ➡   exe

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 )  

usage-requirements are propagated as always:


obj   ➡   obj2   ➡   exe obj   ( ➡   obj2 )   ➡   exe obj   ➡   obj2   ➡   exe
object files are never propagated to/through other OBJECT libraries
obj   ➡   obj2   ➡  exe obj   ➡   obj2   ➡  exe obj   ➡   obj2   ➡   exe

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 )  

usage-requirements are propagated as always:


lib   ➡   obj   ➡   exe lib   ( ➡   obj )   ➡   exe lib   ➡   obj   ➡   exe

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 )  

usage-requirements are propagated as always:


lib   ➡   obj   ➡   exe lib   ( ➡   obj )   ➡   exe lib   ➡   obj   ➡   exe
link-dependency to lib are propagated differently:
lib   ➡   obj   ➡   exe lib   ( ➡   obj )   ➡   exe lib   ( ➡   obj )   ➡   exe

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 )  

usage-requirements are propagated as always:


lib   ➡   obj   ➡   exe lib   ( ➡   obj )   ➡   exe lib   ➡   obj   ➡   exe
link-dependency to lib are propagated differently:
lib   ➡   obj   ➡   exe lib   ( ➡   obj )   ➡   exe lib   ( ➡   obj )   ➡   exe
link-dependency propagation modified/fixed in CMake 3.14:
lib   ( ➡   obj )   ➡   exe lib   ( ➡   obj )   ➡   exe lib   ( ➡   obj )   ➡   exe

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

OK, not really different...

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 )  

2. Make this CMakeLists.txt file a new project.


04
05
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION 1.2.3
10 DESCRIPTION "Description of project"
11 HOMEPAGE_URL "https://www.example.com"
12 LANGUAGES C CXX CUDA )

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 )  

2. Make this CMakeLists.txt file a new project.


04
05
07 # 06   a project for the current CMakeLists.txt.
Define
08 project( MyProject
09 VERSION 1.2.3
10 DESCRIPTION "Description of project"
11 HOMEPAGE_URL "https://www.example.com"
12 LANGUAGES C CXX CUDA )

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 )  

2. Make this CMakeLists.txt file a new project.


04
05
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION 1.2.3
10 DESCRIPTION "Description of project"
11 HOMEPAGE_URL "https://www.example.com"
12 LANGUAGES C CXX CUDA )

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 )  

2. Make this CMakeLists.txt file a new project.


04
05
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION 1.2.3
10 DESCRIPTION "Description of project"
11 HOMEPAGE_URL "https://www.example.com"
12 LANGUAGES C CXX CUDA )

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 )  

2. Make this CMakeLists.txt file a new project.


04
05
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION 1.2.3
10 DESCRIPTION "Description of project"
11 HOMEPAGE_URL "https://www.example.com"
12 LANGUAGES C CXX CUDA )

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 )  

2. Make this CMakeLists.txt file a new project.


04
05
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION 1.2.3
10 DESCRIPTION "Description of project"
11 HOMEPAGE_URL "https://www.example.com"
12 LANGUAGES C CXX CUDA )

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

2. Include a (generated) file with project settings.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 include( "${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in" )  
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

20 / 50
B CMAKELISTS.TXT

include
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a (generated) file with project settings.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project. 05


04  
include( "${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in"
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

20 / 50
B CMAKELISTS.TXT

include
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a (generated) file with project settings.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 include( "${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in" )  
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

Loads variables from a file that shall be used in 01


02
# project-meta-info.in

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

2. Include a (generated) file with project settings.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 include( "${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in" )  
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

Loads variables from a file that shall be used in 01


02
# project-meta-info.in

project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )

In this example: located in the same 05


06
# The description of this project.
set( project_description "Description of root-project" )  

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

2. Include a (generated) file with project settings.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 include( "${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in" )  
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

Loads variables from a file that shall be used in 01


02
# project-meta-info.in

project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )

In this example: located in the same 05


06
# The description of this project.
set( project_description "Description of root-project" )  

directory as CMakeLists.txt 07
08
# The homepage of this project.
set( project_homepage "https://www.example.com" )

Each CMakeLists.txt should load its own file.

20 / 50
B CMAKELISTS.TXT

include
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a (generated) file with project settings.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 include( "${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in" )  
06  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

Loads variables from a file that shall be used in 01


02
# project-meta-info.in

project command.
03 # The version number of this project.
04 set( project_version 1.2.3 )

In this example: located in the same 05


06
# The description of this project.
set( project_description "Description of root-project" )  

directory as CMakeLists.txt 07
08
# The homepage of this project.
set( project_homepage "https://www.example.com" )

Each CMakeLists.txt should load its own file.


However, that is tedious, hard to remember
and too much boiler-plate. 20 / 50
O CMAKELISTS.TXT

CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a common file for all projects.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06 "${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyRootProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

21 / 50
O CMAKELISTS.TXT

CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a common file for all projects.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06 "${CMAKE_CURRENT_LIST_DIR}/common-project-include.in"
07 # Define a project for the current CMakeLists.txt.  
08 project( MyRootProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

21 / 50
O CMAKELISTS.TXT

CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a common file for all projects.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06 "${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyRootProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

The referenced file is automatically included 01 # common-project-info.in


02

directly before each project command 03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )

21 / 50
O CMAKELISTS.TXT

CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a common file for all projects.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06 "${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyRootProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

The referenced file is automatically included 01 # common-project-info.in


02

directly before each project command 03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )

and should include each project's meta-info 01


02
# project-meta-info.in

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" )

21 / 50
O CMAKELISTS.TXT

CMAKE_PROJECT_INCLUDE_BEFORE
1. Define the required CMake-version. 01 # CMakeLists.txt

2. Include a common file for all projects.


02
03 cmake_minimum_required( VERSION 3.15...3.17 )  

3. Make this CMakeLists.txt file a new project.


04  
05 set( CMAKE_PROJECT_INCLUDE_BEFORE
06 "${CMAKE_CURRENT_LIST_DIR}/common-project-include.in" )  
07 # Define a project for the current CMakeLists.txt.  
08 project( MyRootProject
09 VERSION ${project_version}
10 DESCRIPTION ${project_description}
11 HOMEPAGE_URL ${project_homepage}
12 LANGUAGES C CXX CUDA )

The referenced file is automatically included 01 # common-project-info.in


02

directly before each project command 03 include( "${CMAKE_CURRENT_SOURCE_DIR}/project-meta-info.in" )

and should include each project's meta-info, 01


02
# project-meta-info.in

which is relative to the current CMakeLists.txt 03


04
# The version number of this project.
set( project_version 1.2.3 )

file. 05
06
# The description of this project.
set( project_description "Description of root-project" )  

Use CMAKE_CURRENT_SOURCE_DIR instead of 07


08
# The homepage of this project.
set( project_homepage "https://www.example.com" )

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 '

From a subdirectory's CMakeLists.txt file: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.69.0 )

Use find_package to locate Boost! 04


05 # Settings for finding correct Boost libraries.  
06 set( Boost_USE_STATIC_LIBS FALSE )
07 set( Boost_USE_MULTITHREADED TRUE )

  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 '

From a subdirectory's CMakeLists.txt file: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.69.0 )

Use find_package to locate Boost! 04


05 # Settings for finding correct Boost libraries.  

If found, promote IMPORTED targets to global scope. 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

  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 '

From a subdirectory's CMakeLists.txt file: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.69.0 )

Use find_package to locate Boost! 04


05 # Settings for finding correct Boost libraries.  

If found, promote IMPORTED targets to global scope. 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

  08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

Uses find_package's Module mode and the 10


11
set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )

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 '

From a subdirectory's CMakeLists.txt file: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.69.0 )

Use find_package to locate Boost! 04


05 # Settings for finding correct Boost libraries.  

If found, promote IMPORTED targets to global scope. 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

  08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

Uses find_package's Module mode and the 10


11
set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )

FindBoost.cmake module that comes with CMake. 12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT

For Boost versions newer than FindBoost.cmake 14


15
MODULE
REQUIRED COMPONENTS program_options

version, the variable Boost_ADDITIONAL_VERSIONS has 16


17
graph )

to contain the additional version(s). 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 '

From a subdirectory's CMakeLists.txt file: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.69.0 )

Use find_package to locate Boost! 04


05 # Settings for finding correct Boost libraries.  

If found, promote IMPORTED targets to global scope. 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

  08
09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

Uses find_package's Module mode and the 10


11
set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )

FindBoost.cmake module that comes with CMake. 12 # Search for Boost libraries.
13 find_package( Boost ${BOOST_VERSION} EXACT

For Boost versions newer than FindBoost.cmake 14


15
MODULE
REQUIRED COMPONENTS program_options

version, the variable Boost_ADDITIONAL_VERSIONS has 16


17
graph )

to contain the additional version(s). 18


19 # Make found targets globally available.

This is error-prone! 20
21
if ( Boost_FOUND )
set_target_properties( Boost::boost

Dependencies might be wrong. 22


23
Boost::program_options
Boost::graph

IMPORTED targets for new Boost libraries will 24


25 endif ()
PROPERTIES IMPORTED_GLOBAL TRUE )

probably not be created.


24 / 50
F BOOST
N B ≥ . .

Starting with version 1.70.0 Boost provides its own 01


02
# ./external/boost/CMakeLists.txt

BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.  

Use find_package in Config mode to locate Boost! 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )
08 set( Boost_USE_STATIC_RUNTIME FALSE )
09 set( Boost_COMPILER "-gcc8" )
10 set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )
11
12 # Search for Boost libraries.
13 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::boost
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()

25 / 50
F BOOST
N B ≥ . .

Starting with version 1.70.0 Boost provides its own 01


02
# ./external/boost/CMakeLists.txt

BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.  

Use find_package in Config mode to locate Boost! 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

Searches for the BoostConfig.cmake script and creates 08


09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

IMPORTED targets from it. 10 set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )


11
12 # Search for Boost libraries.
13 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::boost
22 Boost::program_options
23 Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()

25 / 50
F BOOST
N B ≥ . .

Starting with version 1.70.0 Boost provides its own 01


02
# ./external/boost/CMakeLists.txt

BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.  

Use find_package in Config mode to locate Boost! 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

Searches for the BoostConfig.cmake script and creates 08


09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

IMPORTED targets from it. 10 set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )


11

Target Boost::boost was renamed to Boost::headers 12


13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT

(but an alias is still available). 14


15
CONFIG
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 ()

25 / 50
F BOOST
N B ≥ . .

Starting with version 1.70.0 Boost provides its own 01


02
# ./external/boost/CMakeLists.txt

BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.  

Use find_package in Config mode to locate Boost! 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

Searches for the BoostConfig.cmake script and creates 08


09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

IMPORTED targets from it. 10


11

Target Boost::boost was renamed to Boost::headers 12


13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT

(but an alias is still available). 14


15
CONFIG
REQUIRED COMPONENTS program_options

The variable Boost_ADDITIONAL_VERSIONS is no longer 16


17
graph )

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 ≥ . .

Starting with version 1.70.0 Boost provides its own 01


02
# ./external/boost/CMakeLists.txt

BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.  

Use find_package in Config mode to locate Boost! 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

Searches for the BoostConfig.cmake script and creates 08


09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

IMPORTED targets from it. 10


11

Target Boost::boost was renamed to Boost::headers 12


13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT

(but an alias is still available). 14


15
CONFIG
REQUIRED COMPONENTS program_options

The variable Boost_ADDITIONAL_VERSIONS is no longer 16


17
graph )

needed. 18
19 # Make found targets globally available.

⇒ Save with all versions of CMake! 20


21
if ( Boost_FOUND )
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 ≥ . .

Starting with version 1.70.0 Boost provides its own 01


02
# ./external/boost/CMakeLists.txt

BoostConfig.cmake file:
03 set( BOOST_VERSION 1.70.0 )
04
05 # Settings for finding correct Boost libraries.  

Use find_package in Config mode to locate Boost! 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

Searches for the BoostConfig.cmake script and creates 08


09
set( Boost_USE_STATIC_RUNTIME
set( Boost_COMPILER
FALSE )
"-gcc8" )

IMPORTED targets from it. 10


11

Target Boost::boost was renamed to Boost::headers 12


13
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT

(but an alias is still available). 14


15
CONFIG
REQUIRED COMPONENTS program_options

The variable Boost_ADDITIONAL_VERSIONS is no longer 16


17
graph )

needed. 18
19 # Make found targets globally available.

⇒ Save with all versions of CMake! 20


21
if ( Boost_FOUND )
set_target_properties( Boost::headers

...with all versions ≥ 2.8.8, to be precise. 22


23
Boost::program_options
Boost::graph
24 PROPERTIES IMPORTED_GLOBAL TRUE )
25 endif ()

25 / 50
F BOOST
N B ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.70.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  
06 set( Boost_USE_STATIC_LIBS FALSE )
07 set( Boost_USE_MULTITHREADED TRUE )
08 set( Boost_USE_STATIC_RUNTIME FALSE )
09 set( Boost_COMPILER "-gcc8" )
10
11

  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 ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.70.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  

Omitting any component only looks for header-only 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

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 ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.70.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  

Omitting any component only looks for header-only 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

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 ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.70.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  

Omitting any component only looks for header-only 06


07
set( Boost_USE_STATIC_LIBS
set( Boost_USE_MULTITHREADED
FALSE )
TRUE )

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 ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.73.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  
06 set( Boost_USE_STATIC_LIBS FALSE )
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 program_options
17 graph )
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 ()

27 / 50
F BOOST
N B ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.73.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  
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 program_options
17 graph )
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 ()

27 / 50
F BOOST
N B ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.73.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  

😧
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 ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.73.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  

😧
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

Boost 1.73.0 (and newer) to the rescue: 15


16
REQUIRED COMPONENTS ALL )

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 ≥ . .

Common for all Boost versions: 01


02
# ./external/boost/CMakeLists.txt

03 set( BOOST_VERSION 1.73.0 )

You must explicitly specify the components! 04


05 # Settings for finding correct Boost libraries.  

😧
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

Boost 1.73.0 (and newer) to the rescue: 15


16
REQUIRED ALL )

ALL component 17
18 # Make found targets globally available.

If REQUIRED keyword is given, the COMPONENTS keyword 19


20
if ( Boost_FOUND )
set_target_properties( ${Boost_ALL_TARGETS}

can be omitted. 21
22 endif ()
PROPERTIES IMPORTED_GLOBAL TRUE )

⇒ looks quite nice with ALL component

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

FetchContent only works with dependencies that


themselves use CMake to build!

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

Bundled with CMake since version 3.11.


02
03 ...
04  
05 # Load FetchContent module.
06 include( FetchContent )
07  

31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt

Bundled with CMake since version 3.11.


02
03 ...
04  
2. Need to tell FetchContent 05 # Load FetchContent module.
06 include( FetchContent )
what code to fetch for building 08 # 07  
Declare GoogleTest as the contentto fetch.
and where to find it. 09 FetchContent_Declare(
10 googletest
⇒ FetchContent_Declare 11 GIT_REPOSITORY https://github.com/google/googletest.g
12 GIT_TAG release-1.8.0
13 )

31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt

Bundled with CMake since version 3.11.


02
03 ...
04  
2. Need to tell FetchContent 05 # Load FetchContent module.
06 include( FetchContent )
what code to fetch for building 07  
08 # Declare GoogleTest as the content to fetch.
and where to find it. 09 FetchContent_Declare(
10 googletest
⇒ FetchContent_Declare 11 GIT_REPOSITORY https://github.com/google/googletest.git
12 GIT_TAG release-1.8.0
13 )
14  

31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt

Bundled with CMake since version 3.11.


02
03 ...
04  
2. Need to tell FetchContent 05 # Load FetchContent module.
06 include( FetchContent )
what code to fetch for building 07  
08 # Declare GoogleTest as the content to fetch.
and where to find it. 09 FetchContent_Declare(
10 googletest
⇒ FetchContent_Declare 11 GIT_REPOSITORY https://github.com/google/googletest.git
12 GIT_TAG release-1.8.0
3. Fetch the content 13 )
14  
making its CMakeLists.txt script available 15 # Fetch GoogleTest and make build scripts available.
16 FetchContent_MakeAvailable( googletest )
(via add_subdirectory).
⇒ FetchContent_MakeAvailable

31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt

Bundled with CMake since version 3.11.


02
03 ...
04  
2. Need to tell FetchContent 05 # Load FetchContent module.
06 include( FetchContent )
what code to fetch for building 07  
08 # Declare GoogleTest as the content to fetch.
and where to find it. 09 FetchContent_Declare(
10 googletest
⇒ FetchContent_Declare 11 GIT_REPOSITORY https://github.com/google/googletest.git
12 GIT_TAG release-1.8.0
3. Fetch the content 13 )
14  
making its CMakeLists.txt script available 15 # Fetch GoogleTest and make build scripts available.
16 FetchContent_MakeAvailable( googletest )
(via add_subdirectory).
⇒ FetchContent_MakeAvailable
General case
which does not always work without
modifications!

31 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt

Bundled with CMake since version 3.11.


02
03 ...
04  
2. Need to tell FetchContent 05 # Load FetchContent module.
06 include( FetchContent )
what code to fetch for building 07
08 # Declare GoogleTest as the content to fetch.
and where to find it. 09 FetchContent_Declare(
10 googletest
⇒ FetchContent_Declare 11 GIT_REPOSITORY https://github.com/google/googletest.git
12 GIT_TAG release-1.8.0
3. Fetch the content 13 )
14  
making its CMakeLists.txt script available 15 # Fetch GoogleTest and make build scripts available.
16 if (NOT googletest_POPULATED)
(via add_subdirectory). 17 # Fetch the content using previously declared details.
18 FetchContent_Populate( googletest )
⇒ FetchContent_MakeAvailable 19
20 # Custom policies, variables and modifications go here.
General case 21 # ...
22
which does not always work without 23 # Bring the populated content into the build.
24 add_subdirectory( ${googletest_SOURCE_DIR}
modifications! 25 ${googletest_BINARY_DIR} )
26 endif()

32 / 50
B FETCHCONTENT
D GOOGLETEST
1. Load FetchContent module 01 # ./myproject/CMakeLists.txt

Bundled with CMake since version 3.11.


02
03 ...
04  
2. Need to tell FetchContent 05 # Load FetchContent module.
06 include( FetchContent )
what code to fetch for building 07
08 # Declare GoogleTest as the content to fetch.
and where to find it. 09 FetchContent_Declare(
10 googletest
⇒ FetchContent_Declare 11 GIT_REPOSITORY https://github.com/google/googletest.git
12 GIT_TAG release-1.8.0
3. Fetch the content 15 # 13 )
Fetch GoogleTest and make build scripts available.
14  
making its CMakeLists.txt script available 16 if (NOT googletest_POPULATED)
17 # Fetch the content using previously declared details
(via add_subdirectory). 18 FetchContent_Populate( googletest )
⇒ FetchContent_MakeAvailable 19
20 # Custom policies, variables and modifications go her
General case 21 # ...
which does not always work without 22
23 # Bring the populated content into the build.
modifications! 24 add_subdirectory( ${googletest_SOURCE_DIR}
25 ${googletest_BINARY_DIR} )
26 endif() 32 / 50
P
GOOGLETEST

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.

But how to set CMake command-line option -Wno-dev through FetchContent?

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 )

That's not working either!

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 )

That's not working either!

😵
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.

Do I really have to patch GoogleTest's CMakeLists.txt file?

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.

Do I really have to patch GoogleTest's CMakeLists.txt file?


No, use CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE!
15 ...
16 # Require GoogleTest's top CMakeLists.txt to include a script
17 # before calling the project command which works around the problem.
18 set( CMAKE_PROJECT_googletest-distribution_INCLUDE_BEFORE
19 "${CMAKE_CURRENT_LIST_DIR}/GoogleTest-helper.cmake" )
20
21 # Fetch GoogleTest and make build scripts available.
22 FetchContent_MakeAvailable( googletest )

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.

Do I really have to patch GoogleTest's CMakeLists.txt file?


No, use CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE!
15 ...
16 # Require GoogleTest's top CMakeLists.txt to include a script
17 # before calling the project command which works around the problem.
18 set( CMAKE_PROJECT_googletest-distribution_INCLUDE_BEFORE
19 "${CMAKE_CURRENT_LIST_DIR}/GoogleTest-helper.cmake" )
20
21 # Fetch GoogleTest and make build scripts available.
22 FetchContent_MakeAvailable( googletest )

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.

Do I really have to patch GoogleTest's CMakeLists.txt file?


No, use CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE!
15 ...
16 # Require GoogleTest's top CMakeLists.txt to include a script
17 # before calling the project command which works around the problem.
18 set( CMAKE_PROJECT_googletest-distribution_INCLUDE_BEFORE
19 "${CMAKE_CURRENT_LIST_DIR}/GoogleTest-helper.cmake" )
20
21 # Fetch GoogleTest and make build scripts available.
22 FetchContent_MakeAvailable( googletest )
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.

Do I really have to patch GoogleTest's CMakeLists.txt file?


No, use CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE!
15 ...
16 # Require GoogleTest's top CMakeLists.txt to include a script
17 # before calling the project command which works around the problem.
18 set( CMAKE_PROJECT_googletest-distribution_INCLUDE_BEFORE
19 "${CMAKE_CURRENT_LIST_DIR}/GoogleTest-helper.cmake" )
20
21 # Fetch GoogleTest and make build scripts available.
22 FetchContent_MakeAvailable( googletest )

01 # .../GoogleTest-helper.cmake
02

😎
03 cmake_policy( SET CMP0048 NEW )

That's working!
36 / 50
Q

37 / 50
Q

38 / 50
Q

01 # Load script for each CMakeLists.txt


02 # directly before calling `project` command
03 set( CMAKE_PROJECT_INCLUDE_BEFORE <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>

introduced in CMake 3.15 introduced in CMake 3.15


 

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>

introduced in CMake 3.15 introduced in CMake 3.15


 

01 # Load script for a specific CMakeLists.txt


02 # directly before calling `project` command
03 # (but after CMAKE_PROJECT_INCLUDE_BEFORE).
04 set( CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE <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>

introduced in CMake 3.15 introduced in CMake 3.15


 

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>

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>

introduced in CMake 3.15 introduced in CMake 3.15


 

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>

will be introduced in CMake 3.17 introduced in CMake 2.8.9


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>

introduced in CMake 3.15 introduced in CMake 3.15


 

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>

will be introduced in CMake 3.17 introduced in CMake 2.8.9


38 / 50
R
P GOOGLETEST

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.

Do I really have to patch GoogleTest's CMakeLists.txt file?


No, use CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE!
15 ...
16 # Require GoogleTest's top CMakeLists.txt to include a script
17 # before calling the project command which works around the problem.
18 set( CMAKE_PROJECT_googletest-distribution_INCLUDE_BEFORE
19 "${CMAKE_CURRENT_LIST_DIR}/GoogleTest-helper.cmake" )
20
21 # Fetch GoogleTest and make build scripts available.
22 FetchContent_MakeAvailable( googletest )

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.

Do I really have to patch GoogleTest's CMakeLists.txt file?


No, use CMAKE_PROJECT_<project-name>_INCLUDE_BEFORE!
15 ...
16 # Require GoogleTest's top CMakeLists.txt to include a script
17 # before calling the project command which works around the problem.
18 set( CMAKE_PROJECT_googletest-distribution_INCLUDE_BEFORE
19 "${CMAKE_CURRENT_LIST_DIR}/GoogleTest-helper.cmake" )
20
21 # Fetch GoogleTest and make build scripts available.
22 FetchContent_MakeAvailable( googletest )

01 # .../GoogleTest-helper.cmake
02

😎 That's only working with CMake 3.17 and newer! 😕


03 cmake_policy( SET CMP0048 NEW )

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 )

That is working with all CMake versions!

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

Need to unset variable temporarily.


19 ...
20 # Unset CMAKE_PROJECT_INCLUDE_BEFORE temporarily.
21 set( backup_CMAKE_PROJECT_INCLUDE_BEFORE ${CMAKE_PROJECT_INCLUDE_BEFORE} )
22 unset( CMAKE_PROJECT_INCLUDE_BEFORE )
23
24 # Fetch GoogleTest and make build scripts available.
25 FetchContent_MakeAvailable( googletest )
26
27 # Restore CMAKE_PROJECT_INCLUDE_BEFORE again.
28 set( CMAKE_PROJECT_INCLUDE_BEFORE ${backup_CMAKE_PROJECT_INCLUDE_BEFORE} )
29 unset( backup_CMAKE_PROJECT_INCLUDE_BEFORE )

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

not use namespace syntax and do 04


05
be either all-keyword or all-plain.

not set usage-requirements. 06


07
The uses of the plain signature are here:

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

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy