|
|
**CAUTION: The contents of this page may be obsolete**
|
|
|
![120px-Old_finnish_stop_sign.svg](/uploads/521180f925eeefd545a3a7a761185c2e/120px-Old_finnish_stop_sign.svg.png)
|
|
|
|
|
|
----
|
|
|
|
|
|
[Back](CMake_User_Contributed_Macros "wikilink")
|
|
|
|
|
|
Lists are an important component of most CMakeLists.txt files. Lists are
|
|
|
built automatically from arguments to commands and macros. Thus, we
|
|
|
often build lists in variables by calling SET with more than one
|
|
|
variable argument. Surprisingly, there are very few CMake commands to
|
|
|
handle lists. Here is a compilation of a few basic list manipulation
|
|
|
commands.
|
|
|
|
|
|
**Update:** Since CMake 2.4 most of the issues discussed here can be
|
|
|
handled using the native CMake LIST command. However, these were very
|
|
|
useful macros for handling lists in previous versions and they still are
|
|
|
if you would like to add LIST support to your CMakeLists.txt files and
|
|
|
for some reason you can't update your CMake installation. As such, I
|
|
|
have maintained the original content as is, and provided a section at
|
|
|
the bottom that makes use of the new CMake LIST command to perform the
|
|
|
same functionality as the CAR, CDR, LIST_LENGTH, LIST_INDEX, and
|
|
|
LIST_CONTAINS macros below. Note that there is a LIST_FILTER macro
|
|
|
below that I have not attempted to write using the enhanced LIST
|
|
|
command.
|
|
|
|
|
|
## CAR and CDR
|
|
|
|
|
|
Our first operations we take from lisp, a programming language built
|
|
|
entirely around lists. Two fundamental functions of lisp are car, which
|
|
|
returns the first element of a list, and cdr, which returns a list minus
|
|
|
the first element. Here we give implementations of car and cdr CMake
|
|
|
macros. Although they are not as efficient as their counterparts in
|
|
|
lisp, they can still be surprisingly useful.
|
|
|
|
|
|
MACRO(CAR var)
|
|
|
SET(${var} ${ARGV1})
|
|
|
ENDMACRO(CAR)
|
|
|
|
|
|
MACRO(CDR var junk)
|
|
|
SET(${var} ${ARGN})
|
|
|
ENDMACRO(CDR)
|
|
|
|
|
|
Here is a simple example of their use.
|
|
|
|
|
|
SET(MYLIST hello world foo bar)
|
|
|
|
|
|
CAR(car ${MYLIST})
|
|
|
CDR(cdr ${MYLIST})
|
|
|
MESSAGE("car: ${car}")
|
|
|
MESSAGE("cdr: ${cdr}")
|
|
|
|
|
|
The output of the command above is
|
|
|
|
|
|
car: hello
|
|
|
cdr: world;foo;bar
|
|
|
|
|
|
Note that the CAR and CDR macros (as well as the rest of the macros in
|
|
|
this document) take advantage of CMake's calling convention of expanding
|
|
|
lists into arguments. If you quote the list argument, you get a very
|
|
|
different result. If you change the previous example to
|
|
|
|
|
|
CAR(car "${MYLIST}")
|
|
|
CDR(cdr "${MYLIST}")
|
|
|
MESSAGE("car: ${car}")
|
|
|
MESSAGE("cdr: ${cdr}")
|
|
|
|
|
|
you get
|
|
|
|
|
|
car: hello;world;foo;bar
|
|
|
cdr:
|
|
|
|
|
|
## LIST_LENGTH
|
|
|
|
|
|
Here is a macro to get the length of a list.
|
|
|
|
|
|
MACRO(LIST_LENGTH var)
|
|
|
SET(entries)
|
|
|
FOREACH(e ${ARGN})
|
|
|
SET(entries "${entries}.")
|
|
|
ENDFOREACH(e)
|
|
|
STRING(LENGTH ${entries} ${var})
|
|
|
ENDMACRO(LIST_LENGTH)
|
|
|
|
|
|
If you use the LIST_LENGTH macro as follows
|
|
|
|
|
|
SET(MYLIST hello world foo bar)
|
|
|
|
|
|
LIST_LENGTH(length ${MYLIST})
|
|
|
MESSAGE("length: ${length}")
|
|
|
|
|
|
you get this output:
|
|
|
|
|
|
length: 4
|
|
|
|
|
|
## LIST_INDEX
|
|
|
|
|
|
Sometimes you want to get a particular entry of a list. This macro lets
|
|
|
you grab the \(n^\mathrm{th}\) entry in a list (indexed from 1).
|
|
|
|
|
|
MACRO(LIST_INDEX var index)
|
|
|
SET(list . ${ARGN})
|
|
|
FOREACH(i RANGE 1 ${index})
|
|
|
CDR(list ${list})
|
|
|
ENDFOREACH(i)
|
|
|
CAR(${var} ${list})
|
|
|
ENDMACRO(LIST_INDEX)
|
|
|
|
|
|
If you use LIST_INDEX with the following commands
|
|
|
|
|
|
SET(MYLIST hello world foo bar)
|
|
|
|
|
|
LIST_INDEX(first 1 ${MYLIST})
|
|
|
LIST_INDEX(second 2 ${MYLIST})
|
|
|
LIST_INDEX(third 3 ${MYLIST})
|
|
|
LIST_INDEX(fourth 4 ${MYLIST})
|
|
|
MESSAGE("first: ${first}")
|
|
|
MESSAGE("second: ${second}")
|
|
|
MESSAGE("third: ${third}")
|
|
|
MESSAGE("fourth: ${fourth}")
|
|
|
|
|
|
you get this output:
|
|
|
|
|
|
first: hello
|
|
|
second: world
|
|
|
third: foo
|
|
|
fourth: bar
|
|
|
|
|
|
## LIST_CONTAINS
|
|
|
|
|
|
Sometimes you just want to know if a list contains a particular entry.
|
|
|
|
|
|
MACRO(LIST_CONTAINS var value)
|
|
|
SET(${var})
|
|
|
FOREACH (value2 ${ARGN})
|
|
|
IF (${value} STREQUAL ${value2})
|
|
|
SET(${var} TRUE)
|
|
|
ENDIF (${value} STREQUAL ${value2})
|
|
|
ENDFOREACH (value2)
|
|
|
ENDMACRO(LIST_CONTAINS)
|
|
|
|
|
|
Here are some simple examples of using LIST_CONTAINS.
|
|
|
|
|
|
SET(MYLIST hello world foo bar)
|
|
|
|
|
|
LIST_CONTAINS(contains foo ${MYLIST})
|
|
|
IF (contains)
|
|
|
MESSAGE("MYLIST contains foo")
|
|
|
ENDIF (contains)
|
|
|
|
|
|
LIST_CONTAINS(contains baz ${MYLIST})
|
|
|
IF (NOT contains)
|
|
|
MESSAGE("MYLIST does not contain baz")
|
|
|
ENDIF (NOT contains)
|
|
|
|
|
|
The result of the previous examples is:
|
|
|
|
|
|
MYLIST contains foo
|
|
|
MYLIST does not contain baz
|
|
|
|
|
|
## LIST_FILTER
|
|
|
|
|
|
# LIST_FILTER(<list> <regexp_var> [<regexp_var> ...]
|
|
|
# [OUTPUT_VARIABLE <variable>])
|
|
|
# Removes items from <list> which do not match any of the specified
|
|
|
# regular expressions. An optional argument OUTPUT_VARIABLE
|
|
|
# specifies a variable in which to store the matched items instead of
|
|
|
# updating <list>
|
|
|
# As regular expressions can not be given to macros (see bug #5389), we pass
|
|
|
# variable names whose content is the regular expressions.
|
|
|
# Note that this macro requires PARSE_ARGUMENTS macro, available here:
|
|
|
# http://www.cmake.org/Wiki/CMakeMacroParseArguments
|
|
|
MACRO(LIST_FILTER)
|
|
|
PARSE_ARGUMENTS(LIST_FILTER "OUTPUT_VARIABLE" "" ${ARGV})
|
|
|
# Check arguments.
|
|
|
LIST(LENGTH LIST_FILTER_DEFAULT_ARGS LIST_FILTER_default_length)
|
|
|
IF(${LIST_FILTER_default_length} EQUAL 0)
|
|
|
MESSAGE(FATAL_ERROR "LIST_FILTER: missing list variable.")
|
|
|
ENDIF(${LIST_FILTER_default_length} EQUAL 0)
|
|
|
IF(${LIST_FILTER_default_length} EQUAL 1)
|
|
|
MESSAGE(FATAL_ERROR "LIST_FILTER: missing regular expression variable.")
|
|
|
ENDIF(${LIST_FILTER_default_length} EQUAL 1)
|
|
|
# Reset output variable
|
|
|
IF(NOT LIST_FILTER_OUTPUT_VARIABLE)
|
|
|
SET(LIST_FILTER_OUTPUT_VARIABLE "LIST_FILTER_internal_output")
|
|
|
ENDIF(NOT LIST_FILTER_OUTPUT_VARIABLE)
|
|
|
SET(${LIST_FILTER_OUTPUT_VARIABLE})
|
|
|
# Extract input list from arguments
|
|
|
LIST(GET LIST_FILTER_DEFAULT_ARGS 0 LIST_FILTER_input_list)
|
|
|
LIST(REMOVE_AT LIST_FILTER_DEFAULT_ARGS 0)
|
|
|
FOREACH(LIST_FILTER_item ${${LIST_FILTER_input_list}})
|
|
|
FOREACH(LIST_FILTER_regexp_var ${LIST_FILTER_DEFAULT_ARGS})
|
|
|
FOREACH(LIST_FILTER_regexp ${${LIST_FILTER_regexp_var}})
|
|
|
IF(${LIST_FILTER_item} MATCHES ${LIST_FILTER_regexp})
|
|
|
LIST(APPEND ${LIST_FILTER_OUTPUT_VARIABLE} ${LIST_FILTER_item})
|
|
|
ENDIF(${LIST_FILTER_item} MATCHES ${LIST_FILTER_regexp})
|
|
|
ENDFOREACH(LIST_FILTER_regexp ${${LIST_FILTER_regexp_var}})
|
|
|
ENDFOREACH(LIST_FILTER_regexp_var)
|
|
|
ENDFOREACH(LIST_FILTER_item)
|
|
|
# If OUTPUT_VARIABLE is not specified, overwrite the input list.
|
|
|
IF(${LIST_FILTER_OUTPUT_VARIABLE} STREQUAL "LIST_FILTER_internal_output")
|
|
|
SET(${LIST_FILTER_input_list} ${${LIST_FILTER_OUTPUT_VARIABLE}})
|
|
|
ENDIF(${LIST_FILTER_OUTPUT_VARIABLE} STREQUAL "LIST_FILTER_internal_output")
|
|
|
ENDMACRO(LIST_FILTER)
|
|
|
|
|
|
Here is a use-case of the two
|
|
|
signatures:
|
|
|
|
|
|
SET(sources foo.c foo.cc foo.cpp foo.cxx foo.h foo.hh foo.hxx foo.hpp foo.hcc)
|
|
|
SET(re_header ".+\\.h$" ".+\\.hh$")
|
|
|
SET(re_inline ".+\\.hxx$" ".+\\.hpp$")
|
|
|
SET(re_impl ".+\\.c+" ".+\\.hcc$")
|
|
|
LIST_FILTER(sources re_header re_inline OUTPUT_VARIABLE headers)
|
|
|
LIST_FILTER(sources re_impl)
|
|
|
FOREACH(var sources headers)
|
|
|
MESSAGE(STATUS "content of variable \"${var}\":")
|
|
|
FOREACH(elt ${${var}})
|
|
|
MESSAGE(STATUS " ${elt}")
|
|
|
ENDFOREACH(elt)
|
|
|
ENDFOREACH(var)
|
|
|
|
|
|
Then you get the following output:
|
|
|
|
|
|
-- content of variable "sources":
|
|
|
-- foo.c
|
|
|
-- foo.cc
|
|
|
-- foo.cpp
|
|
|
-- foo.cxx
|
|
|
-- foo.hcc
|
|
|
-- content of variable "headers":
|
|
|
-- foo.h
|
|
|
-- foo.hh
|
|
|
-- foo.hxx
|
|
|
-- foo.hpp
|
|
|
|
|
|
Note that `LIST_FILTER` requires the macro
|
|
|
[PARSE_ARGUMENTS](CMakeMacroParseArguments "wikilink").
|
|
|
|
|
|
## Using CMake LIST Command
|
|
|
|
|
|
The following code is based on the macros presented above:
|
|
|
|
|
|
SET(MYLIST hello world foo bar)
|
|
|
|
|
|
CAR(car ${MYLIST})
|
|
|
|
|
|
CDR(cdr ${MYLIST})
|
|
|
|
|
|
LIST_LENGTH(length ${MYLIST})
|
|
|
|
|
|
LIST_INDEX(first 1 ${MYLIST})
|
|
|
LIST_INDEX(second 2 ${MYLIST})
|
|
|
LIST_INDEX(third 3 ${MYLIST})
|
|
|
LIST_INDEX(fourth 4 ${MYLIST})
|
|
|
|
|
|
LIST_CONTAINS(contains_foo foo ${MYLIST})
|
|
|
LIST_CONTAINS(contains_baz baz ${MYLIST})
|
|
|
|
|
|
The previous code could have been implemented using the CMake LIST
|
|
|
command (CMake 2.4+) as shown below. Note, however, that the LIST(FIND
|
|
|
...) is available in CMake 2.4.7+.
|
|
|
|
|
|
SET(MYLIST hello world foo bar)
|
|
|
|
|
|
LIST(GET MYLIST 0 car)
|
|
|
|
|
|
SET(cdr ${MYLIST})
|
|
|
LIST(REMOVE_AT cdr 0)
|
|
|
|
|
|
LIST(LENGTH MYLIST length)
|
|
|
|
|
|
LIST(GET MYLIST 0 first)
|
|
|
LIST(GET MYLIST 1 second)
|
|
|
LIST(GET MYLIST 2 third)
|
|
|
LIST(GET MYLIST 3 fourth)
|
|
|
|
|
|
LIST(FIND MYLIST foo contains_foo)
|
|
|
LIST(FIND MYLIST baz contains_baz)
|
|
|
|
|
|
The output of the variables in both cases is:
|
|
|
|
|
|
MESSAGE("car: ${car}")
|
|
|
MESSAGE("cdr: ${cdr}")
|
|
|
MESSAGE("length: ${length}")
|
|
|
MESSAGE("first: ${first}")
|
|
|
MESSAGE("second: ${second}")
|
|
|
MESSAGE("third: ${third}")
|
|
|
MESSAGE("fourth: ${fourth}")
|
|
|
MESSAGE("contains_foo: ${contains_foo}")
|
|
|
MESSAGE("contains_baz: ${contains_baz}")
|
|
|
--
|
|
|
car: hello
|
|
|
cdr: world;foo;bar
|
|
|
length: 4
|
|
|
first: hello
|
|
|
second: world
|
|
|
third: foo
|
|
|
fourth: bar
|
|
|
contains_foo: 2 # for LIST_CONTAINS this is TRUE
|
|
|
contains_baz: -1 # for LIST_CONTAINS this is empty; which evaluates to false
|
|
|
|
|
|
Note that the CMake LIST command also provides additional flexibility,
|
|
|
such as APPEND, INSERT, SORT, REVERSE, etc. Type
|
|
|
|
|
|
cmake --help-command LIST
|
|
|
|
|
|
for the current usage information.
|
|
|
|
|
|
-----
|
|
|
|
|
|
[Back](CMake_User_Contributed_Macros "wikilink")
|
|
|
|
|
|
|
|
|
----
|
|
|
This page was initially populated by conversion from its [original location](https://public.kitware.com/Wiki/CMakeMacroListOperations) in another wiki. |