Initial import

This commit is contained in:
Matteo Settenvini 2019-07-27 18:28:47 +02:00
commit 0a5348b401
31 changed files with 1907 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

62
CMakeLists.txt Normal file
View File

@ -0,0 +1,62 @@
project(presentation LANGUAGES NONE)
cmake_minimum_required(VERSION 3.5)
# ------------------------------------
set(jobname "cmake-workshop-20190729")
set(output "${jobname}.pdf")
set(mainsource "main.tex")
set(sources
${mainsource}
cmake-for-scripting.tex
cross-compilation-toolchains.tex
feature-platform-check.tex
outro.tex
preamble.tex
project-handling.tex
rpath-build-install-tree.tex
starting-from-today.tex
troubleshooting.tex
usage-of-targets.tex)
file(GLOB images "images/*")
list(APPEND sources ${images})
# ------------------------------------
find_program(XETEX NAMES xetex)
if(NOT XETEX)
message(FATAL_ERROR "Please install xetex")
endif()
find_program(RUBBER NAMES rubber)
if(NOT RUBBER)
message(FATAL_ERROR "Please install rubber")
endif()
find_program(PYGMENTS NAMES pygmentize)
if(NOT PYGMENTS)
message(FATAL_ERROR "Please install python3-pygments")
endif()
add_custom_command(OUTPUT ${output}
COMMAND ${RUBBER} --unsafe --pdf
--module xelatex
--module beamer
--module shell_escape
--into ${CMAKE_CURRENT_BINARY_DIR}
--jobname "${jobname}"
"${CMAKE_CURRENT_SOURCE_DIR}/${mainsource}"
MAIN_DEPENDENCY ${mainsource}
DEPENDS ${sources}
BYPRODUCTS ${jobname}.aux
${jobname}.nav
${jobname}.toc
${jobname}.log
${jobname}.out
${jobname}.snm
COMMENT "Generating pdf file for the presentation"
VERBATIM)
add_custom_target(presentation ALL DEPENDS ${output})

215
cmake-for-scripting.tex Normal file
View File

@ -0,0 +1,215 @@
\begin{frame}
\frametitle{CMake as a language}
\begin{center}
\huge CMake as a language: variables, iterating, and functions
\end{center}
\end{frame}
% --------------------------------------------------------------------
\subsection{Variables}
\begin{frame}[containsverbatim]
\frametitle{Setting variables}
\begin{codebox}{CMake}{}
set(local_variable "a string")
set(local_list "item1" "item2" "item3")
set(another_local_list "item1;item2;item3")
set_property(GLOBAL PROPERTY
A_GLOBAL_PROPERTY "${local_variable}")
# Not overridden if already in cache:
set(CACHE_VARIABLE ${local_list}
CACHE BOOL "Variable description")
# Always override, for our internal use:
set(INTERNAL_CACHE_VARIABLE ${local_list}
CACHE INTERNAL "Variable description")
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Scoping of variables}
\begin{codebox}{CMake}{}
# in folder A
set(local_variable "A")
add_subdirectory("B")
message(STATUS ${local_variable}) # -- prints A
# in folder B
set(local_variable "B")
message(STATUS ${local_variable}) # -- prints B
\end{codebox}
\texttt{add\_subdirectory} introduces a new scope.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Scoping of variables -- propagating}
\begin{codebox}{CMake}{}
# in folder A
set(local_variable "A")
add_subdirectory("B")
message(STATUS ${local_variable}) # -- prints B
# in folder B
set(local_variable "B" PARENT_SCOPE)
message(STATUS ${local_variable}) # -- prints B
\end{codebox}
\texttt{add\_subdirectory} introduces a new scope.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Scoping of variables -- caching}
\begin{codebox}{CMake}{}
message(STATUS ${VARIABLE}) # 1st run: nothing, 2nd run: B
add_subdirectory("C")
# in folder C
set(VARIABLE "A")
message(STATUS ${VARIABLE}) # 1st run: A, 2nd run: A
set(VARIABLE "B" CACHE STRING "A looney var")
message(STATUS ${VARIABLE}) # 1st run: B, 2nd run: A
\end{codebox}
Note how, the second time, setting a variable in the cache
is effectively a no-op, since it is already present there.
\end{frame}
% --------------------------------------------------------------------
\subsection{Conditionals and iterating}
\begin{frame}[containsverbatim]
\frametitle{Conditionals}
\texttt{if} has a lot of comparison operators. Read the docs!
\vspace{.5em}
\begin{codebox}{CMake}{}
# for historical reasons, unquoted variable
# names are always expanded:
if(var1 STREQUAL var2)
# if true...
elseif("var1" STREQUAL "var2") # ... but not if quoted!
# (never enters here)
else()
# otherwise
endif()
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Iterating on lists}
\begin{codebox}{CMake}{}
set(a_list "a" "b" "c")
foreach(var IN LISTS a_list)
message(STATUS ${var}) # prints on separate lines: a, b, c
endforeach()
foreach(var IN ITEMS "one" "two" "three" ${a_list})
message(STATUS ${var}) # prints on separate lines:
# one, two, three, a, b, c
endforeach()
# Note that quoted lists do not expand twice here:
foreach(var IN ITEMS "${a_list}")
message(STATUS ${var}) # prints on ONE line a;b;c
endforeach()
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\subsection{Functions}
\begin{frame}[containsverbatim]
\frametitle{Defining functions}
\begin{codebox}{CMake}{}
function(f a b c)
# here you can use a, b, and c.
# ARGN is a magic list that contains all elements
# provided after the third ("c").
endfunction(f)
# Invocation:
f("${var1}" "${var2}" "${var3}" "${var4}")
# This could lead to unexpected results with empty vars:
f(${var1} ${var2} ${var3} ${var4})
\end{codebox}
{\footnotesize Macros are like functions, but do not create a new
scope. Plus assigning values to parameters is strange. Short
rule: do \emph{not} use macros unless you know what you are
doing.}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Returning values from functions}
There is no ``\texttt{return value}'' construct.
\vspace{.5em}
\begin{codebox}{CMake}{}
function(identity VAR a)
# We use VAR as the name of the return variable in the
# parent scope.
set("${VAR}" "${a}" PARENT_SCOPE)
endfunction(identity)
# Invocation:
set(a "value")
identity(a "${a}")
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\subsection{Invoking as a script}
\begin{frame}[containsverbatim]
\frametitle{Invoking a file as a script}
Why using CMake for scripting?
Well, it is more portable than bash across systems!
\vspace{.5em}
\begin{codebox}{Bash}{}
$ cmake -DVAR1="value1" ... -P script-name.cmake
\end{codebox}
\end{frame}
% --------------------------------------------------------------------

