💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 1.10 使用控制流 **NOTE**:*此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-01/recipe-10 中找到,有一个C++示例。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。* 本章前面的示例中,已经使用过`if-else-endif`。CMake还提供了创建循环的语言工具:`foreach endforeach`和`while-endwhile`。两者都可以与`break`结合使用,以便尽早从循环中跳出。本示例将展示如何使用`foreach`,来循环源文件列表。我们将应用这样的循环,在引入新目标的前提下,来为一组源文件进行优化降级。 ## 准备工作 将重用第8节中的几何示例,目标是通过将一些源代码汇集到一个列表中,从而微调编译器的优化。 ## 具体实施 下面是`CMakeLists.txt`中要的详细步骤: 1. 与示例8中一样,指定了CMake的最低版本、项目名称和语言,并声明了几何库目标: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(recipe-10 LANGUAGES CXX) add_library(geometry STATIC geometry_circle.cpp geometry_circle.hpp geometry_polygon.cpp geometry_polygon.hpp geometry_rhombus.cpp geometry_rhombus.hpp geometry_square.cpp geometry_square.hpp ) ``` 2. 使用`-O3`编译器优化级别编译库,对目标设置一个私有编译器选项: ```cmake target_compile_options(geometry PRIVATE -O3 ) ``` 3. 然后,生成一个源文件列表,以较低的优化选项进行编译: ```cmake list( APPEND sources_with_lower_optimization geometry_circle.cpp geometry_rhombus.cpp ) ``` 4. 循环这些源文件,将它们的优化级别调到`-O2`。使用它们的源文件属性完成: ```cmake 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() ``` 5. 为了确保设置属性,再次循环并在打印每个源文件的`COMPILE_FLAGS`属性: ```cmake 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() ``` 6. 最后,添加`compute-areas`可执行目标,并将`geometry`库连接上去: ```cmake add_executable(compute-areas compute-areas.cpp) target_link_libraries(compute-areas geometry) ``` 7. 验证在配置步骤中正确设置了标志: ```shell $ mkdir -p build $ cd build $ cmake .. ... -- Setting source properties using IN LISTS syntax: -- Appending -O2 flag for geometry_circle.cpp -- Appending -O2 flag for geometry_rhombus.cpp -- Querying sources properties using plain syntax: -- Source geometry_circle.cpp has the following extra COMPILE_FLAGS: -O2 -- Source geometry_rhombus.cpp has the following extra COMPILE_FLAGS: -O2 ``` 8. 最后,还使用`VERBOSE=1`检查构建步骤。将看到`-O2`标志添加在`-O3`标志之后,但是最后一个优化级别标志(在本例中是`-O2`)不同: ```shell $ cmake --build . -- VERBOSE=1 ``` ## 工作原理 `foreach-endforeach`语法可用于在变量列表上,表示重复特定任务。本示例中,使用它来操作、设置和获取项目中特定文件的编译器标志。CMake代码片段中引入了另外两个新命令: * `set_source_files_properties(file PROPERTIES property value) `,它将属性设置为给定文件的传递值。与目标非常相似,文件在CMake中也有属性,允许对构建系统进行非常细粒度的控制。源文件的可用属性列表可以在这里找到: https://cmake.org/cmake/help/v3.5/manual/cmake-properties.7.html#source-file-properties 。 * `get_source_file_property(VAR file property)`,检索给定文件所需属性的值,并将其存储在CMake`VAR`变量中。 **NOTE**:*CMake中,列表是用分号分隔的字符串组。列表可以由`list`或`set`命令创建。例如,`set(var a b c d e)`和`list(APPEND a b c d e)`都创建了列表`a;b;c;d;e`。* **TIPS**:*为了对一组文件降低优化,将它们收集到一个单独的目标(库)中,并为这个目标显式地设置优化级别,而不是附加一个标志,这样可能会更简洁,不过在本示例中,我们的重点是`foreach-endforeach`。* ## 更多信息 `foreach()`的四种使用方式: * `foreach(loop_var arg1 arg2 ...) `: 其中提供循环变量和显式项列表。当为`sources_with_lower_optimization`中的项打印编译器标志集时,使用此表单。注意,如果项目列表位于变量中,则必须显式展开它;也就是说,`${sources_with_lower_optimization}`必须作为参数传递。 * 通过指定一个范围,可以对整数进行循环,例如:`foreach(loop_var range total)`或`foreach(loop_var range start stop [step])`。 * 对列表值变量的循环,例如:`foreach(loop_var IN LISTS [list1[...]])` 。参数解释为列表,其内容就会自动展开。 * 对变量的循环,例如:` foreach(loop_var IN ITEMS [item1 [...]])`。参数的内容没有展开。