CMake作用域规则

4

我对cmake的作用域规则有些困惑。 我确实有文件和目录,如下所示:

 ├── test
 │    CMakeLists.txt 
 │   ├── cmake
 │   │       MyCMake 
 │   │       MyCMake2 
 │   ├── child
 │   │       CMakeLists.txt 

The contents are:

cmake/MyCMake:

set(MY_NAME MyName)
message("MyCMake: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

cmake/MyCMake2:

set(HIS_NAME NewName)
message("MyCMake2: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

child/CMakeLists.txt:

set(YOUR_NAME YourName)
set(HIS_NAME HisName PARENT_SCOPE)
message("Child: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

test/CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(MyCMake)
add_subdirectory(child)
message("Parent1: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})
include(MyCMake2)
message("Parent2: " ${MY_NAME} " " ${YOUR_NAME} " " ${HIS_NAME})

结果是:
MyCMake: MyName  
Child: MyName YourName 
Parent1: MyName  HisName
MyCMake2: MyName  NewName
Parent2: MyName  NewName

第一行没问题,第二行和第三个变量还没有定义。第二行显示它似乎是仅父级设置,即定义的变量仅在父级中具有作用域。(那么,我可以/应该使用具有本地作用域的相同变量吗?)第三行仅显示具有父级作用域的变量,没问题。第四行显示我设置了一个本地作用域变量。然而,在第五行中,我看到父级作用域值已经改变了,而我希望它仅在子目录中局部更改。

这里发生了什么?(看起来我可以覆盖不在我的作用域内的变量的值)

为什么我开始尝试:在某些条件下,我在父目录中看不到在子目录中定义的变量(例如包含目录、库名称等)。是否有标准方法在一个子目录中使用库名称进行构建,并在另一个子目录中使用相同的名称进行链接?

还有一个问题:我有一个应用程序,由库和可执行文件组成。看起来CMake不允许同时为两者使用相同的目标名称。在我看来,如果我将名称“ A”用于二进制目标和库目标,这不应该导致混淆,因为真正的第二个目标是“ libA”。我错了吗?


对于第一个问题,请参见如何设置和使用变量的CMake语法?。对于您的第二个问题,我想您正在寻找在cmake中检查未按正确顺序排列的可选目标。对于您的第三个问题,您可能需要查看add_custom_command未生成目标 - Florian
1个回答

17
基本规则很简单:add_subdirectory创建一个新的作用域,而include不会。因此,在您的示例中,只涉及到两个作用域:
  • 顶层CMakeList的作用域受到MyCMakeMyCMake2中的set(...)命令以及child/CMakeLists.txt中的set(... PARENT_SCOPE)命令的影响。
  • child/CMakeLists.txt的作用域受child/CMakeLists.txt内部使用的不带PARENT_SCOPEset(...)命令的影响。

您是正确的,PARENT_SCOPE只在父级作用域中设置值。如果要同时为当前作用域和父级作用域设置值,则必须发出两个set命令:

set(var Value)
set(var Value PARENT_SCOPE)

在Stack Overflow上,我们通常倾向于每个问题只有一个具体问题,但我也会回答关于目标命名的问题:CMake目标名称是针对CMake的目标的逻辑名称,它们必须是唯一的。想象一下,如果不是这样:


add_library(L STATIC ...)
add_library(A SHARED ...)
add_executable(A ...)

target_link_libraries(A L)

最后一行会产生什么影响?库 A 会链接到 L,还是可执行文件 A 会这样做?或者两者都会?对于设置属性等内容也是如此。

您可以独立地控制生成的二进制文件的名称,而不受其目标名称的影响:有关详细信息,请参阅目标属性,例如OUTPUT_NAME


基本上,我同意“一个问题一个问题”的规则,但这次三个问题是相互关联的,并且问题之间的强制延迟意味着我需要4.5小时才能发布三个问题。关于逻辑名称:你是对的,但这个方案防止使用库libA创建名为A的二进制文件。 - katang
1
@katang 不,这并不会阻止二进制库方案。你只需要给目标逻辑名称 A_binA_lib,并将它们的 OUTPUT_NAME 属性都设置为 A没有任何东西会阻止你这样做。 - Angew is no longer proud of SO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接