

Introduction:
In previous examples, we have used if-else-endif. CMake also provides language tools for creating loops: foreach-endforeach and while-endwhile. Both can be combined with break to exit the loop early. This article also serves as the conclusion of the first chapter, marking our official entry into learning CMake.

✦
Project Structure
✦
.
├── cal_add.h
├── cal_subtract.cpp
├── cal_subtract.h
├── CMakeLists.txt
├── main.cpp
├── message.cpp
└── message.h
This project structure returns to a simple structure, mainly to quickly demonstrate the main purpose of this article: how to use control flow to implement certain functions.
Project Address:
https://gitee.com/jiangli01/tutorials/tree/master/cmake-tutorial/chapter1/13
✦
CMakeLists.txt
✦
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(control-flow LANGUAGES CXX)
set(CXX_STANDARD 11)
add_library(test_lib
STATIC
${CMAKE_SOURCE_DIR}/message.h
${CMAKE_SOURCE_DIR}/message.cpp
${CMAKE_SOURCE_DIR}/cal_add.h
${CMAKE_SOURCE_DIR}/cal_subtract.h
${CMAKE_SOURCE_DIR}/cal_subtract.cpp
)
# Compile the library with -O3 optimization level and set a private compiler option for the target
target_compile_options(test_lib PRIVATE -O3)
# Generate a list of source files to be compiled with lower optimization options
list(APPEND sources_with_lower_optimization
cal_subtract.cpp
)
# Loop through these source files and adjust their optimization level to -O2. Use their source file properties to achieve this
message(STATUS "Setting source properties using IN LISTS syntax:")
foreach(_source IN LISTS sources_with_lower_optimization)
set_source_files_properties(${_source} PROPERTIES COMPILE_FLAGS -O2)
message(STATUS "Appending -O2 flag for ${_source}")
endforeach()
# To ensure properties are set, loop again and print each source file's COMPILE_FLAGS property
message(STATUS "Querying sources properties using plain syntax:")
foreach(_source ${sources_with_lower_optimization})
get_source_file_property(_flags ${_source} COMPILE_FLAGS)
message(STATUS "Source ${_source} has the following extra COMPILE_FLAGS: ${_flags}")
endforeach()
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} test_lib)
set_source_files_properties(file PROPERTIES property value)
Sets the properties to the given file’s passing values. Similar to targets, files also have properties in CMake that allow for very fine-grained control over the build system.
get_source_file_property(VAR file property)
Retrieves the value of the required property for the given file and stores it in the CMakeVAR
variable.
Note: In CMake
, lists are strings of groups separated by ;
. Lists can be created by list
or set
commands. For example, set(var a b c d e)
and list(APPEND a b c d e)
both create the list a;b;c;d;e
.
foreach(loop_var range total)
or
foreach(loop_var range start stop [step])
Loop through integers by specifying a range
✦
Related Source Code
✦
cal_add.h
#ifndef CALCULATE_ADD_HEADER
#define CALCULATE_ADD_HEADER
template <typename T, typename U>
auto Add(T t, U u) -> decltype(t + u){
return t + u;
}
#endif // ! CALCULATE_ADD_HEADER
cal_substruct.h
#ifndef CALCULATE_SUBSTRACT_HEADER
#define CALCULATE_SUBSTRACT_HEADER
float Substract(float a, float b);
#endif // ! CALCULATE_SUBSTRACT_HEADER
cal_substruct.cpp
float Substract(float a, float b) { return a - b; }
message.h
#ifndef MESSAGE_HEADER_H_
#define MESSAGE_HEADER_H_
#include <string>
class Message {
public:
Message() {}
void Print(const std::string& message);
};
#endif // ! MESSAGE_HEADER_H_
message.cpp
#include "message.h"
#include <iostream>
void Message::Print(const std::string& message) {
std::cout << message << std::endl;
}
main.cpp
#include "message.h"
#include "cal_add.h"
#include "cal_subtract.h"
int main() {
int a = 1;
int b = 2;
auto c = Add(a , b);
Message message;
message.Print(std::to_string(c));
return 0;
}
Compilation Result
-- The CXX compiler identification is GNU 9.4.0
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Setting source properties using IN LISTS syntax:
-- Appending -O2 flag for cal_add.cpp
-- Appending -O2 flag for cal_subtract.cpp
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jiangli/repo/tutorials/cmake-tutorial/chapter1/13/build
✦
Appendix
✦
foreach()
has four usage forms:
-
foreach(loop_var arg1 arg2 ...)
: where the loop variable and explicit item list are provided. This form is used when printing compiler flags for items insources_with_lower_optimization
. Note that if the project list is in a variable, it must be explicitly expanded; that is,${sources_with_lower_optimization}
must be passed as an argument. You can loop through integers by specifying a range, for example:foreach(loop_var range total)
orforeach(loop_var range start stop [step])
. -
Looping over list value variables, for example:
foreach(loop_var IN LISTS [list1[...]])
. The parameter is interpreted as a list, and its contents will be automatically expanded. -
Looping over variables, for example:
foreach(loop_var IN ITEMS [item1 [...]])
. The contents of the parameter are not expanded.
Finally: Don’t let bad moods affect your day! Peace & Love!

