Перестроить зависимую цель после выполнения пользовательской цели - PullRequest
1 голос
/ 10 апреля 2020

У меня есть проект CMake, который использует внешний инструмент для создания специальных библиотек для определенной платформы. При запуске этого инструмента используется «файл конфигурации» для создания нескольких файлов, которые вставляются в параметры компилятора и компоновщика при сборке окончательной программы:

  • Библиотека объектов
  • Команда компоновщика файл, который связывает в нескольких предварительно скомпилированных библиотеках и вышеупомянутой объектной библиотеке
  • Файл опций make-файла, который устанавливает различные опции компилятора платформы

при изменении любого из этих файлов, основная программа должна быть полностью перестроенным, так как они являются неотъемлемыми c частями программы и включают в себя такие вещи, как флаги компилятора и системные компоненты.

Пока у меня есть что-то вроде этого, которое выглядит как рекомендуемый способ:

# run the external build tool to generate platform libs
# and compiler/linker option files
add_custom_command(
    OUTPUT ${LINKER_CMD_FILE} ${COMPILER_OPTS_FILE} ${PLATFORM_OBJECT_LIB}
    COMMAND "${EXTERNAL_BUILD_TOOL}"
    ARGS --config ${CFG_FILE}
    DEPENDS ${CFG_FILE}
    COMMENT "Invoking external build tool for ${CFG_FILE}"
)

add_custom_target(platform_libs
    DEPENDS ${LINKER_CMD_FILE} ${COMPILER_OPTS_FILE} ${PLATFORM_OBJECT_LIB}
)

....

add_executable(main_prog
    main.c
)

# whenever any of these change, rebuild
add_dependencies(main_prog platform_libs)

# add the platform compiler opts from the generated file
target_compile_options(main_prog PRIVATE
    @${COMPILER_OPTS_FILE}
)

Это также в значительной степени то, что делается в этом вопросе .

Когда я изменяю файл конфигурации, запускается цель platform_libs и генерирует библиотеку и другие файлы по мере необходимости. Однако, хотя запуск make main_prog действительно запускает сборку platform_libs правильно, он, похоже, не "замечает" каких-либо изменений и поэтому приходит к выводу, что ему не нужно фактически перестраивать основную программу.

Я всегда могу запустить make clean, но не здорово, что CMake полностью игнорирует изменения фундаментальных системных библиотек.

Как заставить main_prog пересобрать, если platform_libs запустился?

1 Ответ

0 голосов
/ 17 апреля 2020

[Центральный метод этого ответа взят из ответа @ KamilCuk в комментарии к вопросу].

Хитрость заключается в том, чтобы использовать одно из:

  • Установить свойство LINK_DEPENDS для нижестоящей цели (main_prog в примере) - это означает, что если файл в этом свойстве изменится, будет выполнена повторная ссылка.
  • Установите OBJECT_DEPENDS для каждого источника, используемого для main_prog .

В моем случае, поскольку ${COMPILER_OPTS_FILE} влияет на компиляцию каждого файла, мне понадобился метод OBJECT_DEPENDS. Если вы сделаете это, вам на самом деле не понадобится LINK_DEPENDS, так как вы будете перекомпилировать свои источники и в любом случае заново связать их, но я сделал оба для ясности смысла. Теоретически вы могли бы создать ситуацию, когда командный файл компоновщика изменяется, но не выбирает компилятор, и в этом случае вы можете пропустить повторную ссылку.

В моем случае мне нужно было сделать это не только для main_prog, но также и все остальные используемые библиотеки main_prog, поэтому я сохранил командные файлы компоновщика, а файл компилятора выбирает свойства цели в качестве цели platform_libs:

set_property(TARGET platform_libs
    PROPERTY MY_LINKER_CMD_FILE ${LINKER_CMD_FILE}
)
set_property(TARGET platform_libs
    PROPERTY MY_COMPILER_OPTS_FILE ${COMPILER_OPTS_FILE}
)

позже, без необходимости знать точные имена файлов (или даже иметь доступ к самим переменным):

# Retrieve the previously-stored options
# To do this, we only need the target name and the (fixed) property name
get_target_property(MY_LINKER_CMD platform_libs MY_LINKER_CMD_FILE)
get_target_property(MY_COMPILER_OPTS platform_libs MY_COMPILER_OPTS_FILE)

set_target_properties(main_prog PROPERTIES
    LINK_DEPENDS ${MY_LINKER_CMD}
)

# Also set as the linker cmd on the linker command line
# This depends on the linker, for GCC it's -Wl,T<file>
target_link_libraries(main_prog PRIVATE
    -Wl,-T${MY_LINKER_CMD}
)

# these are the sources that depend on the opts file
get_target_property(MAIN_SRCS main_prog SOURCES)

# set the dependency of source files on platform_libs
set_property(SOURCE ${MAIN_SRCS}
    PROPERTY OBJECT_DEPENDS ${MY_COMPILER_OPTS}
)
# Set as a compiler opt file
# For GCC: @<opt_file>
target_compile_options(${TARGET_TO_COMPILE} PRIVATE
    @${MY_COMPILER_OPTS}
)

# make sure the platform_libs is a dep
# or the compiler opts and linker files won't be generated
add_dependencies(main_prog platform_libs)

Примечательно, что в этом коде Cmake имена проектов main_prog и platform_libs могут быть переменными, и тогда вы можете превратить все это в функцию, которой просто нужны эти два имени проекта. Это облегчает повторное использование кода для компиляции библиотек с библиотекой platform_libs.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...