49
cmake_install.cmake Normal file
View File

@ -0,0 +1,49 @@
# Install script for directory: /home/matteo/cmake-presentation
# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
# Set the install configuration name.
if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
if(BUILD_TYPE)
string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
else()
set(CMAKE_INSTALL_CONFIG_NAME "")
endif()
message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
endif()
# Set the component getting installed.
if(NOT CMAKE_INSTALL_COMPONENT)
if(COMPONENT)
message(STATUS "Install component: \"${COMPONENT}\"")
set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
else()
set(CMAKE_INSTALL_COMPONENT)
endif()
endif()
# Install shared libraries without execute permission?
if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)
set(CMAKE_INSTALL_SO_NO_EXE "1")
endif()
# Is this installation the result of a crosscompile?
if(NOT DEFINED CMAKE_CROSSCOMPILING)
set(CMAKE_CROSSCOMPILING "FALSE")
endif()
if(CMAKE_INSTALL_COMPONENT)
set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt")
else()
set(CMAKE_INSTALL_MANIFEST "install_manifest.txt")
endif()
string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT
"${CMAKE_INSTALL_MANIFEST_FILES}")
file(WRITE "/home/matteo/cmake-presentation/${CMAKE_INSTALL_MANIFEST}"
"${CMAKE_INSTALL_MANIFEST_CONTENT}")

View File

@ -0,0 +1,104 @@
\subsection{Cross-Compilation, Toolchain files}
\begin{frame}
\frametitle{Cross-compilation}
\begin{center}
\huge Dealing with different platforms
\end{center}
\end{frame}
%--------------------------------------------------------------------------------------------------
\begin{frame}
\frametitle{Cross-Compilation, Concepts}
Building binaries for a platform other than the one on which the
compiler runs.
\vspace{1em}
\textbf {Host Platform} \\
{\info {Platform/System \textbf {ON} which the binaries are built, compiler(cross-compiler) runs.}}
\vspace{1em}
\textbf{Target Platform} \\
{\info {Platform \textbf {FOR} which the binaries are built.}}
\end{frame}
%--------------------------------------------------------------------------------------------------
\begin{frame}
\frametitle{Cross-Compilation, Concepts}
\textbf {Toolchain}\\
{\info {Set of tools and libraries to built binaries for a target platform, such as:}
\begin{itemize}
\item Binutils
\item Cross Compiler
\item C Library
\item Debugger
\end{itemize}
}
\end{frame}
%--------------------------------------------------------------------------------------------------
\begin{frame}
\frametitle{CMake \& Cross-Compilation}
CMake needs help to recognize Cross-Compilation, e.g.\\
\begin{itemize}
\item Target System Name
\item Cross Compiler Location
\item Library Search Paths
\item etc.
\end{itemize}
\end{frame}
%--------------------------------------------------------------------------------------------------
\begin{frame}
\frametitle{CMake \& Cross-Compilation}
\textbf {Toolchain Files} - CMake Script enclosing toolchain info.
E.g.:
\begin{itemize}
\item Target System Name -- {\code CMAKE\_SYSTEM\_NAME}
\item Cross-Compiler to be used -- {\code CMAKE\_C\_COMPILER}
\item Library and Package search root -- {\code {CMAKE\_FIND\_ROOT\_PATH}}
\item Default compiler and linker flags specific to the target platform
\end{itemize}
{\info {\code {CMAKE\_TOOLCHAIN\_FILE}} used to provide toolchain file location}
\end{frame}
%--------------------------------------------------------------------------------------------------
\begin{frame}
\frametitle{CMake \& Cross-Compilation}
System introspection is still possible while cross-compiling:
\begin{itemize}
\item {\code {try\_compile}} - works as expected
\item {\code {try\_run}} - limited functionality, run phase is usually skipped
\end{itemize}
\end{frame}
%--------------------------------------------------------------------------------------------------
\note{
What is cross-compilation
HOST, TARGET, compilers
Toolchain files
- meaning and content
Cross compilation with cmake
- CMAKE Variables
- Searching \& finding packages
- toolchain files
- system introspection (try-compile, try-run)
- HOST-TOOLS, why might be required
- Using Executables in the build created during the build
}

145
exercises/CMakeLists.txt Normal file
View File

