Может ли одна целевая ссылка CMake против * разделяемой * версии другой целевой библиотеки? - PullRequest
5 голосов
/ 16 апреля 2020

У меня есть проект с базовой библиотекой (LibA в примере ниже), исполняемым файлом и второй библиотекой (LibB), которая зависит от первой библиотеки. Вторая библиотека (LibB) всегда встроена в общую (динамическую c библиотеку) форму.

Есть ли способ заставить LibB всегда ссылаться на shared версия LibA?

Вот небольшой CMakeLists.txt файл, иллюстрирующий проблему:

cmake_minimum_required(VERSION 3.16)

project(my_project LANGUAGES CXX)

# LibA should be buildable in either static or shared form.
add_library(LibA A.cpp)
# In the real case, there are many customizations to `LibA`: 
# compile flags, include dirs, target properties, etc.

add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibA)

# I want library myB to *always* link against the dynamic library libLibA.so.
add_library(LibB SHARED B.cpp)
target_link_libraries(LibB PUBLIC LibA m pthread)

Он может быть построен с помощью следующих команд:

echo 'int main() {}' > main.cpp
touch A.cpp B.cpp
mkdir -p build 
cmake -B build/ -S .
cmake --build build/

Я знаю, что могу заставить LibA всегда делиться с add_library(LibA SHARED A.cpp), но я хочу иметь возможность собрать LibA в виде библиотеки c.

Настоящий контекст для этого заключается в том, что у меня есть базовая библиотека (LibA), и я хочу статически ссылаться на нее при создании исполняемых файлов, но динамически (как LibA.so) ссылаться на нее при создании модуля расширения Python ( LibB.so).

Ответы [ 2 ]

5 голосов
/ 19 апреля 2020

Это невозможно, libA может быть только stati c или Dynami c, но не оба.

Вам необходимо иметь две версии libA, одну динамику c одна стати c:

cmake_minimum_required(VERSION 3.16)

project(my_project LANGUAGES CXX)

function( addLibA suffix type )

    set( libname LibA${suffix} )
    add_library(${libname} ${type} A.cpp)

    # specify library properties here

endfunction()

# LibA should be buildable in either static or shared form.
addLibA("s" STATIC)
addLibA("" SHARED)
# In the real case, there are many customizations to `LibA`: 
# compile flags, include dirs, target properties, etc.

add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibAs)

# I want library myB to *always* link against the dynamic library libLibA.so.
add_library(LibB SHARED B.cpp)
target_link_libraries(LibB PUBLIC LibA m pthread)
3 голосов
/ 24 апреля 2020

Для того, что вы конкретно запрашиваете, потребуется несколько целей, как уже упоминалось в комментариях / ответе jpo38

Однако вам может быть интересно использовать Библиотеки объектов в CMake для совместного использования объектов. между целью библиотеки и исполняемой целью. Например:

cmake_minimum_required(VERSION 3.16)

project(my_project LANGUAGES CXX)

# Objects get built exactly once
add_library(LibA.objects OBJECTS 
  A.cpp
)
target_compile_commands( ... )
target_include_directories( ... )

# Shared library for libA
add_library(LibA SHARED
  $<OBJECTS:LibA.objects>
)

# LibB -- always shared, always linked against dynamic LibA
add_library(LibB SHARED
  B.cpp
)
target_link_libraries(LibB PUBLIC LibA)

# ExecutableA, built using LibA's objects 
# (effectively the same linking a static LibA.a)
add_executable(ExecutableA
  main.cpp
  $<OBJECTS:LibA.objects>
)

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

Это позволяет ExecutableA иметь встроенные в него объекты LibA, поэтому он ведет себя эффективно, как если бы вы статически были связаны в LibA.a. В этом случае LibA теперь явно создается как библиотека SHARED, так как это необходимо для LibB для динамического связывания с.

Если вы используете более новые версии CMake, вы также можете избегайте выражения генератора $<OBJECTS:...> и просто связывайте объектную библиотеку напрямую с помощью target_link_libraries - например:

target_link_libraries(libA PRIVATE LibA.objects)
...
target_link_libraries(ExecutableA PRIVATE LibA.objects)

Этот подход также позволит применять свойства один раз к их соответствующим целям. Любые свойства, касающиеся самих исходных файлов, просто необходимо применить непосредственно к библиотеке объектов. Любые свойства, относящиеся к настройке / макету библиотеки (например, расположение вывода, суффиксы и т. Д. c), применяются строго к целям библиотеки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...