2015-11-30 2 views
0

Допустим, у меня есть компиляция кода в некоторый момент с cmake 2.8 на linux.Почему cmake компилирует все после git commit

Я изменяю файл «my_changed_file», запускаю cmake, и создается только этот файл. Все идет нормально.

Теперь я хочу, чтобы совершить это:

git add my_changed_file 
git commit 

Если я снова запустить CMake, я бы ожидать, ничего не происходит. Но все мои файлы перекомпилированы, несмотря на то, что я ничего не трогал! Временная метка кажется нетронутой, когда я делаю ls -l.

У меня есть такие строки:

execute_process(
    COMMAND git describe --abbrev=8 --dirty --always --tags 
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 
    OUTPUT_VARIABLE GIT_CODE_VERSION 
    OUTPUT_STRIP_TRAILING_WHITESPACE 
) 
add_definitions("-DCODE_VERSION=${GIT_CODE_VERSION}") 

Но это влияет только на файл main.cpp

Что происходит?

благодаря

ответ

3

CMake не отслеживает, что исходный файл может зависеть от конкретного определения компиляции. Когда определения компиляции изменений, CMake предполагает, что все источники должны быть восстановлены.

Лучше всего использовать сконфигурированный файл заголовка. Таким образом, когда содержимое этого файла изменяется, только те источники будут перекомпилировать, который включает этот файл (прямо или косвенно):

version.h.in:

#define CODE_VERSION @[email protected] 

main.cpp :

#include "version.h" 
... 

CMakeLists.txt:

# Calculate value of variable GIT_CODE_VERSION 
... 
configure_file("version.h.in" "version.h") 

Хорошая вещь с configure_file заключается в том, что она не обновляет временную метку полученного файла, если ее содержимое не будет изменено. Итак, если вы перезапустите cmake без git commit, ничто не будет перекомпилировано в следующей сборке. Только перезагрузка cmake после git commit заставит файл main.cpp (и только его) перекомпилировать в следующей сборке.


Другой способ заключается в использовании COMPILE_DEFINITIONS собственности на конкретных исходных файлов, а не цели-широкий один (который зависит от add_definition() вызова):

set_property(SOURCE main.cpp APPEND 
    PROPERTY COMPILE_DEFINITIONS "-DCODE_VERSION=${GIT_CODE_VERSION}") 

Изменение этого свойства через cmake вызов будет обнаружен постройте систему, поэтому следующая сборка перекомпилит main.cpp и только ее.

К сожалению, этот подход не работает должным образом в случае генераторов makefile: даже если определения компиляции изменяются для конкретного источника, все источники (для одной цели) будут перестроены.Это known limitation.

+0

привет. Я попробовал добавить или заменить мое add_definition с помощью set_property, но, похоже, он мало что делает. Есть ли что-то другое? Может быть, он будет помещен где-нибудь? Если я не укажу COMPILE_DEFINITIONS_ $ CONFIG, то это применимо к каждой конфигурации, правильно? Спасибо – Napseis

+1

Я обнаружил, что с исходным кодом COMPILE_DEFINITIONS не работает с генератором makefile (который вы используете). Но есть лучший подход, который использует файл заголовка configure. Я обновил свой ответ на этот случай. – Tsyvarev

+1

Чтобы уменьшить то, что восстанавливается еще больше, вместо того, чтобы регенерировать заголовок каждый раз при изменении данных фиксации git, поместите '@ GIT_CODE_VERSION @' в файл реализации (например, 'version.cpp.in') внутри тривиальной функции и скопируйте это файл с 'configure_file'. Заголовок затем содержит только прототип функции и никогда не изменяется. Результатом будет только то, что один файл реализации необходимо перестроить, а не каждый файл, который включает 'version.h'. –

Смежные вопросы