Хобрук: Ваш путь к мастерству в программировании

Транзитивные зависимости с различной привязкой к сторонним библиотекам

У меня немного запутанный вопрос. У меня есть сторонняя зависимость, которая поставляется в статической (libthird.a) и общей форме изображения (libthird.so).

У меня есть библиотека util, которая зависит от libthird.

И у меня есть приложения, зависящие от util, которые хотят связать libthird статически, и мне нужно создать несколько общих библиотек, которые зависят от util и должны связать libthird динамически.

Мой текущий (рабочий) подход выглядит примерно так:

add_library(third INTERFACE)
target_link_libraries(third INTERFACE /path/to/libthird.a)
add_library(third_shared INTERFACE)
target_link_libraries(third_shared INTERFACE /path/to/libthird.so)

add_library(util ${UTIL_SOURCES})
add_library(util_shared ${UTIL_SOURCES}) # same sources again!!
target_link_libraries(util PUBLIC third)
target_link_libraries(util_shared PUBLIC third_shared)

add_executable(some_app ...)
target_link_libraries(some_app PRIVATE util)

add_library(some_shared_object ...)
target_link_libraries(some_shared_object PUBLIC util_shared)

Это работает. Но я собираю util (и, на самом деле, еще полдюжины библиотек или около того) дважды... просто чтобы получить разные зависимости компоновщика. Есть ли более разумный способ сделать это в cmake?

Если я просто target_link_libraries() на верхнем уровне some_app и some_shared_object, я получу флаги компоновщика, выпущенные в неправильном порядке, поскольку util действительно зависит от third.

30.12.2017

  • Было бы возможно сделать util_shared тонкой оболочкой вокруг утилиты, или вы действительно привязаны к статической библиотеке утилит без -fPIC? 05.01.2018

Ответы:


1

Подход, который вы используете, определенно один из тех, которые я видел и сам использовал раньше. Хорошо, если он используется для небольшого архива и/или одноразового использования.

В следующих примерах я предполагаю следующую структуру проекта:

foo/
  CMakeLists.txt
  include/
    foo.h
  src/
    foo.c

Итак, я также (наивно?) использовал следующий подход, основанный на знании того, что вы можете создать (по крайней мере, в системах на базе Unix) разделяемую библиотеку из статического архива.

project(foo C)

set(SOURCES
  "src/foo.c")

set(LIBNAME "foo")

add_library(${LIBNAME} STATIC ${SOURCES})

target_include_directories(${LIBNAME} PUBLIC "include")
target_compile_options(${LIBNAME} PUBLIC "-fPIC")

#

get_property(CUR_PREFIX TARGET ${LIBNAME} PROPERTY PREFIX)
get_property(CUR_SUFFIX TARGET ${LIBNAME} PROPERTY SUFFIX)
get_property(CUR_NAME TARGET ${LIBNAME} PROPERTY NAME)
get_property(CUR_OUTPUT_NAME TARGET ${LIBNAME} PROPERTY OUTPUT_NAME)
get_property(CUR_ARCHIVE_OUTPUT_NAME TARGET ${LIBNAME} PROPERTY ARCHIVE_OUTPUT_NAME)

message(STATUS "prefix: ${CUR_PREFIX}")
message(STATUS "suffix: ${CUR_SUFFIX}")
message(STATUS "name: ${CUR_NAME}")
message(STATUS "output name: ${CUR_OUTPUT_NAME}")
message(STATUS "archive name: ${CUR_ARCHIVE_OUTPUT_NAME}")

add_custom_command(TARGET ${LIBNAME} POST_BUILD 
  COMMAND ${CMAKE_C_COMPILER} -shared -o libfoo.so -Wl,--whole-archive libfoo.a -Wl,--no-whole-archive
  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

Моя нерешенная проблема с этим подходом заключается в том, что я не нашел надежного и переносимого способа получить имя статического архива (libfoo.a). Следовательно, все эти message команды для целевых свойств; они могут вести себя по-разному на ваших платформах.


Самый эффективный способ, который также хорошо поддерживается cmake, — использовать библиотека объектов:

# cmake file

cmake_minimum_required(VERSION 3.2)

project(foo C)

set(SOURCES
  "src/foo.c")

set(LIBNAME "foo")
set(LIBNAME_OBJ "${LIBNAME}_obj")

add_library(${LIBNAME_OBJ} OBJECT ${SOURCES})

target_include_directories(${LIBNAME_OBJ} PUBLIC "include")
target_compile_options(${LIBNAME_OBJ} PUBLIC "-fPIC")

#

add_library(${LIBNAME} SHARED $<TARGET_OBJECTS:${LIBNAME_OBJ}>)
add_library(${LIBNAME}_static STATIC $<TARGET_OBJECTS:${LIBNAME_OBJ}>)

Все примеры были протестированы с cmake версии 3.6.1.

Надеюсь это поможет. Дайте нам знать, если вы нашли лучший способ.

05.01.2018
Новые материалы

Решения DBA Metrix
DBA Metrix Solutions предоставляет удаленного администратора базы данных (DBA), который несет ответственность за внедрение, обслуживание, настройку, восстановление базы данных, а также другие..

Начало работы с Блум
Обзор и Codelab для генерации текста с помощью Bloom Оглавление Что такое Блум? Некоторые предостережения Настройка среды Скачивание предварительно обученного токенизатора и модели..

Создание кнопочного меню с использованием HTML, CSS и JavaScript
Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

Внедрите OAuth в свои веб-приложения для повышения безопасности
OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

Классы в JavaScript
class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

Как свинг-трейдеры могут использовать ИИ для больших выигрышей
По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

Как построить любой стол
Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...