分层CMake项目,在构建“;“内部”;(非根)项目
假设我有一个分层的CMake项目,由不同的项目组成:分层CMake项目,在构建“;“内部”;(非根)项目,cmake,build,Cmake,Build,假设我有一个分层的CMake项目,由不同的项目组成: CMakeLists.txt proj-1/CMakeLists.txt proj-2/CMakeLists.txt (...) proj-n/CMakeLists.txt 显然,每个项目都会有源文件 我会确保所有感兴趣的命令都添加到根CMakeLists.txt文件中,比如说,CMAKE\u CXX\u STANDARD,enable\u testing(),add\u compile\u options(),等等。如果我理解正确,根CM
CMakeLists.txt
proj-1/CMakeLists.txt
proj-2/CMakeLists.txt
(...)
proj-n/CMakeLists.txt
显然,每个项目都会有源文件
我会确保所有感兴趣的命令都添加到根CMakeLists.txt
文件中,比如说,CMAKE\u CXX\u STANDARD
,enable\u testing()
,add\u compile\u options()
,等等。如果我理解正确,根CMakeLists.txt
文件中包含的任何选项也将应用于所有子CMakeLists.txt
文件--如果我错了,请纠正我,因为我指望这种行为。对于每个X
=1,…,n,根CMakeLists.txt
还包含一个add_子目录(proj-X)
语句
无论如何。假设出于某种原因,我只想构建一个proj-X
文件夹,比如proj-1
。可能构建在其他项目中被破坏,或者可能我需要修复proj-1
上的一个bug,它不依赖于其他项目,而且构建所有项目将花费永远的时间
要点是:我想在proj-1/CMakeLists.txt上运行cmake
,而不是在根CMakeLists.txt
文件上运行cmake
,但是我想确保proj-1
的构建方式与在根CMakeLists.txt
文件上运行cmake
完全相同。这是一个问题,因为根CMakeLists.txt
包含子CMakeLists.txt
应该在从根构建的常规情况下“继承”的语句,而在这个场景中,我直接从proj-1/CMakeLists.txt
(在这种情况下,根CMakeLists.txt
文件不会出现在图片中。)
据我所知,一种可能是将所有选项从根CMakeLists.txt
文件复制到其他每个proj-X/CMakeLists.txt
文件。当然,这是一个黑客和维护噩梦,但我想它会起作用
还有其他可能的解决方案吗?比如说,我可以创建一个包含所有公共选项的文件并将其保存到根目录下,然后在每个proj-X/CMakeLists.txt
文件中执行类似于#include
的CMake>操作吗?如果运行相同的命令两次,是否会出现问题(从根目录开始构建时,在根目录下CMakeLists.txt
和proj-X/CMakeLists.txt
文件上分别打开一次)?您可能需要修改一些CMakeLists.txt文件
我建议看(幻灯片可用)
其要点是,您的所有项目都应该提供构建或编译所需的一切,本质上是构建需求和使用需求。要以可维护和可扩展的方式实现这一点,您必须远离变量并设置全局选项(add_compile_options
,include_directories
,等等),而是关注目标(target_compile_options
,target_include_directories
,等等)
因此,在您的例子中,proj-1/CMakeLists.txt
将提供一个目标(我们称之为proj::proj1
),用于设置适当的PUBLIC
和INTERFACE
选项(我指的选项是所需的编译器功能、依赖项、包括目录等)
一个抽象的例子:
project(proj1)
add_library(proj1 src.cpp)
# This are private include files, whoever uses this library does not need them
target_include_directories(proj1 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
# These are public, needed both by this target and by whoever uses it.
target_include_directories(proj1 PUBLIC
# This is used when building the target
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/public/include>
# This is used when the target is installed
$<INSTALL_INTERFACE:include>)
# Instead of asking directly for a language standard we ask for a compiler feature. We make this public so whoever depends on this target knows they also need this feature.
target_compile_features(proj1 PUBLIC cxx_strong_enums)
# As above, but this is needed only by this target during the build.
target_compile_features(proe1 PRIVATE cxx_lambdas)
# Add an alias, users can use target_link_libraries(target PRIVATE|PUBLIC proj::proj1) to add this target as a dependency (this will propagate all the PUBLIC include paths, compile options, compile features, dependencies, etc.
add_library(proj::proj1 ALIAS proj1)
项目(proj1)
添加库(proj1 src.cpp)
#这是私有的包含文件,任何使用此库的人都不需要它们
目标目录(proj1 PRIVATE${CMAKE\u CURRENT\u SOURCE\u DIR}/include)
#这些都是公共的,这个目标和使用它的人都需要。
目标目录(proj1公共目录)
#这在构建目标时使用
$
#这在安装目标时使用
$)
#我们没有直接要求语言标准,而是要求编译器功能。我们将其公开,以便依赖此目标的人知道他们也需要此功能。
目标编译功能(proj1公共cxx强枚举)
#如上所述,但这仅是该目标在构建期间需要的。
目标功能(proe1专用cxx\u lambdas)
#如果添加别名,用户可以使用target|link_库(target PRIVATE | PUBLIC proj::proj1)将此目标添加为依赖项(这将传播所有公共包含路径、编译选项、编译功能、依赖项等)。
添加库(proj::proj1别名proj1)
这是高度抽象的,这取决于您在构建脚本中实际执行的操作,很难给出比Daniel Pfeifer更好的解释,因此我建议您观看他的演讲或至少阅读幻灯片。这将使您的构建脚本更易于编写、阅读和使用
另一个很好的资源是。非常感谢,我将回顾这些幻灯片。不过:这是否意味着每个选项都应该放在自己的proj-X/CMakeLists.txt
文件中?如果我有10个不同的选项,它们都是通用的呢?在每个选项中重复这10个不同的选项似乎不是正确的方法文件。这确实有点问题。首先想到的方法是在根CMakeLists.txt
中的变量中添加公共选项,然后使用target.*
将它们添加到特定目标。但是,如果您想将一个项目编译为独立项目,您将没有这些选项。您可以使用interfa捆绑这些选项并与之链接的ce库,但问题是您将该库放在何处以及如何找到它?我不知道一种处理此问题的通用方法。一种替代方法是始终从根项目生成,但具有禁用您不需要的目标的选项。但如果您愿意,这将不起作用提供仅包含一个子项目的包。