Functions And Macros¶
Simplest Of Functions¶
function(simple)
message("that was simple")
endfunction()
simple()
$ cmake -P function-simple.cmake
that was simple
Function Scope¶
Variables are local to a function
function(simple) set(some_variable "value") endfunction() simple() if (NOT DEFINED some_variable) message("pooh, not seeing function side effect") endif()
$ cmake -P function-scope.cmake pooh, not seeing function side effect
Caller’s (parent’s) variables are visible inside a function
function(access_parent) message("inside function: ${some_variable}") endfunction() set(some_variable "outside value") access_parent()
$ cmake -P function-scope-parent.cmake inside function: outside value
Function cannot modify caller’s variables ⟶ function scope is a copy of caller’s scope
Function Scope: And Nested Function?¶
Calling functions inherit their scope into called functions
function(inner_function) message("inner_function: \${outer_variable}: ${outer_variable}") endfunction() function(outer_function) set(outer_variable "outer value") inner_function() endfunction() outer_function()
$ cmake -P function-nested-scope.cmake inner_function: ${outer_variable}: outer value
Passing Parameters In¶
In function “body”, formal parameters (e.g.
param
) are treated just like variablesfunction(take_one_parameter param) message("${param}") endfunction() take_one_parameter("the parameter")
$ cmake -P function-one-parameter.cmake the parameter
Superfluous parameters are discarded ⟶ quoting!
function(take_one_parameter param) message("${param}") endfunction() take_one_parameter(the parameter)
$ cmake -P function-one-parameter-passed-two.cmake the
… whereas missing parameters cause a CMake error
function(take_one_parameter param) message("${param}") endfunction() take_one_parameter()
$ cmake -P function-one-parameter-passed-none.cmake CMake Error at function-one-parameter-passed-none.cmake:5 (take_one_parameter): take_one_parameter Function invoked with incorrect arguments for function named: take_one_parameter
This is a function that takes two formal parameters
function(take_two_parameters param1 param2) message("param1: ${param1}, param2: ${param2}") endfunction() take_two_parameters("the first parameter" "the second parameter")
$ cmake -P function-two-parameters.cmake param1: the first parameter, param2: the second parameter
Parameters: ARGC
, ARGV
, ARGVn
, ARGN
¶
ARGC
: number of arguments passedfunction(argv_etc first_param second_param) message("${ARGC}") endfunction() argv_etc("one" "two") argv_etc("one" "two" "three")
$ cmake -P function-argc.cmake 2 3
ARGV
: list of all argumentsfunction(argv_etc first_param second_param) message("${ARGV}") endfunction() argv_etc("one" "two") argv_etc("one" "two" "three")
$ cmake -P function-argv.cmake one;two one;two;three
ARGVn
: referencing arguments by position (invalid position ⟶ empty/undefined)function(argv_etc first_param second_param) message("ARGV0: >${ARGV0}<") message("ARGV1: >${ARGV1}<") message("ARGV3000: >${ARGV3000}<") endfunction() argv_etc("one" "two")
$ cmake -P function-argvn.cmake ARGV0: >one< ARGV1: >two< ARGV3000: ><
ARGN
: arguments past the last formal argumentfunction(argv_etc first_param second_param) message("${ARGN}") endfunction() argv_etc("one" "two" "three" "four")
$ cmake -P function-argn.cmake three;four
And Output Variables? Return Values?¶
There is no
return
statement⟶ functions aren’t expressions
No “output” parameters (like references in C++, or pointers in C)
… but there is
set(... PARENT_SCOPE)
PARENT_SCOPE
Examples¶
Creating a variable in caller scope just because we can
function(reach_out) set(caller_variable "ha, I modified parent scope" PARENT_SCOPE) endfunction() reach_out() message("caller_variable magically appeared: >${caller_variable}<")
$ cmake -P function-reaching-out.cmake caller_variable magically appeared: >ha, I modified parent scope<
Modifying a variable passed in by the caller (“output variable”, “pass by reference”)
function(reach_out ref_param) set(${ref_param} "callee's value" PARENT_SCOPE) endfunction() set(some_variable "caller's value") message("some_variable before call: >${some_variable}<") reach_out(some_variable) message("some_variable after call: >${some_variable}<")
$ cmake -P function-output-parameter.cmake some_variable before call: >caller's value< some_variable after call: >callee's value<
Popular trick, used by many CMake functions: set multiple variables with the same prefix in caller scope
function(reach_out stem) set(${stem}_one "one value" PARENT_SCOPE) set(${stem}_another "another value" PARENT_SCOPE) endfunction() reach_out(some_variable) message(${some_variable_one}) message(${some_variable_another})
$ cmake -P function-reaching-out-stem.cmake one value another value
Passing Any Number Of Parameters¶
Special parameters
ARGC
(number of arguments) andARGV
(of list type)function(takes_any_number_args) message("number of args passed: ${ARGC}") message("args passed: ${ARGV}") endfunction() takes_any_number_args("one" "two")
$ cmake -P function-varargs.cmake number of args passed: 2 args passed: one;two
Accessing parameters by position
function(takes_any_number_args) message("${ARGV0}") message("${ARGV1}") endfunction() takes_any_number_args("one" "two")
$ cmake -P function-varargs-by-position.cmake one two
Fancy Parameter Parsing: cmake_parse_arguments()
¶
function(takes_fancy_parameters)
cmake_parse_arguments(MYPARAMS
"VERBOSE;COOL" # options/flags
"FANCY1;FANCY2" # single-value parameters
"FANCIES1;FANCIES2" # multi-value parameters
${ARGV}
)
if (MYPARAMS_VERBOSE)
message("being verbose")
endif()
if (MYPARAMS_COOL)
message("being cool")
endif()
if (DEFINED MYPARAMS_FANCY1)
message("FANCY1: >${MYPARAMS_FANCY1}<")
else()
message("FANCY1: undefined")
endif()
if (DEFINED MYPARAMS_FANCY2)
message("FANCY2: >${MYPARAMS_FANCY2}<")
else()
message("FANCY2: undefined")
endif()
if (DEFINED MYPARAMS_FANCIES1)
message("FANCIES1: >${MYPARAMS_FANCIES1}<")
else()
message("FANCIES1: undefined")
endif()
if (DEFINED MYPARAMS_FANCIES2)
message("FANCIES2: >${MYPARAMS_FANCIES2}<")
else()
message("FANCIES2: undefined")
endif()
endfunction()
takes_fancy_parameters(FANCIES1 "one-fancy" "two-fancy" VERBOSE FANCY2 "fancy")
$ cmake -P function-parse-args.cmake
being verbose
FANCY1: undefined
FANCY2: >fancy<
FANCIES1: >one-fancy;two-fancy<
FANCIES2: undefined
And Macros?¶
Just like functions
… only without own scope
⟶ share caller’s scope
macro(simple)
set(some_variable "value") # <--- no PARENT_SCOPE
endmacro()
simple()
message("some_variable: >${some_variable}<")
$ cmake -P macro-simple.cmake
some_variable: >value<