Previous Highlights:CMake Hello, WorldCMake VariablesCMake Official Tutorial (Basic Project Setup)CMake Official Tutorial (Library Creation)CMake Official Tutorial (Usage Requirements)CMake Official Tutorial (Installation and Testing)CMake Common Syntax (if Statement)CMake Common Syntax (Cache Variables)CMake Common Syntax (Environment Variables)CMake Common Syntax (Mathematical Calculations)CMake Common Syntax (Strings)
In CMake, a list is a collection of strings separated by semicolons, and we generally use the set command to create a list:
set(src "a.cpp" "b.cpp" c.cpp)
message("${src}")
#
set(_src_ "a.c;b.c;c.c")
message("${_src_}")
To facilitate various operations on lists, CMake provides the list command, which is detailed in the official documentation:
https://cmake.org/cmake/help/latest/command/list.html
The list command is categorized into four types based on functionality:
- 1. Read Operations
- 2. Search Operations
- 3. Modify Operations
- 4. Sorting and Reversing Operations
Read Operations
Command | Syntax | Function |
LENGTH | <span>list(LENGTH <list> <out var>)</span> |
Returns the length of the list |
GET | <span>list(GET <list> <elem index> [<elem index> ...] <out var>)</span> |
Gets the element at the specified index |
JOIN | <span>list(JOIN <list> <glue> <out var>)</span> |
Joins the list into a string with a separator |
SUBLIST | <span>list(SUBLIST <list> <begin> <length> <out var>)</span> |
Extracts a sublist |
This part of the commands does not require much explanation; we will directly provide examples:
cmake_minimum_required(VERSION 3.12)
project(listTest)
#
set(src "a.cpp;b.cpp;c.cpp;d.cpp;e.cpp")
message("${src}") #a.cpp;b.cpp;c.cpp;d.cpp;e.cpp
#
list(LENGTH src len)
message("src length=${len}") #5
# Index can be negative, -1 indicates the last element, but the index cannot be out of bounds
list(GET src 0 var)
message("src[0] = ${var}") #a.cpp
list(GET src 1 var)
message("src[1] = ${var}") #b.cpp
list(GET src -1 var)
message("src[-1] = ${var}") #e.cpp
#
list(JOIN src "|" out)
message("${out}") #a.cpp|b.cpp|c.cpp|d.cpp|e.cpp
#
list(SUBLIST src 02 sub)
message("${sub}") #a.cpp;b.cpp
Search Operations
Command | Syntax | Function |
FIND | <span>list(FIND <list> <value> <out var>)</span> |
Returns the index of the element (returns -1 if not found) |
The FIND subcommand syntax is simple and easy to understand; we will also provide examples directly:
cmake_minimum_required(VERSION 3.12)
project(listTest)
#
set(src "a.cpp;b.cpp;c.cpp;d.cpp;e.cpp")
message("${src}")
#
list(FIND src "a.cpp" idx)
message("idx=${idx}") #0
#
list(FIND src "bb.cpp" idx)
message("idx=${idx}") #-1
Modify Operations
This part of the commands is relatively numerous, especially in TRANSFORM, where different ACTIONs can be specified to flexibly transform elements in the list.
Command | Syntax | Function |
APPEND | <span>list(APPEND <list> [<elem>...])</span> |
Appends elements to the end |
FILTER | list(FILTER <list> {INCLUDE|EXCLUDE} REGEX <regex>) | Filters elements based on regex |
INSERT | <span>list(INSERT <list> <index> [<elem>...])</span> |
Inserts elements at the specified position |
POP_BACK | <span>list(POP_BACK <list> [<out-var>...])</span> |
Removes the last element and returns it |
POP_FRONT | <span>list(POP_FRONT <list> [<out-var>...])</span> |
Pops the first element |
PREPEND | <span>list(PREPEND <list> [<elem>...])</span> |
Inserts elements at the front |
REMOVE_ITEM | <span>list(REMOVE_ITEM <list> <value>...)</span> |
Removes all matching items |
REMOVE_AT | <span>list(REMOVE_AT <list> <index>...)</span> |
Removes items by index |
REMOVE_DUPLICATES | <span>list(REMOVE_DUPLICATES <list>)</span> |
Removes duplicates, keeping the first occurrence |
TRANSFORM | <span>list(TRANSFORM <list> <ACTION> [...])</span> |
Transforms elements (e.g., case conversion, replacement) |
Except for TRANSFORM, the other commands are relatively simple; here are usage examples:
cmake_minimum_required(VERSION 3.12)
project(listTest)
#
set(src "a.cpp;b.cpp")
#APPEND
list(APPEND src "c.cpp" "d.cpp")
message("${src}")
#FILTER
set(myList apple banana cherry)
list(FILTER myList INCLUDE REGEX "^a") # Keep elements starting with a
message("${myList}") #apple
#
set(myList apple banana cherry)
list(FILTER myList EXCLUDE REGEX "^a") # Remove elements starting with a
message("${myList}") #banana;cherry
#INSERT
set(myList a b d)
list(INSERT myList 2 c) # Insert at index 2
message("${myList}") #"a;b;c;d"
#POP_BACK
set(myList a b c)
list(POP_BACK myList last)
message("last = ${last}") #c
message("${myList}") #a;b
#POP_FRONT
set(myList a b c)
list(POP_FRONT myList first)
message("first = ${first}") #a
message("${myList}") #b;c
#PREPEND
set(myList b c)
list(PREPEND myList a)
message("${myList}") #"a;b;c"
#REMOVE_ITEM
set(myList a b a c)
list(REMOVE_ITEM myList a)
message("${myList}") #"b;c"
#REMOVE_AT
set(myList a b c d)
list(REMOVE_AT myList 1) # Remove indices 1 and 3
message("${myList}") #"a;c"
#REMOVE_DUPLICATES
set(myList a b a c b)
list(REMOVE_DUPLICATES myList)
message("${myList}") #"a;b;c"
The general syntax structure for TRANSFORM is as follows:
list(TRANSFORM <list> <ACTION> [<SELECTOR>] [OUTPUT_VARIABLE <output variable>])
For the ACTION part, the optional values are as follows:
- • APPEND/PREPEND, append/prefix, followed by a value
- • TOLOWER/TOUPPER, case conversion, no additional parameters needed
- • STRIP and GENEX_STRIP, remove spaces, no parameters needed
- • REPLACE, replace content, followed by a regex and a replacement expression
For the SELECTOR part:
- • AT, transform by index, followed by a list of indices.
- • FOR, transform by range, specifying start, end, and step.
- • REGEX, transform by regex, followed by a regex pattern.
Note that when using OUTPUT_VARIABLE, the original list will not be modified, and the result is stored in a new variable. Otherwise, the transformation will directly modify the original list.。
Examples of TRANSFORM are as follows:
cmake_minimum_required(VERSION 3.15)
project(listTest)
#
set(my_list "a" "b" "c")
# Append "_suffix" to all elements
list(TRANSFORM my_list APPEND "_suffix")
message("${my_list}") #"a_suffix;b_suffix;c_suffix"
# Add prefix "pre_" to the element at index 1
list(TRANSFORM my_list PREPEND "pre_" AT 1)
message("${my_list}") #"a_suffix;pre_b_suffix;c_suffix"
# Convert all to lowercase
set(my_list "Apple" "Banana" "Cherry")
list(TRANSFORM my_list TOLOWER)
message("${my_list}") #"apple;banana;cherry"
# Convert indices 0-1 to uppercase
list(TRANSFORM my_list TOUPPER FOR 01)
message("${my_list}") #"APPLE;BANANA;cherry"
# Remove spaces
set(my_list " foo " " bar " " baz ")
list(TRANSFORM my_list STRIP)
message("${my_list}") #"foo;bar;baz"
# Replace file extensions
set(my_list "file1.txt" "image.jpg" "doc.pdf")
list(TRANSFORM my_list REPLACE "\..+$" ".new")
message("${my_list}") #"file1.new;image.new;doc.new"
# Only replace filenames containing numbers
list(TRANSFORM my_list REPLACE "([0-9]+)" "V\1" REGEX ".*[0-9].*")
message("${my_list}") #"fileV1.new;image.new;doc.new"
# Modify elements at indices 0 and 3
set(nums "zero" "one" "two" "three")
list(TRANSFORM nums PREPEND "num_" AT 03)
message("${nums}") #"num_zero;one;two;num_three"
# Modify indices 1-3 (step 2)
set(alphas "a" "b" "c" "d" "e")
list(TRANSFORM alphas APPEND "X" FOR 132)
message("${alphas}") #"a;bX;c;dX;e"
# Add tags for C++ files
set(files "README.md" "src.cpp" "test.py")
list(TRANSFORM files APPEND "[C++]" REGEX ".*\.cpp$")
message("${files}") #"README.md;src.cpp[C++];test.py"
Sorting and Reversing
Command | Syntax | Function |
REVERSE | <span>list(REVERSE <list>)</span> |
Reverses the order of the list |
SORT | <span>list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])</span> |
Sorts according to rules |
The SORT command is slightly more complex, with optional parameter values as follows:
- 1.
<span>COMPARE</span>
: Selects the comparison method for sorting:
- •
<span>STRING</span>
: Sorts in dictionary order (default behavior). - •
<span>FILE_BASENAME</span>
: Sorts by the base name of the file path (file name). - •
<span>NATURAL</span>
: Sorts in natural order (treats consecutive numbers as whole values).
<span>CASE</span>
: Specifies case sensitivity:- •
<span>SENSITIVE</span>
: Case-sensitive (default behavior). - •
<span>INSENSITIVE</span>
: Case-insensitive (only sorts alphabetically, does not guarantee fixed order for case-differentiated items).
<span>ORDER</span>
: Specifies sorting direction:- •
<span>ASCENDING</span>
: Ascending order (default behavior). - •
<span>DESCENDING</span>
: Descending order.
Note that REVERSE and SORT directly modify the original list; if you need to keep the original list, you should copy it first.
Examples are as follows:
cmake_minimum_required(VERSION 3.15)
project(listTest)
#
set(my_list "a" "b" "c")
list(REVERSE my_list)
message("${my_list}") #c;b;a
# Default dictionary order (case-sensitive)
set(myList "banana" "Apple" "Cherry" "apple")
list(SORT myList)
message("SORT default:${myList}") # Output: Apple;Cherry;apple;banana
# Natural sorting (by numerical size)
set(versions "v12" "v3" "v1" "v20")
list(SORT versions COMPARE NATURAL)
message("Natural sorting: ${versions}") # Output: v1;v3;v12;v20
# Sort by file name
set(paths "/usr/bin/cmake" "/tmp/foo.txt" "/home/user/a.txt")
list(SORT paths COMPARE FILE_BASENAME)
message("File name sorting: ${paths}")
# Case-insensitive and descending
set(fruits "Banana" "apple" "Cherry" "Apricot")
list(SORT fruits CASE INSENSITIVE ORDER DESCENDING)
message("Descending + case-insensitive: ${fruits}") # Output: Cherry;Banana;Apricot;apple