\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 either 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{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} \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{\_FOUND}, \texttt{\_INCLUDE\_DIRS}, \texttt{\_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} % --------------------------------------------------------------------