[Центральный метод этого ответа взят из ответа @ 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
.