\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} % --------------------------------------------------------------------