Хороший стиль CMake: наследование свойств

Даниэль Пфайфер в своей презентации «Эффективный CMake» отмечает, что желательно избегать определений переменных, насколько это возможно.

Теперь о том, как получить свойства для различных целей сборки. То есть, например

   target_include_directories(base_IncludeFlags
                              INTERFACE 
                              first/dir
                              second/dir
                              ...)

определяет набор включаемых каталогов. Вместо того, чтобы определять одни и те же включаемые каталоги для target_a, target_b и target_c, я хотел бы позволить этим целям наследовать включаемые каталоги от 'base_target' с чем-то вроде

target_link_libraries(target_a PUBLIC base_IncludeFlags) 
target_link_libraries(target_b PUBLIC base_IncludeFlags)
target_link_libraries(target_c PUBLIC base_IncludeFlags)

где base_IncludeFlags не должен быть реальной физической целью, а скорее чем-то вроде абстрактного базового класса или интерфейса.

С другой стороны, я не хочу использовать include_directories, так как это влияет на все цели. Лучше использовать foreach? Каков самый элегантный способ сделать это? Должен ли я сделать base_target библиотеку и добавить зависимости?


person Frank-Rene Schäfer    schedule 31.07.2018    source источник
comment
Сделать base_target библиотекой и добавить зависимости? - Да, вы можете создать библиотеку INTERFACE, добавить в нее общие включаемые каталоги и связываться с библиотекой всякий раз, когда вам нужны эти общие включаемые каталоги.   -  person Tsyvarev    schedule 31.07.2018
comment
Если вы украсите свой ответ некоторым примером кода, я думаю, это будет решением.   -  person Frank-Rene Schäfer    schedule 01.08.2018
comment
Хм, на самом деле мой предыдущий комментарий был первой мыслью о тексте вопроса. Но я не совсем понимаю проблему, которую вы хотите решить. Согласно вашему коду, у вас уже есть цель base_target, которая может быть только библиотекой или исполняемым файлом (иначе вы не можете вызвать для нее target_inclide_directories). Если это библиотека, вы можете просто использовать для нее target_link_libraries. Если это исполняемый файл, почему вы хотите наследовать его свойства? Пожалуйста, уточните это. Шаблоны, предоставляемые CMake, предназначены не только для кода, но и для дизайна. Использование хорошего кода для плохого дизайна не так уж и хорошо.   -  person Tsyvarev    schedule 01.08.2018
comment
Я хочу цель, которая на самом деле не создается физически, но которая распространяет некоторые общие свойства.   -  person Frank-Rene Schäfer    schedule 01.08.2018
comment
Я хочу цель, которая на самом деле не создается физически, но которая распространяет некоторые общие свойства. - Да, это многое объясняет. Не могли бы вы добавить эту (или аналогичную) формулировку в свой вопрос?   -  person Tsyvarev    schedule 01.08.2018


Ответы (2)


Я хочу цель, которая на самом деле не создается физически, но которая распространяет некоторые общие свойства.

Именно для этого в CMake есть библиотека INTERFACE - контейнер для различных свойств, которые распространяются, когда эта библиотека связана с другой целью.

Пример:

# Create "container" target
add_library(base_target INTERFACE)

# Add some INTERFACE properties for that target
target_include_directories(base_target INTERFACE 
                          first/dir
                          second/dir)

# Some 'other_target' (library or executable) may easily consume all common properties:
target_link_libraries(other_target PUBLIC base_target)
# Now 'other_target' has aforementioned include directories too.
# Instead of PUBLIC other linking types (PRIVATE, INTERFACE) may be used.
person Tsyvarev    schedule 01.08.2018
comment
это работает только для свойств из белого списка. Пользовательские свойства нельзя распространять с помощью библиотеки INTERFACE. - person linuxUser123; 28.08.2019

Каков самый элегантный способ сделать это?

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

Если вы введете абстракции, скрытое неявное поведение любого рода, всем будет сложнее поддерживать файл CMake.

Для меня простым в данном случае будет означать копирование (дублирование) записей, если их всего 2-3. Если бы было больше библиотек, я бы поместил заголовки в переменную. В презентации "Эффективный CMake" рекомендуется избегать ненужных определений одноразовых переменных. Я бы сказал, что этот список заголовков будет полезной переменной, и его стоит создать.

person w-m    schedule 31.07.2018
comment
Для приложения 2-3, я думаю, подход "foreach" в вашем понимании. Что касается подхода к наследованию, «виртуальная библиотека», идентифицируемая по имени, например «XXX_include_flags_notalib», будет столь же прозрачной. - person Frank-Rene Schäfer; 01.08.2018