我想设置一个变量,该变量可在我作为子目录 ( ) 包含的第三方库中修改add_subdirectory(.../third_party/libA)
。该库允许我启用/禁用构建过程的某些部分,例如包括测试目标,例如:set(BUILD_TESTS OFF)
。
但是,如果多个库包含相同的选项,并且名称相同,我该怎么办?我知道存在我想要实现的“相反方向”PARENT_SCOPE
的选项set()
,但是有没有办法以某种方式限制范围,以便我可以执行以下操作(下面的模拟行为):
project(my_project)
set(libA_BUILD_TESTS OFF) # I DO NOT want to build tests for libA
add_subdirectory("${my_project_SOURCE_DIR}/third_party/libA")
set(libB_BUILD_TESTS ON) # I DO want to build tests for libB
add_subdirectory("${my_project_SOURCE_DIR}/third_party/libB")
由于我无法控制第三方库的变量名,因此变量libA_BUILD_TESTS
和libB_BUILD_TESTS
实际上并不存在。它们都只是有BUILD_TESTS
。
是否可以这样做并期望每个都应该正确设置?我不熟悉 CMake 如何处理变量解析的时间...
set(BUILD_TESTS OFF) add_subdirectory(.../third_party/libA) set(BUILD_TESTS ON) add_subdirectory(.../third_party/libB)
除了共享相同的变量名之外,有没有更明确/更安全的方式来声明我希望这两个变量不同?对我来说,重复使用相同的变量名似乎从根本上容易出错,而且特别“糟糕”。我不喜欢这样,因为它使变量“有状态”,这使得在构建过程中更难跟踪。
我是否正确地思考了这个基本的变量设置过程?也许我对 #2 的感受根本不是“做事的方式”。
我尝试过的一些随机的事情(没有成功):
特定于子目录的设置属性:
set(libA_dir "${my_project_SOURCE_DIR}/third_party/libA")
set(libB_dir "${my_project_SOURCE_DIR}/third_party/libB")
set_property(DIRECTORY ${libA_dir} PROPERTY BUILD_TESTS OFF)
set_property(DIRECTORY ${libB_dir} PROPERTY BUILD_TESTS ON)
设置目标属性(由于目标尚不存在,因此不起作用):
# does not work because the libA target does not yet exist
set_target_properties(libA PROPERTIES BUILD_TESTS OFF)
add_subdirectory("${my_project_SOURCE_DIR}/third_party/libA")
# this does work based on how the third party CMake was written...
find_package(libA REQUIRED)
在定义目标之后设置目标属性(不起作用,因为在看到我的 set_target_properties 之前逻辑已经被处理了):
add_subdirectory("${my_project_SOURCE_DIR}/third_party/libA")
# does not work because the subdir was already included and seems to have not respected
# the options here due to timing/ordering.
set_target_properties(libA PROPERTIES BUILD_TESTS OFF)
# this does work based on how the third party CMake was written...
find_package(libA REQUIRED)
最后:我希望了解确保这两个库之间变量分配“隔离”的方法,尤其是当同一个变量有两个不同的值时(即“我想为 libA 构建测试,但不想为 libB 构建测试”)。谢谢。
我认为您使用的思维模型缺少一些部分。我会仔细阅读CMake 文档中有关变量范围的内容
BUILD_TESTS
,并特别注意“范围”和“绑定”这两个词的用法。如果您可以分享 libA 和 libB 的声明方式,以便我们了解它是缓存变量还是普通变量,这也有助于改进问题。我有两个建议供您尝试,具体取决于您是否可以编辑
third_party
目录1. 将 libA 和 libB cmake 配置分离到不同目录范围内的不同文件中。
如果您为 libA 和 libB 创建了一个包含 CMakeLists.txt 文件的包装器目录,那么您在这些包装器目录中设置的任何常规变量都将封装到该目录中。例如,如果您的项目如下所示:
顶层 CMakeLists.txt:
libA_wrapper/CmakeLists.txt:
libB_wrapper/CMakeLists.txt
然后
BUILD_TESTS
每个库的变量将彼此独立,并且独立于您的顶级范围。构建输出将如下所示:2. 使用 block() 范围分离 libA 和 libB 配置
如果您的项目需要将第三方配置保存在单个文件中,那么您可以使用关键字
block()
来创建自己的范围块。以下顶级 CMakeLists.txt 在功能上等同于上述示例:顶层 CMakeLists.txt
但要注意缓存变量
上述示例仅
BUILD_TESTS
在您的项目中将其声明为普通变量(而非缓存变量)时才有效。然后您需要更改使用方式set()
这个问题开始变得主观,因此更难回答。如果在同一范围内使用相同的变量名来表示多个含义,我会觉得很容易出错(而且很严重)。但是,我认为在不同
BUILD_TESTS
范围内使用同名变量是正常的,甚至可能是一件好事。libA 和 libB 都可以定义自己的变量而不必担心彼此,这很好。i
我认为这与使用和重用名称作为for
我在每个循环中写入的迭代器变量的能力相同C
。