@ -0,0 +1,145 @@
# cmake_minimum_required(VERSION 3.11)
cmake_minimum_required(VERSION 3.11)
## Declare a project named "cmake-exercise"
project(cmake-exercise VERSION 0.90.0)
if(CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Don't build in the source directory, pretty please.")
endif()
## Includes
include(GNUInstallDirs)
include(GenerateExportHeader)
include(CMakePackageConfigHelpers)
## Find necessary packages
find_package(OpenMP)
find_package(Threads REQUIRED)
## Artifacts to create
add_library(obj OBJECT)
add_library(static STATIC)
add_library(shared SHARED)
add_library(interface INTERFACE)
add_executable(tests)
## Generate other files
generate_export_header(shared
BASE_NAME DSO
EXPORT_FILE_NAME include/cmake-exercise/config.hh)
## Specify source files
target_sources(obj
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/cmake-exercise/a.hh>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cmake-exercise/a.hh>
PRIVATE src/a.cc)
target_sources(shared
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/cmake-exercise/b.hh>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cmake-exercise/b.hh>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include/cmake-exercise/config.hh>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cmake-exercise/config.hh>
PRIVATE src/b.cc
$<TARGET_PROPERTY:obj,INTERFACE_SOURCES>
$<TARGET_OBJECTS:obj>)
target_sources(interface
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/cmake-exercise/c.hh>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cmake-exercise/c.hh>)
target_sources(tests
PRIVATE test/test.cc)
## Add include folders
target_include_directories(interface
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_include_directories(obj
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_include_directories(shared
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
## Set target properties for visibility and PIC
set_property(TARGET obj PROPERTY POSITION_INDEPENDENT_CODE TRUE)
set_property(TARGET obj shared PROPERTY CXX_VISIBILITY_PRESET hidden)
set_property(TARGET obj shared PROPERTY VISIBILITY_INLINES_HIDDEN TRUE)
## Specify C++ version to use
target_compile_features(interface
INTERFACE cxx_std_11)
target_compile_features(obj
INTERFACE cxx_std_11
PRIVATE cxx_std_14)
## Link to other libraries, and inherit their settings
target_link_libraries(obj
PUBLIC Threads::Threads)
target_link_libraries(static
PRIVATE interface
PUBLIC obj)
target_link_libraries(shared
PRIVATE interface obj)
target_link_libraries(tests
PRIVATE static)
if(TARGET OpenMP::OpenMP_CXX)
target_compile_definitions(tests PRIVATE HAVE_OPENMP)
target_link_libraries(tests PRIVATE OpenMP::OpenMP_CXX)
endif()
## Install all needed files for packaging
install(FILES $<TARGET_PROPERTY:shared,INTERFACE_SOURCES>
$<TARGET_PROPERTY:interface,INTERFACE_SOURCES>
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
COMPONENT devel)
install(TARGETS shared
EXPORT cmake-exercise
DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS obj interface
EXPORT cmake-exercise
COMPONENT devel
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS tests
DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake-exercise/test
COMPONENT test)
## Add a test
enable_testing()
add_test(NAME not-really-a-test
COMMAND tests --ignored-param)
## Generate the export sets to be able to import this project
## in other projects via find_package (the config file is not complete though)
set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/cmake-exercise)
export(EXPORT cmake-exercise
NAMESPACE cmake-exercise::
FILE cmake-exercise-targets.cmake)
install(EXPORT cmake-exercise
NAMESPACE cmake-exercise::
DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
FILE cmake-exercise-targets.cmake
COMPONENT devel)
configure_package_config_file(cmake-exercise-config.cmake.in
cmake-exercise-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_CMAKEDIR})
write_basic_package_version_file(cmake-exercise-version.cmake
COMPATIBILITY SameMajorVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake-exercise-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmake-exercise-version.cmake
DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
COMPONENT devel)
## Trigger packaging
set(CPACK_PACKAGE_FILE_NAME package)
set(CPACK_GENERATOR TXZ)
set(CPACK_ARCHIVE_COMPONENT_INSTALL TRUE)
include(CPack)

6
exercises/README Normal file
View File

@ -0,0 +1,6 @@
This is a simple exercise to get familiar a bit with CMake.
See the deployment diagram in doc/ to know what is the final result
should look like.
Other than that, follow the comments in CMakeLists.txt

View File

@ -0,0 +1,3 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/cmake-exercise-targets.cmake)

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

View File

@ -0,0 +1,119 @@
@startuml
left to right direction
hide <<Layout>> stereotype
skinparam rectangle<<Layout>> {
borderColor Transparent
backgroundColor Transparent
fontColor Transparent
shadowing false
}
folder "source directory" as srcdir {
folder "include/cmake-exercise" as include_srcdir {
file a.hh
file b.hh
file c.hh
}
folder "src" {
file a.cc
file b.cc
}
folder "test" as test_srcdir {
file test.cc
}
file CMakeLists.txt
}
folder "build directory" as builddir {
rectangle folders_layout <<Layout>> {
folder "src" as src_builddir {
file a.o
file b.o
}
folder "test" as test_builddir {
file test.o
}
folder "include/cmake-exercise" as include_builddir {
file config.hh
}
}
rectangle artifacts_layout <<Layout>> {
artifact "<<static library>>\nlibstatic.a" as static
artifact "<<shared library>>\nlibshared.so" as shared
artifact "<<executable>>\ntest-binary" as test
static -[hidden]r- shared
shared -[hidden]r- test
}
}
srcdir -[hidden]r- builddir
package package.tar.xz {
folder "<prefix>/include/cmake-exercise" {
file a.hh as installed_a.hh
file b.hh as installed_b.hh
file c.hh as installed_c.hh
file config.hh as installed_config.hh
}
folder "<prefix>/share/cmake-exercise/test" {
artifact "<<executable>>\ntest" as installed_test
}
folder "<prefix>/lib" {
artifact "<<shared library>>\nlibshared.so" as installed_shared
}
}
actor CMake
a.hh --> installed_a.hh : <<install>>
b.hh --> installed_b.hh : <<install>>
c.hh --> installed_c.hh : <<install>>
config.hh --> installed_config.hh : <<install>>
test --> installed_test : <<install>>
shared --> installed_shared : <<install>>
file "<<source>>\na.cc" as a.cc
file "<<source>>\nb.cc" as b.cc
file "<<source>>\na.hh" as a.hh
file "<<source>>\nb.hh" as b.hh
file "<<source>>\nc.hh" as c.hh
file "<<source>>\nconfig.hh" as config.hh
file "<<file>>\na.o" as a.o
file "<<file>>\nb.o" as b.o
file "<<file>>\ntest.o" as test.o
file "<<source>>\ntest.cc" as test.cc
CMake -u-> config.hh : <<generate>>
a.cc --> a.o : <<compile>>
b.cc --> b.o : <<compile>>
test.cc --> test.o : <<compile>>
test ..> test.o : <<link>>
test ..> static : <<link>>
static ..> a.o : <<archive>>
shared ..> a.o : <<link>>
shared ..> b.o : <<link>>
b.hh ~r~> a.hh : <<include>>
a.hh ~~> c.hh : <<include>>
b.hh ~~> c.hh : <<include>>
a.hh ~~> config.hh : <<include>>
b.hh ~~> config.hh : <<include>>
a.cc ~~> a.hh : <<include>>
b.cc ~~> b.hh : <<include>>
test.cc ~~> a.hh : <<include>>
@enduml

View File

@ -0,0 +1,16 @@
#pragma once
#include <thread>
class A
{
public:
A ();
A (A&&) = default;
~A ();
A& operator= (A&&) = default;
private:
std::thread _t;
};

View File

@ -0,0 +1,16 @@
#pragma once
#include <cmake-exercise/a.hh>
#include <cmake-exercise/config.hh>
#include <vector>
class B
{
public:
DSO_EXPORT B ();
private:
std::vector<A> _a;
};

View File

@ -0,0 +1,4 @@
#pragma once
template <typename T>
void unused_function (); // nothing to see here

31
exercises/src/a.cc Normal file
View File

@ -0,0 +1,31 @@
#include <cmake-exercise/a.hh>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <sstream>
A::A ()
: _t ([] ()
{
{
std::ostringstream oss;
oss << "Starting thread " << std::this_thread::get_id () << std::endl;
std::cout << oss.str() << std::flush;
}
std::this_thread::sleep_for (std::chrono::milliseconds(std::rand() % 100 * 10));
{
std::ostringstream oss;
oss << "Thread " << std::this_thread::get_id () << " finished" << std::endl;
std::cout << oss.str() << std::flush;
}
})
{
}
A::~A ()
{
_t.join ();
}

7
exercises/src/b.cc Normal file
View File

@ -0,0 +1,7 @@
#include <cmake-exercise/b.hh>
#include <cmake-exercise/c.hh>
B::B ()
: _a (10)
{
}

19
exercises/test/test.cc Normal file
View File

@ -0,0 +1,19 @@
#include <cmake-exercise/a.hh>
#include <vector>
int
main()
{
// not a real test, heh.
#ifdef HAVE_OPENMP
# pragma omp parallel for
for (int n = 0; n < 20; ++n)
{
A a;
}
#else
std::vector<A> a (20);
#endif
}

142
feature-platform-check.tex Normal file
View File

@ -0,0 +1,142 @@
\subsection{Feature vs. Platform Checks}
\begin{frame}
\frametitle{Feature checks}
\begin{center}
\huge Probing the outside system\\for capabilities
\end{center}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}
\frametitle{What's a ``Feature''}
Distinctive attribute which may have influence on the final system being built.\\
\\
Can be classified in 3 domains:
\begin{itemize}
\item Platform features\\
{\info {library, symbols, functions, type size}}
\item Compiler features\\
{\info {variadic templates, constexpr, final, override}}
\item System dictated features\\
{\info {no-exceptions, no-rtti, no logging}}
\end{itemize}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle {Platform specific feature check}
\textbf{Bad}
\begin{codebox}{CMake}{}
if(IOS OR ANDROID OR UNIX)
target_compile_definitions(lua PRIVATE HAVE_POSIX_SPAWN)
endif()
\end{codebox}
\textbf{Good}
\begin{codebox}{CMake}{}
check_symbol_exists("posix_spawn" "spawn.h" has_posix_spawn)
if(has_posix_spawn)
target_compile_definitions(lua PRIVATE HAVE_POSIX_SPAWN)
endif()
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle {Compiler specific feature checks}
\textbf{Bad}
\begin{codebox}[minted options={fontsize=\tiny}]{CMake}{}
if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
target_compile_definitions(my-library
PRIVATE -DBOOST_THREAD_DONT_USE_CHRONO)
endif()
\end{codebox}
\textbf{Good}
\begin{codebox}[minted options={fontsize=\tiny}]{CMake}{}
# (incomplete example, checking for exception support is slightly harder)
check_cxx_source_compile("
int main() {
#if !defined(__EXCEPTIONS)
#error Exceptions not supported.
#endif
}" exceptions_supported)
if(NOT exceptions_supported)
target_compile_definitions(my-library
PRIVATE -DBOOST_THREAD_DONT_USE_CHRONO)
endif()
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle {System dictated feature checks}
\textbf{Bad}
\begin{codebox}[minted options={fontsize=\scriptsize}]{CMake}{}
find_package(Boost)
if(Boost_FOUND)
add_definition(ENABLE_FEATURE_X)
endif()
\end{codebox}
\textbf {Good}
\begin{codebox}[minted options={fontsize=\scriptsize}]{CMake}{}
# In product config file
set(ENABLE_FEATURE_X TRUE)
# In project configuration
if(ENABLE_FEATURE_X)
find_package(Boost REQUIRED)
add_definition(FEATURE_X_ENABLED)
endif()
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}
\frametitle{Functions for configure checks}
CMake provides an API to check:
\begin{itemize}
\item Header existence: {\code{check\_include\_file()}}
\item Library existence: {\code{check\_library\_exists()}}
\item Symbol existence: {\code{check\_symbol\_exists()}}
\item Supported type sizes: {\code{check\_type\_size()}}
\end{itemize}
CMake provides an API to write custom checks via:
\begin{itemize}
\item {\code{try\_compile()}}
\item {\code{try\_run()}}
\end{itemize}
With {\code configure\_file} you can generate a header file
enabling required code switches based on the checks.
\end{frame}
% --------------------------------------------------------------------
\note{
What is Platform check
What is feature check
CMAKE system introspection interface
-What type of checks can be done with CMAKE
https://cmake.org/Wiki/CMake:How\_To\_Write\_Platform\_Checks
Pros and Cons
}

BIN
images/cmake-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/dylib_rpath.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
images/eye-of-god.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/so_rpath.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

82
main.tex Normal file
View File

@ -0,0 +1,82 @@
%\documentclass[notes,usenames,dvipsnames]{beamer}
\documentclass[usenames,dvipsnames]{beamer}
%\documentclass[usenames,dvipsnames,handout]{beamer}
\input{preamble}
% for the handout
\usepackage{pgfpages}
\setbeamertemplate{headline}{}
\addtobeamertemplate{navigation symbols}{}{%
\usebeamerfont{footline}%
\usebeamercolor[fg]{footline}%
\hspace{1em}%
\insertframenumber/\inserttotalframenumber
}
\begin{document}
\hypersetup{
colorlinks=true,
urlcolor=cyan
}
\title{Introduction to CMake}
\author[M. Settenvini] {
Matteo Settenvini \\
$\langle$\href{mailto:matteo@member.fsf.org}{matteo@member.fsf.org}$\rangle$
}
\date{\today}
% --------------------------------------------------
\begin{frame}
\begin{columns}[T]
\begin{column}{.5\textwidth}
\titlepage
\end{column}
\begin{column}{.5\textwidth}
\begin{center}
\begin{tikzpicture}
\node (logo) {\includegraphics[width=.6\textwidth]{images/cmake-logo.png}};
\node (eye) at ([shift={(logo)}] -90:.55) {\includegraphics[width=.3\textwidth]{images/eye-of-god.png}};
\end{tikzpicture}
\vspace{1em}
\end{center}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------
\begin{frame}
\frametitle{Table of Contents}
\begin{multicols}{2}
\footnotesize
\tableofcontents
\end{multicols}
\end{frame}
% --------------------------------------------------
\section{CMake as a language}
\input{cmake-for-scripting}
\section{Setting up a CMake project}
\input{usage-of-targets}
\input{project-handling}
\section{Starting from today}
\input{starting-from-today}
\section{Outro}
\input{outro}
% --------------------------------------------------
\end{document}

13
outro.tex Normal file
View File

@ -0,0 +1,13 @@
% --------------------------------------------------
\subsection{Q\&A}
\begin{frame}
\frametitle{Q\&A}
\begin{center}
\huge Questions?
\end{center}
\end{frame}
% --------------------------------------------------

145
preamble.tex Normal file
View File

@ -0,0 +1,145 @@
\usepackage{fontspec}
\usepackage{polyglossia}
\usepackage[justification=centering]{caption}
\usepackage{graphics}
\usepackage[listings,skins,minted]{tcolorbox}
\usepackage{etoolbox,xpatch}
\usepackage{multicol}
\setdefaultlanguage{english}
\newfontfamily\emotifont{Noto Emoji}
% ---------------------------------------------------------------------
% new commands
\newcommand\hint[1]{\tiny \color{Black} {#1}\\}
\newcommand\todo[1]{\tiny \color{Red} {TODO: #1}\\}
\newcommand\code[1]{\scriptsize \ttfamily \color{blue} {#1}}
\newcommand\info[1]{\scriptsize \slshape {#1}}
% ---------------------------------------------------------------------
% style thingies
\usetheme{Malmoe}
\tikzset{
every overlay node/.style={
rounded corners,anchor=north west,
},
}
% Usage:
% \tikzoverlay at (-1cm,-5cm) {content};
% or
% \tikzoverlay[text width=5cm] at (-1cm,-5cm) {content};
\def\tikzoverlay{%
\tikz[baseline,overlay]\node[every overlay node]
}%
\addtobeamertemplate{headline}{}{%
\tikzoverlay at (-.97\textwidth,.18\textheight) {%
\includegraphics[height=.15\textheight,keepaspectratio]{images/cmake-logo.png}%
};
}
\definecolor{herenavy}{RGB}{15,22,33}
\definecolor{hereblue}{RGB}{72,218,208}
\setbeamercolor{structure}{fg=herenavy}
\setbeamercolor{palette primary}{fg=white,bg=herenavy!70}
\setbeamercolor{palette secondary}{fg=white,bg=herenavy!80}
\setbeamercolor{palette tertiary}{fg=white,bg=herenavy!90}
\setbeamercolor{palette quaternary}{fg=white,bg=herenavy}
\setbeamercolor{titlelike}{parent=palette quaternary}
\setbeamercolor{subsection in head/foot}{bg=herenavy!90}
\setbeamercolor{block title}{fg=white,bg=herenavy}
\setbeamercolor{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!bg}
\setbeamercolor{block title example}{use=example text,fg=white,bg=example text.fg!75!bg}
\setbeamercolor{block body}{parent=normal text,use=block title,bg=block title.bg!25!bg}
\setbeamercolor{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!25!bg}
\setbeamercolor{block body example}{parent=normal text,use=block title example,bg=block title example.bg!25!bg}
\setbeamercolor{sidebar}{bg=hereblue!70}
\setbeamercolor{palette sidebar primary}{fg=herenavy}
\setbeamercolor{palette sidebar secondary}{fg=herenavy!75}
\setbeamercolor{palette sidebar tertiary}{fg=herenavy!75}
\setbeamercolor{palette sidebar quaternary}{fg=herenavy}
\setbeamercolor*{separation line}{}
\setbeamercolor*{fine separation line}{}
% ---------------------------------------------------------------------
\newcommand\fullscreenimage[2]{
\begin{figure}
\centering
\includegraphics[width=\textwidth,height=.7\textheight,keepaspectratio]{#1}
\caption*{\tiny #2}
\end{figure}
}
% ---------------------------------------------------------------------
% Listings stuff
\newcommand{\mynewminted}[3]{%
\newminted[#1]{#2}{#3}%
\tcbset{myminted/#1/.style={minted language=#2,minted options={#3}}}}
\mynewminted{CMake}{cmake}{tabsize=2,fontsize=\footnotesize}
\mynewminted{C++}{cpp}{tabsize=4,fontsize=\footnotesize}
\mynewminted{Bash}{bash}{tabsize=2,fontsize=\footnotesize}
\mynewminted{Shell}{shell-session}{tabsize=2,fontsize=\footnotesize,breaklines}
\newtcblisting{codebox}[3][]{%
listing only,%
title={#3},%
enhanced,%
colback=structure.bg!20,%
colframe=black!60,%
drop fuzzy shadow,%
myminted/#2,%
#1}
\newtcblisting{goodcodebox}[2][]{%
listing only,%
title={Good},%
enhanced,%
top=.3em,%
left=.3em,%
fonttitle=\tiny\bfseries,%
colback=structure.bg!20,%
colframe=green!80!black!90,%
drop fuzzy shadow,%
myminted/#2,%
minted options={fontsize=\tiny},%
#1}
\newtcblisting{badcodebox}[2][]{%
listing only,%
title={Bad},%
enhanced,%
top=.3em,%
left=.3em,%
fonttitle=\tiny\bfseries,%
colback=structure.bg!20,%
colframe=red!90!black!90,%
drop fuzzy shadow,%
myminted/#2,%
minted options={fontsize=\tiny},%
#1}
% We ignore parsing errors as part of this presentation
\makeatletter
\AtBeginEnvironment{minted}{\dontdofcolorbox}
\def\dontdofcolorbox{\renewcommand\fcolorbox[4][]{##4}}
\xpatchcmd{\inputminted}{\minted@fvset}{\minted@fvset\dontdofcolorbox}{}{}
\makeatother

6
project-handling.tex Normal file
View File

@ -0,0 +1,6 @@
\input{rpath-build-install-tree}
\input{cross-compilation-toolchains}
\input{feature-platform-check}
\input{troubleshooting}
% --------------------------------------------------------------------

View File

@ -0,0 +1,135 @@
\begin{frame}
\frametitle{Relocatable binaries and resources}
\begin{center}
\huge Making packages relocatable
\end{center}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{rpath}
Runtime search path - embedded in the binaries
\vspace{1em}
\includegraphics[width=.95\textwidth,keepaspectratio]{images/so_rpath.png}
\vspace{1em}
\includegraphics[width=.95\textwidth,keepaspectratio]{images/dylib_rpath.png}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{rpath}
Used by the Dynamic Linker (DL) on UNIX systems
\begin{itemize}
\item rpath - almost the first place to look for the libraries,
\newline nowadays {\code{DT\_RUNPATH}} is more common than
{\code{DT\_RPATH}} as a tag
\item Search path sequence for DL -
{\code{RPATH, LD\_LIBRARY\_PATH, RUNPATH, /etc/ld.so.conf, /lib/,
/usr/lib}, …}
\end{itemize}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{rpath}
\begin{itemize}
\item Can be overwritten - {\code {chrpath, patchelf}}
\item Can be extracted - {\code {objdump, readelf, otool, etc.}}
\end{itemize}
\begin{codebox}{Shell}{}
$ objdump -x <path-to-library> | grep RPATH
$ readelf -d <path-to-library> | grep RPATH
$ otool -L <path-to-library>
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}
\frametitle{rpath}
\begin{tabular}{ | p{5cm} | p{5cm} |}
\hline
{\textbf {In Build Tree}} & {\textbf {In Install Tree}} \\
\hline
{Points to directories in the build folder
{\begin{itemize}
\item Usually full paths
\item Updated while installing
\end{itemize}}} &
{Points to directories specified during build for installation
{\begin{itemize}
\item Can be full path
\item Can be relative path
\item Can be empty
\end{itemize}}} \\
\hline
\end{tabular}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}
\frametitle {Relocatable packages}
Relative or empty rpaths when installed
\begin{itemize}
\item {\code \$ORIGIN} - *nix OSs
\item {\code @rpath} (+ {\code @loader\_path}, {\code @executable\_path}) - Mac OSX \& IOS
\item Always Empty - Android\\
{\info {Usually libraries are packed with {\code APK} and loaded using {\code
dlopen} interface\\}}
\item Always Empty - for Windows\\
{\info {Only user account and system env paths are
searched for libraries, plus the current folder\\}}
\end{itemize}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}
\frametitle{Making loading resources relocatable}
Resources used by package should be easily locatable\\
\textbf{Bad:} when resource paths are hardcoded in the source code\\
\textbf{Good:} when resource paths are dynamically determined at runtime\\
\end{frame}
\begin{frame}
\frametitle{Making loading resources relocatable}
You need to write a function able to determine the relative path from its
containing binary to the installation root at runtime.\\
\begin{itemize}
\item No need to hardcode resouce location in the sources
\item Path to resources should be located based on their types, such as:\\
{\code LIBRARY}, {\code BINARY}, {\code DATA}, {\code CONFIG},
etc.
\item Aware of the install tree directory structure
\item Just make sure that install tree structure is not violated
\end{itemize}
\end{frame}
% --------------------------------------------------------------------

45
rules.ninja Normal file
View File

@ -0,0 +1,45 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by "Ninja" Generator, CMake Version 3.13
# This file contains all the rules used to get the outputs files
# built from the input files.
# It is included in the main 'build.ninja'.
# =============================================================================
# Project: presentation
# Configuration:
# =============================================================================
# =============================================================================
#############################################
# Rule for running custom commands.
rule CUSTOM_COMMAND
command = $COMMAND
description = $DESC
#############################################
# Rule for re-running cmake.
rule RERUN_CMAKE
command = /usr/bin/cmake -S/home/matteo/cmake-presentation -B/home/matteo/cmake-presentation
description = Re-running CMake...
generator = 1
#############################################
# Rule for cleaning all built files.
rule CLEAN
command = /usr/bin/ninja -t clean
description = Cleaning all built files...
#############################################
# Rule for printing all primary targets available.
rule HELP
command = /usr/bin/ninja -t targets
description = All primary targets available:

234
starting-from-today.tex Normal file
View File

@ -0,0 +1,234 @@
\begin{frame}
\frametitle{Starting from today}
\begin{center}
\huge Things you can start doing\newline Right Now™
\end{center}
\end{frame}
% --------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Use targets in place of variables}
\begin{codebox}[minted options={fontsize=\scriptsize}]{CMake}{}
find_package(GTest REQUIRED)
find_package(Boost REQUIRED COMPONENTS system thread)
find_package(EXPAT REQUIRED) # only vars
add_library(alexandria …)
\end{codebox}
\begin{columns}
\begin{column}{.5\textwidth}
\begin{badcodebox}[equal height group=targets1]{CMake}
target_link_libraries(alexandria
PRIVATE
${BOOST_LIBRARIES}
${EXPAT_LIBRARIES}
${GTEST_MAIN_LIBRARIES})
\end{badcodebox}
\end{column}
\begin{column}{.5\textwidth}
\begin{goodcodebox}[equal height group=targets1]{CMake}
target_link_libraries(alexandria
PRIVATE
Boost::system
Boost::thread
GTest::Main
${EXPAT_LIBRARIES}) # legacy
\end{goodcodebox}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Use target-specific commands\footnote{An exception is of
course in toolchain files.}}
Some commands propagate to all subfolders and included files. This
can lead to potential problems where some targets get extra
unintended flags.
\vspace{.3em}
\begin{columns}
\begin{column}{.5\textwidth}
\begin{badcodebox}[equal height group=tgtspecific1]{CMake}
add_definitions(-DDEFINE_SOMETHING=1)
add_compile_options(-fvisibility=hidden)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fno-exceptions")
\end{badcodebox}
\end{column}
\begin{column}{.5\textwidth}
\begin{goodcodebox}[equal height group=tgtspecific1]{CMake}
target_compile_definitions(tgt PRIVATE
DEFINE_SOMETHING=1)
target_compile_options(tgt PRIVATE
"-fno-tree-vrp")
\end{goodcodebox}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Avoid \texttt{target\_include\_directories}}
\begin{codebox}[minted options={fontsize=\scriptsize}]{CMake}{}
find_package(EXPAT REQUIRED) # external, has only vars
find_package(Boost REQUIRED) # external, has targets
add_library(alexandria egypt.cc)
target_link_libraries(alexandria
PUBLIC calliope clio Boost::filesystem
PRIVATE euterpe erato ${EXPAT_LIBRARIES})
\end{codebox}
\vspace{.2em}
\begin{columns}
\begin{column}{.5\textwidth}
\begin{badcodebox}[equal height group=tgtincdir1]{CMake}
target_include_directories(alexandria
PUBLIC ${PROJECT_SOURCE_DIR}/include
$<TARGET_PROPERTY:calliope,#
INTERFACE_INCLUDE_DIRECTORIES>
PRIVATE ${EUTERPE_INCLUDE_DIRS} # ...
${CMAKE_SOURCE_DIR}/calliope/inc
${BOOST_INCLUDE_DIRS}
${EXPAT_INCLUDE_DIRS})
\end{badcodebox}
\end{column}
\begin{column}{.5\textwidth}
\begin{goodcodebox}[equal height group=tgtincdir1]{CMake}
target_include_directories(alexandria
PUBLIC $<BUILD_INTERFACE:#
${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:#
${include_install_rel_dir}>
PRIVATE ${EXPAT_INCLUDE_DIRS})
\end{goodcodebox}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Use PRIVATE and PUBLIC}
\begin{columns}
\begin{column}{.5\textwidth}
\begin{badcodebox}[equal height group=privpub1]{CMake}
target_link_libraries(tgt
libA
libB
libC)
target_compile_definitions(tgt
HAVE_THINGIE)
\end{badcodebox}
\end{column}
\begin{column}{.5\textwidth}
\begin{goodcodebox}[equal height group=privpub1]{CMake}
target_link_libraries(tgt
PRIVATE libA
libB
PUBLIC libC)
target_compile_definitions(tgt
PRIVATE HAVE_THINGIE)
\end{goodcodebox}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Prefer feature checks}
\begin{columns}
\begin{column}{.5\textwidth}
\begin{badcodebox}[equal height group=feat1]{CMake}
if(APPLE OR IOS OR (UNIX AND NOT ANDROID))
target_compile_definitions(lua PRIVATE
HAVE_POSIX_SPAWN)
endif()
\end{badcodebox}
\end{column}
\begin{column}{.5\textwidth}
\begin{goodcodebox}[equal height group=feat1]{CMake}
check_symbol_exists("posix_spawn" "spawn.h"
has_posix_spawn)
if(has_posix_spawn)
target_compile_definitions(lua PRIVATE
HAVE_POSIX_SPAWN)
endif()
\end{goodcodebox}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Make your package relocatable}
\begin{columns}
\begin{column}{.5\textwidth}
\begin{badcodebox}[equal height group=relocatable1]{CMake}
install(FILES "example.conf"
DESTINATION some/strange/folder)
\end{badcodebox}
\begin{badcodebox}[equal height group=relocatable2]{C++}
char buf[2048];
getcwd(buf, 2048);
using boost::filesystem::path;
path rez = path(buf) /
HARDCODED_ABSOLUTE_PREFIX_PATH
/ "some" / "strange" / "folder" /
"example.conf";
\end{badcodebox}
\end{column}
\begin{column}{.5\textwidth}
\begin{goodcodebox}[equal height group=relocatable1]{CMake}
include(GNUInstallDirs)
install(RESOURCES "example.conf"
DESTINATION
${CMAKE_INSTALL_SYSCONFDIR}/appname)
\end{goodcodebox}
\begin{goodcodebox}[equal height group=relocatable2]{C++}
using your_ns::some_enum::ResourceType;
using boost::filesystem::path;
path = your_ns::get_resource_path(
ResourceType::CONFIG,
{ "appname", "example.conf" });
\end{goodcodebox}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------

20
troubleshooting.tex Normal file
View File

@ -0,0 +1,20 @@
\subsection{Troubleshooting}
% --------------------------------------------------------------------
\begin{frame}
\frametitle{Troubleshooting}
When problems arise while hacking CMake code, do \textbf{not} panic!
\vspace{1em}
Run in the build directory:\\
\texttt{\$ cmake --trace-expand . 2> trace\_expand.txt}.
\vspace{1em}
This will give more insight about what happens behind the scenes.
\end{frame}
% --------------------------------------------------------------------

288
usage-of-targets.tex Normal file
View File

@ -0,0 +1,288 @@
\subsection{The CMake processing steps}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Projects and targets}
\begin{center}
\huge Defining what to build
\end{center}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{The CMake Process}
\begin{columns}
\begin{column}{0.425\textwidth}
CMake has two main steps:
\begin{itemize}
\item Configure step.
\item Generate step.
\end{itemize}
\end{column}
\begin{column}{0.575\textwidth}
\begin{figure}
\centering
\includegraphics[width=.8\textwidth,keepaspectratio]{images/cmake-simple-flowchart.png}
\caption*{\tiny 2017 © Jeff Preshing \url{http://preshing.com/20170511/how-to-build-a-cmake-based-project/}}
\end{figure}
\end{column}
\end{columns}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{$1^{st}$ step - Configuration}
In the \emph{configure} step CMake processes all the input given to
it, via \texttt{CMakeLists.txt}, and creates an internal
representation of the build to be performed. \texttt{CMakeCache.txt}
is generated at this step.
\vspace{1em}
The end of this step is expressed by \texttt{"Configuring done"}
message from CMake.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{$2^{nd}$ step - Generation}
In the \emph{generate} step CMake will produce native build tool
files e.g. Visual Studio solution files, XCode project files, Ninja
build files etc.
\vspace{1em}
The end of this step is expressed by \texttt{"Generating done"}
message from CMake.
\end{frame}
% --------------------------------------------------------------------
\subsection{About targets}
\begin{frame}
\frametitle{Targets and dependency propagation}
\begin{center}
\huge Targets and their dependencies
\end{center}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Targets}
A CMake-based buildsystem is organized as a set of high-level
logical \emph{targets}.
\vspace{1em}
Each target corresponds to an executable or library, or is a custom
target containing custom commands.
\vspace{1em}
\begin{codebox}{CMake}{}
add_library(archive archive.cpp zip.cpp lzma.cpp)
add_executable(zipapp zipapp.cpp)
target_link_libraries(zipapp archive)
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Transitive Usage Requirements}
The usage requirements of a target can transitively propagate to
dependents.
\vspace{1em}
The {\code{target\_link\_libraries()}} command has
\texttt{PRIVATE}, \texttt{INTERFACE}, and \texttt{PUBLIC} keywords
to control the propagation.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Transitive Usage Requirements}
A dependency should be specified in a use of
{\code{target\_link\_libraries()}} with the:
\begin{itemize}
\item \texttt{PRIVATE} keyword, if it is used \emph{only} by the
implementation of a library, and not in its public header files.
\item \texttt{PUBLIC} keyword, if a dependency is additionally
used in the header files of a library (e.g. any header
inclusion).
\item \texttt{INTERFACE} keyword, if is \emph{not} used by the
implementation of a library, but only by its public header
files.
\end{itemize}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Transitive Usage Requirements Example}
\begin{codebox}{CMake}{}
add_library(liba a.cpp)
target_compile_definitions(liba INTERFACE USING_LIB_A)
add_library(libb b.cpp)
target_compile_definitions(libb INTERFACE USING_LIB_B)
add_library(libc c.cpp)
target_link_libraries(libc PUBLIC liba PRIVATE libb)
# libc is compiled with -DUSING_LIB_A and -DUSING_LIB_B
add_executable(app main.cpp)
target_link_libraries(app libc)
# app is compiled with -DUSING_LIB_A
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Targets Modifier functions}
You should use the following functions to control your targets:
\begin{itemize}
\item {\code{target\_include\_directories()}} adds directories to
the include search path.
\item {\code{target\_compile\_definitions()}} adds pre-processor
definitions.
\item {\code{target\_compile\_options()}} adds compiler options
(\texttt{-Wall, /bigobj}).
\item {\code{target\_compile\_features()}} adds necessary compiler
features (\texttt{cxx\_constexpr, cxx\_variadic\_templates}).
\item {\code{target\_sources()}} adds more source files to the
target.
\item {\code{target\_link\_libraries()}} add library dependency.
\end{itemize}
\end{frame}
% --------------------------------------------------------------------
\subsection{Preparing for packaging}
\begin{frame}
\frametitle{Locating packages}
\begin{center}
\huge Preparing the project for packaging
\end{center}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{CMake packages}
Packages provide dependency information to CMake.
\vspace{1em}
Packages are found with the {\code{find\_package()}} command.
\vspace{1em}
The result of using {\code{find\_package()}} is either a set of
\texttt{IMPORTED} targets, or a set of variables
e.g. \texttt{<package>\_FOUND}, \texttt{<package>\_INCLUDE\_DIRS},
\texttt{<package>\_LIBRARIES}.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Packages Example}
CMake provides direct support for two forms of packages:
\begin{itemize}
\item \texttt{CONFIG}-file packages (the new way).
\item Find-\texttt{MODULE} packages (prioritized for backwards-compat).
\end{itemize}
\begin{codebox}{CMake}{}
# CMake provides a Boost find-module
find_package(Boost 1.60.0 MODULE REQUIRED)
# Qt Project provides a Qt5 package config file.
find_package(Qt5Core 5.9.0 CONFIG REQUIRED
COMPONENTS Widgets)
# Use pkg-config via the LibXml2 find-module
find_package(LibXml2 MODULE REQUIRED)
\end{codebox}
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Packages Config-file}
A config-file package the recommended CMake package type.
\vspace{1em}
The config-file package consists of a set of files provided by
upstreams for downstreams to use.
\vspace{1em}
The Qt Project doesn't use CMake as their own build system, but
they do provide a config-file package for CMake users.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Packages -- Find-module}
A find-module is needed when the upstream is not built with CMake,
or is not CMake-aware enough to otherwise provide a package
configuration file.
\vspace{1em}
The find-module is a file with a set of rules for finding the
required pieces of a dependency, primarily header files and
libraries e.g. \texttt{FindBoost.cmake}.
\end{frame}
% --------------------------------------------------------------------
\begin{frame}[containsverbatim]
\frametitle{Packages Config-file continued}
A config-file package can be used in two ways:
\begin{itemize}
\item to find a configured project that is already part of the
build.
\item to import an installed package.
\end{itemize}
\vspace{1em}
The process of creating a config-file package using CMake commands
({\code{configure\_package\_config\_file()}},
{\code{write\_basic\_package\_version\_file()}}, {\code{install()}},
{\code{export()}}) is quite verbose, and error prone.
\end{frame}
% --------------------------------------------------------------------