当环境变量发生变化时,基于makefile的cmake项目会自动运行make rebuild_cache

时间:2011-05-24 17:18:06

标签: c++ c cmake

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

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

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

这可能吗?

2 个答案:

答案 0 :(得分:1)

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

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

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

1)写一个规则(比如,envir_cache)将环境变量写入文件(命名,不是那么重合,envir_cache), if 该文件不但是存在,文件存在,但其内容与环境变量的值不同。 (if [ -f envir_cache ]read cached_var < envir_cache以及if [ "${myvar}" != "${cached_var}" ]之类的内容。)

2)使目标rebuild_cache取决于envir_cache

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

答案 1 :(得分:0)

使用CMake并不容易做到这一点,但如下所示,作为CMake包含模块的示例如下所示。解决方案取决于使用自定义目标将有问题的变量输出到文件,并调用cmake compare_files选项将先前文件与验证文件进行比较,并调用cmake以在它们不匹配的情况下重建缓存。

该解决方案涉及精心设计的CMake包含模块,该模块将递归调用自身以验证环境变量未更改缓存的值。如果有,它将通过使用适当的参数调用cmake来执行重建缓存步骤,如下所示。预计您将使用Environment变量为您希望能够覆盖的每个变量调用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 Makefile):

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

以下示例显示如何将上面临时更改的变量恢复为默认值,并触发另一个变量以更改其值。请注意,当MYSTR变量获得提供的新值时,MYVAR变量将恢复为其默认值。

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