【问题标题】:Global variables in CMake for dependency trackingCMake 中用于依赖跟踪的全局变量
【发布时间】:2010-12-07 01:06:23
【问题描述】:

你好,

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

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

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

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

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

有人知道如何做到这一点,或者这对 CMake 来说是不可能的吗?是否有针对此问题的其他方法的建议,但是,包括使用 CMake?您是否知道任何其他构建系统可以轻松处理此要求?

非常感谢, 脆皮鱼

【问题讨论】:

    标签: variables dependencies cmake global


    【解决方案1】:

    制作全局 CMake 变量的一种方法是:

    set(EXAMPLE_INCLUDE_DIRS CACHE INTERNAL "include directories" FORCE)
    

    比当你想追加或设置值时使用:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 感谢您非常详尽的回答。据我所知,您的解决方案朝着不同的方向发展,因为我不能省略 add_subdirectory,因为每个部件子目录中的 CMakeLists.txt 都包含缓存选项,该选项将使该部件的目标生成与否。无论选择要构建哪些部分,都必须添加每个子目录。
      【解决方案3】:

      与此同时,我自己解决了这个问题。事实上,实现我上面解释的设置非常简单。我对所有目标使用了 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,target不会设置为EXCLUDE_FROM_ALL,会被包含在all中;如果不是,则目标设置为 EXCLUDE_FROM_ALL 并且仅当另一个目标依赖于此时才会构建。如果这个目标被构建,那么“some_other_target”也将被构建,无论它是否被包含在所有对象中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-22
        • 1970-01-01
        • 2015-04-15
        • 1970-01-01
        • 2013-01-09
        • 2019-06-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多