#cmake
#cmake
Вопрос:
Я понимаю назначение библиотек объектов, но почему для связывания его с целью необходимо использовать выражение генератора?
add_library(myObjects OBJECT a.cpp b.cpp) add_library(mainLib ${other_srcs}
lt;TARGET_OBJECTS:myObjects>) # Why not "PRIVATE myObjects" just like other files and targets?
Насколько я понимаю, выражения генератора полезны для оценки вещей, доступных только на этапе генерации. Почему это может быть так, что библиотеки объектов, которые представляют собой просто набор объектных файлов, и их местоположение не будут известны на этапе настройки?
Ответ №1:
В дополнение к тому, что уже сказал @Alex Reinking, расположение объектного файла само по себе может зависеть от конфигурации, например, с генератором «Ninja Multi-Config» объектные файлы цели t
находятся в <build-dir>/t/CMakeFiles/t.dir/<config>/<path-of-source-file-relative-to-dir-in-which-target-is-defined>/<src-file-name>.o
Итак, вы точно находитесь в ситуации, когда вы знаете местоположение только во время генерации, отсюда и необходимость выражения генератора.
Комментарии:
1. Интересно, почему то же самое не относится к не объектным библиотекам, созданным в середине конвейера.
2. @User10482 Что именно вы имеете в виду? Для библиотек, не являющихся объектами, конечное местоположение также разрешается только во время генерации, точно по той же причине — это может зависеть от конфигурации. Таким образом, не объектные библиотеки ведут себя точно так же.
3. Да, но им не нужно выражение генератора, как
OBJECT
библиотеке. Я могу связать их черезtarget_link_libraries
.4. @User10482 Как объяснил @KamilCuk в своем ответе, вы можете использовать
target_link_libraries
сOBJECT
библиотеками с 3.12. Однако по техническим причинам вам все еще иногда требуется$<TARGET_OBJECTS:tgt>
выражение генератора. Если у вас естьOBJECT
библиотекаo_base
и две библиотеки объектовo1
, иo2
обе они ссылаются наo_base
(не имеет значения, ссылаются ли ониPRIVATE
ly илиPUBLIC
ly) и исполняемый файл, который ссылается на обаo1
, иo2
вам все равно нужно будет вручную добавить$<TARGET_OBJECTS:o_base>
в исполняемый файл.5. Спасибо за быстрые ответы. Итак, это сводится к проектному решению, принятому разработчиками CMake, поскольку они смогли удалить это выражение генератора в случае, приведенном @KamilCuk.
Ответ №2:
add_library(mainLib ${other_srcs} $<TARGET_OBJECTS:MyObjects>) # Почему не «MyObjects», как и другие файлы и целевые объекты?
Итак:
add_library(mainLib ${other_srcs} myObjects)
Потому что это означало бы попытку найти файл с именем myObjects
и скомпилировать его. Файл не имеет расширений, поэтому cmake завершит работу, потому что файл не существует, и он все равно не знает, как его скомпилировать.
Если вы имели в виду:
add_library(mainLib ${other_srcs})
target_link_libraries(mainLib PUBLIC myObjects)
link_libraries
Зависимость от библиотек объектов не работала в более старом cmake, когда OBJECT
были введены библиотеки.
В документации по библиотекам объектов явно упоминается форма add_library(... $<TARGET_OBJECTS:...)
и отмечается, что, поскольку cmkae 3.12 target_link_libraries
может использоваться с библиотеками объектов.
Комментарии:
1. Однако связывание библиотеки объектов с
target_link_libraries
не всегда устраняет необходимость в$<TARGET_OJBECTS:tgt>
выражении генератора. Если у вас есть цельA
, которая ссылается на библиотеку объектовObj1
, которая сама ссылается на библиотеку объектовObj2
, которую вам нужно будет использоватьtarget_sources(A PRIVATE $<TARGET_OBJECTS:Obj2>)
в дополнение кtarget_link_libraries(A PRIVATE Obj1)
, потому что объекты не наследуются транзитивно.2. Ах, да, это то, что я имел в виду. Отредактировано. Итак, разработчики решили использовать выражение генератора, потому
link_libraries
что оно не работало в течение начального периода времени?3.
the developers decided to roll
спросите их.because link_libraries did not work during the initial time period?
cmake 3.11 не поддерживалсяtaget_link_libraries
с библиотеками объектов. Но это просто удобство, все же использованиеadd_library( $<TARGET_OBJECTS
было бы предпочтительным способом.
Ответ №3:
Почему это может быть так, что библиотеки объектов, которые представляют собой просто набор объектных файлов, и их местоположение не будут известны на этапе настройки?
Просто: target_sources
команда может использоваться для добавления источников (и, следовательно, объектов) к цели в любой момент. Если бы переменная была расширена немедленно, можно было бы пропустить объекты, которые были добавлены позже.
В сборках с несколькими конфигурациями во время настройки также неизвестно, ссылаетесь ли вы на объекты Debug или Release.
Представьте, что add_library(target a.cpp b.cpp)
создана переменная с именем target_OBJECTS
containing /path/to/a.o;/path/to/b.o
. Затем следующая последовательность демонстрирует проблему:
add_library(target a.cpp b.cpp)
add_executable(main main.cpp ${target_OBJECTS}) # (1)
# ... later ...
target_sources(target PRIVATE c.cpp)
# ... later ...
add_executable(utility util.cpp ${target_OBJECTS}) # (2)
Теперь, как бы (2) узнал об /path/to/c.o
этом? Вы могли бы target_sources
обновить эту переменную, но теперь у одной объектной библиотеки есть зависимые элементы, которые видят разные ее подмножества. Это ужасно сбивает с толку. Более того, (1) не будет видно c.o
, что, возможно, и желательно в этом примере, но это не всегда так. Возможно, ваш код просто организован для определения пользовательских команд для последующего создания сгенерированных источников.
Придание этому императивному, а не декларативному типу $<TARGET_OBJECTS:target>
, налагает на код CMake структуру, аналогичную требованию топологической сортировки целевых объектов в Makefile. Это также изменяет значение с «объектных файлов для этой цели» на «объектные файлы для этой цели на данный момент времени выполнения CMake«, что, строго говоря, более сложно рассуждать, не предлагая никаких выразительных преимуществ.
Если вы замените этот код поддержкой привязки библиотеки объектов CMake 3.12 , это выглядит еще более неприятно:
add_library(target a.cpp b.cpp)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE target) # (1)
# ... later ...
target_sources(target PRIVATE c.cpp)
# ... later ...
add_executable(utility util.cpp)
target_link_libraries(utility PRIVATE target) # (2)
Теперь, глядя на любой вызов target_link_libraries(... target)
, можно было бы разумно ожидать, что будут добавлены одни и те же объекты.
Комментарии:
1. Если аргументами для
target_sources
являются объектные файлы, указанные на этапе настройки, они должны быть доступны тогда. Точно так же, как цели для общих и статических библиотек, не так ли?2. Я обновил свой ответ примером, дополнительно демонстрирующим проблему. Неверно , что пути к объектным файлам известны во время настройки, во всяком случае, из-за генераторов с несколькими конфигурациями.