CMake 中用于依赖性跟踪的全局变量

发布于 2024-10-06 16:22:19 字数 911 浏览 0 评论 0原文

你好,

我在我的一个项目中使用 CMake 作为构建系统,该项目非常复杂。该项目包括多个库和多个应用程序。我的目标是,使以下成为可能:

  1. 库可以根据用户的请求构建(通过缓存的 CMake 变量实现)
  2. 应用程序根据用户的请求构建(见上文),但应用程序可以选择所需的库并构建它们,而无需用户选择它们
  3. 这不应更改缓存的用户选择要构建的库(如果应用程序构建关闭,则禁用自动构建库)

我的构建系统布局如下:我有一个包含 CMakeLists.txt 的父目录。 txt 将库和应用程序添加为子目录。每个库和应用程序都有自己的 CmakeLists.txt,它定义了要存储在缓存中的用户可定义的配置选项、要构建的目标以及它所依赖的项目的其他库。应用程序不一定位于父目录的下一个子目录中,但也可能低于某些级别,因此我无法使用 PARENT_SCOPE,因为父目录不必是最顶层的父目录,但必须知道依赖关系在上面。

我尝试将 GLOBAL 属性(如 PROJECT_BUILD_SOMELIBRARY 设置为 on)并尝试在 SOMELIBRARY 的 CMakeLists.txt 中检索它们来决定是否构建,但这些属性没有传递到库,因此即使实际上它也从未构建本来就必须这样做,因为另一个库或应用程序表明它依赖于这个库。使用包含每个应用程序或库目标名称的列表(取决于库)并在内部缓存该名称也不起作用。

总结一下这些话,我正在寻找一种方法来影响某个子目录中的 CMakeLists ,该子目录负责通过某个其他子目录中的 CMakeLists 来构建库(这不一定是与其他子目录相同的子目录级别)来构建该库,即使用户没有通过 cmake 调用时的配置选项显式指定它。

有人知道如何实现这一点吗?或者这对于 CMake 来说是不可能的吗?对于解决此问题的其他方法(包括使用 CMake)是否有建议?您知道还有其他构建系统可以轻松满足此要求吗?

非常感谢, 卷毛属

Hallo,

I'm using CMake as build system in one of my projects which is quite complex. The project includes several libraries and several applications. My goal is, to make the following possible:

  1. Libraries may be built on request by user (realised by cached CMake variable)
  2. Applications are built on request by user (see above), but an application may select which libraries are required and build them without the user selecting them
  3. This should not change the cached user selection on which libraries to build (to disable building the libraries automatically if the application building is turned off)

My build system layout is the following: I have a parent directory which contains a CMakeLists.txt that adds the libraries and applications as subdirectory. Each library and application has its own CmakeLists.txt which defines the user definable configuration options to be stored in cache, the targets to be built and on which other libraries of the project it depends. Applications are not necessarily located in the next subdirectory of the parent directory, but could also be some levels lower, so that I cannot make use of PARENT_SCOPE, because the parent hasn't to be the topmost parent, but the dependencies have to be known on top.

I tried setting GLOBAL properties like PROJECT_BUILD_SOMELIBRARY set to on and tried to retrieve them in SOMELIBRARY's CMakeLists.txt to decide whether to build or not, but the properties didn't get passed on to the library, so it never built even if it in fact would have had to, because another library or application indicated that it depended on this library. Using a LIST containing the name of each application or library target depending on a library and caching that one internally didn't work either.

To sum these many words up, I'm looking for a way to influence a CMakeLists in some subdirectory responsible for building a library by a CMakeLists in some other subdirectory (which isn't necessarily the same subdirectory level as the other subdir) to build that library, even if the user didn't specify it explicitly via the configuration option on cmake invocation.

Does someone know how this could be achieved or is this impossible with CMake? Are there suggestions for other approaches towards this problem that, however, include using CMake? Do you know of any other build system that could handle this requirements comfortably?

Many thanks,
crispinus

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

初心未许 2024-10-13 16:22:19

创建全局 CMake 变量的一种方法是:

set(EXAMPLE_INCLUDE_DIRS CACHE INTERNAL "include directories" FORCE)

当您想要附加或设置值时,请使用:

  set(EXAMPLE_INCLUDE_DIRS ${EXAMPLE_INCLUDE_DIRS } ${EXTRA_INCLUDE_DIRS }
CACHE INTERNAL "include directories") 

One way to make global CMake variables is:

set(EXAMPLE_INCLUDE_DIRS CACHE INTERNAL "include directories" FORCE)

