Подтвердить что ты не робот

Transitive target_include_directories в библиотеках OBJECT

Вот фрагмент из make CMakeLists.txt:

add_library(foo-object OBJECT src/foo.cpp)
target_include_directories(foo-object PUBLIC include)
add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
add_library(foo_static STATIC $<TARGET_OBJECTS:${PROJECT_NAME}-object>)

Теперь все работает нормально, генерируются обе библиотеки. Однако у меня есть проблема, когда я пытаюсь его использовать:

add_executable(bar src/main.cpp)
target_link_libraries(bar foo)

Target bar не компилируется, потому что не включаются каталоги из foo-объекта. Если я добавлю target_include_directories непосредственно на foo, все будет прекрасно компилироваться.

Как я могу автоматически использовать как foo, так и foo_static (и пересылать вещи в зависимости от них), включая каталоги из foo-object?

4b9b3361

Ответ 1

Hm, на данный момент я придумал следующее:

add_library(foo-object OBJECT src/foo.cpp)
target_include_directories(foo-object PUBLIC include)

get_property(object_include_dirs TARGET foo-object PROPERTY INCLUDE_DIRECTORIES)
get_property(object_link_libs TARGET foo-object PROPERTY LINK_LIBRARIES)

add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo PUBLIC ${object_include_dirs})
target_link_libraries(foo PUBLIC ${object_link_libs})

add_library(foo_static STATIC $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo_static PUBLIC ${object_include_dirs})
target_link_libraries(foo_static PUBLIC ${object_link_libs})

но давайте, должен быть лучший способ:/

Ответ 2

Кажется, что транзитивные свойства работают только тогда, когда цели связаны цепочкой вызовов target_link_library. В вашем случае у вас нет такой связи между foo-object и foo.

Если вы добавите исходный файл в foo, то также не сможете увидеть каталог include из foo-object.

Это может быть недосмотр в дизайне библиотек OBJECT, поскольку он существенно нарушает транзитивные свойства для них.

Ответ 3

На CMake <3.12 используйте следующее:

add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo
    PRIVATE
    $<TARGET_PROPERTY:${PROJECT_NAME}-object,INTERFACE_INCLUDE_DIRECTORIES>)

На CMake> = 3.12 взгляните на этот ответ (спасибо @ian5v за предложение)


Как это устроено:

target_include_directories(...)

...

Элементы PUBLIC и INTERFACE будут заполнять свойство INTERFACE_INCLUDE_DIRECTORIES элемента <target>.

Поэтому ${PROJECT_NAME}-object имеет установленный INTERFACE_INCLUDE_DIRECTORIES. Нам нужно извлечь это свойство и вставить его в наш собственный путь включения.

Это похоже на работу для "генератора выражений" ! В частности, $<TARGET_PROPERTY:tgt,prop> выглядит так, как будто он здесь пригодится.

Наш tgt будет ${PROJECT_NAME}-object, и мы пытаемся извлечь все значения из INTERFACE_INCLUDE_DIRECTORIES, поэтому INTERFACE_INCLUDE_DIRECTORIES будет prop.

Это относится к $<TARGET_PROPERTY:${PROJECT_NAME}-object,INTERFACE_INCLUDE_DIRECTORIES>, который именно то, что мы использовали в приведенном выше коде.