使用CMake缓存变量"之前"定义

时间:2017-11-14 16:41:29

标签: cmake

可以从几乎所有地方设置CMake缓存变量(请参阅@ Florian' s What's the CMake syntax to set and use variables?)。我假设设定值在任何地方都可见,甚至是之前解析过的CMake列表,但事实并非如此。

用例

  • 模块A使用${CMAKE_MYDEF}
  • 模块B设置缓存变量CMAKE_MYDEF
  • add_subdirectory(A)之前调用
  • add_subdirectory(B)

显示行为的简短示例

cmake_minimum_required(VERSION 3.7)
project(test)
add_executable(EXEC test.cpp)
target_compile_definitions(EXEC PRIVATE MYDEF=${CMAKE_MYDEF})
set(CMAKE_MYDEF "MyValue" CACHE STRING "")

问题

  • 无论我添加模块A和模块B的顺序如何,我如何确保CMAKE_MYDEF具有所需的值?
  • 有没有办法确保CMake配置步骤重新运行两次,或者,如果适用,只要缓存变量发生变化? (这可能不是一个干净的解决方案,但由于我使用遗留代码并不是一切都可以完美地完成。)
  • 如果不手动重新运行CMake配置,是否有缓存变量的替代方法可以实现相同的结果?
  • 是否可以在生成阶段设置编译器定义(即,当所有CMake缓存变量都已知并设置时)?使用某种生成器表达式?

编辑:简短示例解决方案

按照@ Florian的回答,这里显示了解决方案的改编示例:

cmake_minimum_required(VERSION 3.7)
project(test)
add_executable(EXEC test.cpp)
target_link_libraries(EXEC MyOtherLib)

add_library(MyOtherLib INTERFACE)
set(CMAKE_MYDEF "MyValue" CACHE STRING "")
target_compile_definitions(MyOtherLib INTERFACE MYDEF=${CMAKE_MYDEF})

2 个答案:

答案 0 :(得分:1)

CMake处理脚本顺序,从顶级CMakeLists.txt开始并逐个执行其行。

因此,如果在分配变量之前读取变量,则不会得到任何结果。该场景中唯一具体的 CACHE 变量可能是在之前的cmake调用中分配该变量。

在分配之前使用变量需要占据一席之地通常会发出关于糟糕设计的信号。在许多情况下(即使使用遗留代码),可以优雅地修复设计。

强制CMake重新配置项目可以完成,例如touching current script

  

强制重新配置,可以" cmake -E touch"   在目标构建期间以某种方式CMAKE_CURRENT_LIST_FILE   或者其他一些。

答案 1 :(得分:1)

是的,我完全使用@Tsyvarev's answer,CMake的解析器按顺序工作。所以变量 - 甚至是缓存的 - 或生成器表达式 - 无法读取变量 - 在这里都不好。

我只想根据A和B之间的依赖关系添加使用目标和目录属性的可能性:

  1. A取决于B时,例如

    target_link_libraries(A PUBLIC B)
    

    然后一个简单的

    target_compile_definitions(B PUBLIC MYDEF=SOME_DEF)
    

    会将必要的定义传播到A

  2. B取决于AA已知时,

    target_link_libraries(B PUBLIC A)
    target_compile_definitions(A PUBLIC MYDEF=SOME_OTHER_DEF)
    
  3. 如果您正在使用子目录,我建议将定义全局放在根CMakeLists.txt中:

    add_definitions(-DMYDEF=GLOBAL_DEF)
    
  4. 最后,包含子目录的完整变体允许B决定该怎么做:

    <强>的CMakeLists.txt

    cmake_minimum_required(VERSION 3.7)
    
    project(test)
    
    add_subdirectory(A)
    add_subdirectory(B)
    

    :一种\的CMakeLists.txt

    file(WRITE a.cpp [=[
    #include <iostream>
    
    #ifndef MYDEF
    #define MYDEF "Hello from A!"
    #endif
    
    void a()
    {
        std::cout << MYDEF << std::endl;
    }
    ]=])
    
    add_library(A a.cpp)
    

    <强>乙\的CMakeLists.txt

    file(WRITE b.cpp [=[
    
    void a();
    
    void main()
    {
        a();
    }
    ]=])
    
    add_executable(B b.cpp)
    target_link_libraries(B A)
    
    if (TARGET "A")
        target_compile_definitions(A PRIVATE MYDEF="Hello from B!")
    else()
        set_property(
            DIRECTORY ".." 
            APPEND PROPERTY 
                COMPILE_DEFINITIONS "MYDEF=\"Hello from Global!\""
        )
    endif()
    
  5. 参考