#c #c #cmake
#c #c #cmake
Вопрос:
В моей конфигурации cmake несколько переменных зависят от переменной среды, чтобы быть правильно установленными. Эта переменная среды может измениться, и это означает, что кэш для cmake должен быть перестроен.
Моя конфигурация может обнаружить необходимость в этой перенастройке и обновить соответствующие записи кэша при вызове другого вызова «cmake» или «make rebuild_cache». Вызывается.
Однако я хотел бы, чтобы при каждом запуске make он автоматически проверялся на наличие изменений и при необходимости запускался целевой файл rebuild_cache.
Возможно ли это?
Ответ №1:
У Make нет памяти. У make нет способа «запомнить», на какое значение была установлена данная переменная среды при последнем запуске make.
Если вы не запишете переменную среды в файл.
Я никогда не использовал CMake, поэтому не знаю, как это лучше реализовать. Но на «необработанном» уровне make общая идея заключалась бы в:
1) напишите правило (скажем, envir_cache
), которое записывает переменную окружения в файл (названный, не совсем случайно, envir_cache
), если этот файл еще не существует, или файл существует, но его содержимое отличается от значения переменной окружения. (Что-то вроде if [ -f envir_cache ]
и read cached_var < envir_cache
и if [ "${myvar}" != "${cached_var}" ]
.)
2) сделайте цель rebuild_cache
зависимой от envir_cache
.
Таким образом, rebuild_cache
правило будет выполняться при первом запуске и всякий раз, когда переменная изменяется между запусками.
Комментарии:
1. Спасибо за ваш ответ; это кажется осуществимым, у меня просто не было времени опробовать это. Как только я это сделаю, я отмечу ответ как принятый.
Ответ №2:
Это нелегко сделать с помощью CMake, но пример того, как это сделать в виде модулей, включенных в CMake, показан ниже. Решение зависит от использования пользовательского целевого объекта, который выводит соответствующие переменные в файл и вызывает опцию cmake compare_files для сравнения предыдущего файла с файлом проверки и вызывает cmake для перестроения кэша в случае, если они не совпадают.
Решение включает в себя тщательно созданный модуль CMake include, который будет рекурсивно вызывать сам себя, чтобы проверить, что кэшированные значения не были изменены переменной среды. Если это так, он выполнит этап перестройки кэша, вызвав 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 file выполните следующие действия (используя Make-файлы Unix):
mkdir build
cd build
Следующий пример демонстрирует первоначальное создание Make-файлов Unix. Обратите внимание, что в этом случае переменные используют свои значения по умолчанию.
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 выше. Обратите внимание, что перестроение кэша не происходит.
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