2019-07-27 18:28:47 +02:00
|
|
|
|
\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}
|
|
|
|
|
|
2019-07-28 21:53:30 +02:00
|
|
|
|
Each target either corresponds to an executable or library, or is a custom
|
2019-07-27 18:28:47 +02:00
|
|
|
|
target containing custom commands.
|
|
|
|
|
|
|
|
|
|
\vspace{1em}
|
|
|
|
|
|
2019-07-28 21:53:30 +02:00
|
|
|
|
\begin{codebox}{CMake}{}
|
|
|
|
|
add_library(archive archive.cpp zip.cpp lzma.cpp)
|
|
|
|
|
add_executable(zipapp zipapp.cpp)
|
|
|
|
|
target_link_libraries(zipapp archive)
|
|
|
|
|
\end{codebox}
|
|
|
|
|
|
2019-07-27 18:28:47 +02:00
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
|
|
% --------------------------------------------------------------------
|
|
|
|
|
|
2019-07-28 21:53:30 +02:00
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
|
\frametitle{Custom Target and Dependencies}
|
|
|
|
|
|
|
|
|
|
Example with custom targets:
|
|
|
|
|
|
|
|
|
|
\vspace{1em}
|
|
|
|
|
|
|
|
|
|
\begin{codebox}{CMake}{}
|
|
|
|
|
add_custom_command(OUTPUT output.file
|
|
|
|
|
COMMAND generator
|
|
|
|
|
--in ${CMAKE_CURRENT_SOURCE_DIR}/input.file
|
|
|
|
|
--out output.file
|
|
|
|
|
DEPENDS input.file
|
|
|
|
|
COMMENT "This is an example invocation of a generator"
|
|
|
|
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
|
|
|
|
|
|
|
|
|
add_custom_target(my-target
|
|
|
|
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/output.file)
|
|
|
|
|
\end{codebox}
|
|
|
|
|
\end{frame}
|
|
|
|
|
|
2019-07-27 18:28:47 +02:00
|
|
|
|
\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}
|
|
|
|
|
|
|
|
|
|
% --------------------------------------------------------------------
|