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

% --------------------------------------------------------------------
