当环境变量更改时,让基于 makefile 的 cmake 项目自动运行 make rebuild_cache

Posted

技术标签:

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

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

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

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

这可能吗?

【问题讨论】:

【参考方案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

【讨论】:

以上是关于当环境变量更改时,让基于 makefile 的 cmake 项目自动运行 make rebuild_cache的主要内容,如果未能解决你的问题,请参考以下文章

Makefile引用与环境变量

JDK版本更改,修改环境变量不生效

开发环境Windows 系统中使用 Makefile 构建脚本编译 C 程序 ( 下载并安装 TDM-GCC 编译器 | 配置环境变量 | 编译 Makefile 程序 )

除了更改环境变量“PATH”之外,您还需要做啥才能让 Eclipse 识别 MinGW?

用于在头文件更改时构建简单 c 项目重新编译的示例 makefile

makefile 变量前后加 @是啥意思?例如 prefix=@prefix@