Than when you want to append or set the value use:

  set(EXAMPLE_INCLUDE_DIRS ${EXAMPLE_INCLUDE_DIRS } ${EXTRA_INCLUDE_DIRS }
CACHE INTERNAL "include directories") 
你的他你的她 2024-10-13 16:22:19

我在网上创建了一个示例来尝试回答这个问题。你
应该能够从我的 GitHub 存储库下载它
bgoodrs-CMake-Examples。如果你点击那个
链接,您可以阅读该文档(该存储库中的 README.markdown )
试图做与我认为你相同的事情
想做。您可以单击下载按钮下载副本
本地实验的例子。如果没有达到目标,那么
对我的答案发表评论,我将尝试相应地改进该示例。

I created an example online that attempts to answer this question. You
should be able to download it my GitHub repository at
bgoodrs-CMake-Examples. If you click on that
link, you can read the document (README.markdown in that repository)
that attempts to do the same kinds of things that I think that you
want to do. You may click the download button to download a copy of
the examples for local experimentation. If that missed the mark, then
comment on my answer, and I'll try to improve the example accordingly.

心如荒岛 2024-10-13 16:22:19

在此期间我自己解决了这个问题。事实上,实现我上面解释的设置非常简单。我对所有目标使用了 EXCLUDE_FROM_ALL 选项,具体取决于用户是否显式选择它们(=忽略 EXCLUDE_FROM_ALL)。

EXCLUDE_FROM_ALL 选项的作用是,某个目标不包含在 all-Target 中,除非另一个目标(未标记为 EXCLUDE_FROM_ALL)依赖于此目标。这甚至适用于子目录,因为 CMake 目标实际上是全局的,甚至最顶层的父目录也知道最底层子目录的目标,甚至同一级别的子目录也知道另一个子目录的目标。

在我的布局中,项目的每个单独部分都包含自己的 CMakeLists.txt 并将其自己的选项添加到缓存中,因此示例子项目将如下所示:


SET(PART_NAME SAMPLE_PART)
SET(PART_TARGET_NAME samplepart)

SET(BUILD_${PART_NAME} off CACHE BOOL "Build part ${PART_NAME}")
SET(${PART_NAME}_FILES some_file.c another_file.c)

IF(NOT BUILD_${PART_NAME})
SET(EXCLUDE_${PART_NAME} EXCLUDE_FROM_ALL)
ENDIF(NOT BUILD_${PART_NAME})

ADD_LIBRARY(${PART_TARGET_NAME} SHARED ${EXCLUDE_SAMPLE_PART} ${PART_NAME}_FILES)
TARGET_LINK_LIBRARY(${PART_TARGET_NAME} some_other_target)

因此,如果用户选择 BUILD_SAMPLE_PART,则目标不会设置为 EXCLUDE_FROM_ALL 并且将被纳入所有;如果不是,目标将设置为 EXCLUDE_FROM_ALL,并且仅当另一个目标依赖于此时才会构建。如果构建了此目标,则还将构建“some_other_target”,无论它是否单独包含在 all 中。

I solved the problem by myself in meantime. In fact, it was quite straightforward to implement the setup I explained above. I used the EXCLUDE_FROM_ALL option to all targets depending on whether they were explicitly selected by user (=leave out the EXCLUDE_FROM_ALL) or not.

The EXCLUDE_FROM_ALL option has the effect that a target is not included in the all-Target, unless another target (which is not marked as EXCLUDE_FROM_ALL) depends on this target. This works even over subdirectories, because CMake targets are really global and even the topmost parent knows about the bottommost subdirectory's target, and even a subdirectory at the same level knows about the targets of another subdirectory.

In my layout, each separate part of my project contains its own CMakeLists.txt and adds its own options to the cache, so a sample subproject would look this way:


SET(PART_NAME SAMPLE_PART)
SET(PART_TARGET_NAME samplepart)

SET(BUILD_${PART_NAME} off CACHE BOOL "Build part ${PART_NAME}")
SET(${PART_NAME}_FILES some_file.c another_file.c)

IF(NOT BUILD_${PART_NAME})
SET(EXCLUDE_${PART_NAME} EXCLUDE_FROM_ALL)
ENDIF(NOT BUILD_${PART_NAME})

ADD_LIBRARY(${PART_TARGET_NAME} SHARED ${EXCLUDE_SAMPLE_PART} ${PART_NAME}_FILES)
TARGET_LINK_LIBRARY(${PART_TARGET_NAME} some_other_target)

So if the user chooses to BUILD_SAMPLE_PART, the target is not set to EXCLUDE_FROM_ALL and will be included in all; if not, the target is set to EXCLUDE_FROM_ALL and will be built only if another target depends on this. If this target is build, also the "some_other_target" will be built, whether it's included in all by itself or not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文