【问题标题】:Have makefile based cmake projects automatically run make rebuild_cache when an environment variable changes当环境变量更改时,让基于 makefile 的 cmake 项目自动运行 make rebuild_cache
【发布时间】:2011-09-01 03:22:38
【问题描述】:

在我的 cmake 配置中,几个变量依赖于环境变量才能正确设置。这个环境变量可以改变,这意味着应该重建cmake的缓存。

我的配置可以检测到重新配置的需要,并在调用“cmake”的另一个调用或调用“make rebuild_cache”时更新相应的缓存条目。

但是,我希望在我运行时自动检查更改,并在必要时运行rebuild_cache 目标。

这可能吗?

【问题讨论】:

    标签: c++ c cmake


    【解决方案1】:

    Make 没有记忆。 make 无法“记住”最后一次运行 make 时给定环境变量的设置。

    除非您将环境变量写入文件。

    我从未使用过 CMake,所以我不知道如何最好地实现它。但在“原始”制作级别上,一般的想法是:

    1) 编写一条规则(例如,envir_cache),将环境变量写入文件(命名,并非巧合,envir_cache),如果该文件尚不存在,或文件存在,但其内容与环境变量的值不同。 (类似于if [ -f envir_cache ]read cached_var < envir_cacheif [ "${myvar}" != "${cached_var}" ]。)

    2) 使目标rebuild_cache 依赖于envir_cache

    这样,rebuild_cache 规则将在第一次运行时执行,并且每当变量在运行之间发生变化时。

    【讨论】:

    • 感谢您的回复;这似乎可行,我只是没有时间尝试一下。我会尽快将答案标记为已接受。
    【解决方案2】:

    使用 CMake 不容易做到这一点,但下面显示了如何作为 CMake 包含模块执行此操作的示例。该解决方案依赖于使用自定义目标,该目标将相关变量输出到文件并调用 cmake compare_files 选项将前一个文件与验证文件进行比较,并在它们不匹配时调用 cmake 重建缓存。

    该解决方案涉及一个精心设计的 CMake 包含模块,该模块将递归调用自身以验证缓存值没有被环境变量更改。如果有,它将通过使用适当的参数调用 cmake 来执行重建缓存步骤,如下所示。预计您将为您希望能够使用环境变量覆盖的每个变量调用 add_option 宏(请参见下面的示例):

    # Capture the full path to this CMake module file
    if(NOT _option_cmake_file)
      set(_option_cmake_file ${CMAKE_CURRENT_LIST_FILE})
    endif()
    
    # When this CMake module is called as a script include the option file
    if(_option_verify)
      include(${_option_file})
    endif()
    
    # add_option macro for adding cached values you want to be able to
    # override with an environment variable of the same name
    # _name - variable name to use for the cached value
    # _type - type of cached variable
    # _description - description of cached variable for CMake GUI
    # _default - default value if no variable with same name is defined
    macro(add_option _name _type _description _default)
      # Define _option_file to be created if not in verify mode
      if(NOT _option_verify)
        set(_option_file ${CMAKE_BINARY_DIR}/${_name}.cmake)
      endif()
    
      # Determine the source for the alue of the cached variable
      set(_option_output "set(_name ${_name})")
      list(APPEND _option_output "\nset(_type ${_type})")
      list(APPEND _option_output "\nset(_description \"${_description}\")")
      if(DEFINED ENV{${_name}})
        set(${_name} $ENV{${_name}} CACHE ${_type} "${_description}" FORCE)
        list(APPEND _option_output "\nset(${_name} $ENV{${_name}})")
      elseif(${_name})
        set(${_name} ${${_name}} CACHE ${_type} "${_description}" FORCE)
        set(ENV{${_name}} ${${_name}}) # needed to pass from verify back to rebuild_cache
        list(APPEND _option_output "\nset(${_name} ${${_name}})")
      else()
        set(${_name} ${_default} CACHE ${_type} "${_description}" FORCE)
        list(APPEND _option_output "\nset(${_name} ${_default})")
      endif()
    
      # Create the _option_file (or verify file) containing the values
      # defined above
      execute_process(
        COMMAND ${CMAKE_COMMAND} -E echo ${_option_output}
        OUTPUT_FILE ${_option_output}${_option_verify})
    
      # If not in verify mode create check target to verify value
      if(NOT _option_verify)
        # Only create parent check-variables target once
        if(NOT TARGET check-variables)
          add_custom_target(check-variables ALL)
        endif()
        # Use this file as custom CMake target to verify variable value
        add_custom_target(check-${_name}
          COMMAND ${CMAKE_COMMAND}
          -D_option_verify:String=-verify
          -D_option_file:Filepath=${_option_file}
          -D_option_sdir:Path=${CMAKE_SOURCE_DIR}
          -D_option_bdir:Path=${CMAKE_BINARY_DIR}
          -P ${_option_cmake_file}
          COMMENT "Checking variable '${_name}' for changes"
          VERBATIM)
        # Add custom target as dependency for parent check-variables target
        add_dependencies(check-variables check-${_name})
      else()
        # Use cmake to compare options file and verify file created above
        execute_process(
          COMMAND ${CMAKE_COMMAND} -E compare_files
            ${_option_file} ${_option_file}${_option_verify}
          OUTPUT_VARIABLE COMPARE_OUTPUT
          ERROR_VARIABLE COMPARE_ERROR
          RESULT_VARIABLE COMPARE_RESULT)
        # Remove verify file
        file(REMOVE ${_option_file}${_option_verify})
        # If compare failed, then call CMAKE to rebuild_cache
        if(NOT COMPARE_RESULT EQUAL 0)
          # Perform the rebuild_cache step
          execute_process(
            COMMAND ${CMAKE_COMMAND} -H${_option_sdir} -B${_option_bdir})
        endif()
      endif()
    endmacro()
    
    # In verify mode? then call add_option macro to initiate the process
    if(_option_verify)
      # The values below come from the include(_option_file) above
      add_option(${_name} ${_type} "${_description}" ${${_name}})
    endif()
    

    如果上面的 CMake 模块被命名为 add_option.cmake,你可以按如下方式使用它:

    cmake_minimum_required(VERSION 2.8)
    project(Example)
    include(${PROJECT_SOURCE_DIR}/add_option.cmake)
    add_option(MYVAR
      BOOL
      "A boolean cached value that can be overridden by Environment variable"
      ON)
    add_option(MYSTR
      STRING
      "A string cached value that can be overridden by Environment variable"
      "some string")
    message(STATUS "MYVAR=${MYVAR}")
    message(STATUS "MYSTR=${MYSTR}")
    

    使用上面的 CMakeLists.txt 文件执行以下操作(使用 Unix Makefiles):

    mkdir build
    cd build
    

    以下示例演示了 Unix Makefile 的初始创建。请注意,在这种情况下,变量使用它们的默认值。

    cmake .. -G "Unix Makefiles"
    -- The C compiler identification is GNU 4.8.4
    -- The CXX compiler identification is GNU 4.8.4
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- MYVAR=ON
    -- MYSTR=some string
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/user/example/build
    

    以下示例显示了 make 如何调用上面的 add_option.cmake 模块创建的 check-variables 目标及其依赖目标。注意没有重建缓存发生。

    make
    Scanning dependencies of target check-MYVAR
    [ 50%] Checking variable 'MYVAR' for changes
    [ 50%] Built target check-MYVAR
    Scanning dependencies of target check-MYSTR
    [100%] Checking variable 'MYSTR' for changes
    [100%] Built target check-MYSTR
    Scanning dependencies of target check-variables
    [100%] Built target check-variables
    

    以下示例显示环境变量如何导致检查变量步骤之一失败并触发重建缓存事件。注意缓存重建过程中 MYVAR 值的变化。

    make MYVAR=off
    [ 50%] Checking variable 'MYVAR' for changes
    -- MYVAR=off
    -- MYSTR=some string
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/user/example/build
    [ 50%] Built target check-MYVAR
    [100%] Checking variable 'MYSTR' for changes
    [100%] Built target check-MYSTR
    [100%] Built target check-variables
    

    以下示例显示了如何将上面临时更改的变量恢复为默认值,并触发不同的变量来更改其值。请注意 MYVAR 变量恢复到其默认值,而 MYSTR 变量获得提供的新值。

    make MYSTR="hi mom"
    [ 50%] Checking variable 'MYSTR' for changes
    -- MYVAR=ON
    -- MYSTR=hi mom
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/user/example/build
    [ 50%] Built target check-MYSTR
    [100%] Checking variable 'MYVAR' for changes
    [100%] Built target check-MYVAR
    [100%] Built target check-variables
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-04
      • 2018-12-26
      • 1970-01-01
      • 1970-01-01
      • 2021-04-26
      • 2022-11-20
      • 1970-01-01
      相关资源
      最近更新 更多