Может ли в Linux статическая библиотека использовать динамическую?
Пытаюсь сделать приложение и статическую библиотеку, которая использует ffmpeg. Фрагмент CMakeLists.txt для статической библиотеки:
find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
find_library(AVCODEC_LIBRARY avcodec)
find_path(AVFORMAT_INCLUDE_DIR libavformat/avformat.h)
find_library(AVFORMAT_LIBRARY avformat)
find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h)
find_library(AVUTIL_LIBRARY avutil)
find_path(AVDEVICE_INCLUDE_DIR libavdevice/avdevice.h)
find_library(AVDEVICE_LIBRARY avdevice)
add_library(prj STATIC ${SOURCE_LIB})
target_include_directories(prj PRIVATE ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ${AVDEVICE_INCLUDE_DIR})
target_link_libraries(prj ${AVCODEC_LIBRARY} ${AVFORMAT_LIBRARY} ${AVUTIL_LIBRARY} ${AVDEVICE_LIBRARY})
Всё собирается, nm показывает нужные мне функции:
U avformat_close_input
U avformat_find_stream_info
U avformat_free_context
U avformat_network_init
В CMakeLists.txt приложения:
add_library( libprj STATIC IMPORTED )
set_property( TARGET libprj PROPERTY IMPORTED_LOCATION /tmp/libprj.a )
add_executable(app ${SOURCE_EXE})
target_link_libraries(app libprj)
При сборке приложения множество сообщений о статической библиотеке, типа
ошибка: /tmp/libprj.a(prj.c.o): in function `st':
ошибка: undefined reference to `avformat_close_input'
Задумался. А так, вообще, можно делать? Или, искать ошибку в конфиге сборки?
Ответы (3 шт):
В общем, абсолютно чёткого понимания нет, но есть предположение. Если указать библиотеки ffmpeg при компоновке приложения, то всё нормально. Похоже на то, что, таки, статически прилинкованная библиотека никак не участвует в подгрузке динамической, просто ссылаясь на функции из неё. Собственно, учитывая, что статическая библиотека становится частью приложения, то, в принципе, логично, что именно оно и ответственнено за загрузку нужных .so.
Проблема в том, что библиотечные файлы ffmpeg реализованы средствами компилятора C, а не C++, а значит, в них отсутствует mangling. Отсюда и проблема поиска сигнатур C++ там где этих сигнатур нет.
Чтобы решить эту проблему достаточно включение заголовков ffmpeg, в коде программы, заключить в extern "C" { }.
Статические библиотеки представляют собой архив из собранных объектных файлов. Шаг линковки для них не выполняется. Он и не может выполняться, так как не известно, какие символы будут использоваться - это становится известно после того, как библиотека прилинкуется к бинарю. Соответственно и динамические библиотеки необходимо линковать к конечному бинарю. Причем на линукс есть проблема с порядком линковки - библиотеки, которые содержат недостающие символы, должны линковаться строго после единиц трансляции и библиотек, использующих эти символы.