Как правильно сконфигурировать CMakelist файл?

237
17 ноября 2021, 16:30

У меня есть два набора файлов (основной и дополнительный) и я хотел бы держать их отдетьно друг от друга.

Для первого набора(основного) такая конфигурация была сделана

set(libplayersource
        ....
        )
add_library( # Sets the name of the library.
        libplayer
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        ${libplayersource})

Для второго (дополнительного) вот такая

set(codec_source
        ...)
add_library(libcodec SHARED ${codec_source})

В итоге мне нужно все это залинковать

target_link_libraries( # Specifies the target library.
        libplayer
        libcodec)

Потом мне еще нужно добавить log библиотеку. Для этого мне нужно сначала ее найти и потом добавить

find_library( # Sets the name of the path variable.
        log-lib
        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

Редактирую target_link_libraries блок

target_link_libraries( # Specifies the target library.
        libplayer
        libcodec
        ${log-lib})

Все хорошо работает если вы собираетесь использовать log библиотеку в libplayer модуле, но если вы захотите использовать ее в libcodec модуле, то получите вот такую ошибку

undefined reference to `__android_log_print'

clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

Линкер не видит имплементации log либы для этого модуля. Нашел вот такой ответ на SO

https://stackoverflow.com/a/47803975/5709159

для того, чтоб все заработало мне нужно добавить в CMakeList блок

target_link_libraries( # Specifies the target library.
        libcodec
        ${log-lib}
        )

Теперь имплементация выглядит вот так

...
#Main module
set(libplayersource
        ....
        )
add_library( # Sets the name of the library.
        libplayer
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        ${libplayersource})
#Additional module
set(codec_source
        ...)
add_library(libcodec SHARED ${codec_source})
#Log lib
find_library( # Sets the name of the path variable.
        log-lib
        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)
#Linking
target_link_libraries( # Specifies the target library.
        libcodec
        ${log-lib}
        )
target_link_libraries( # Specifies the target library.
        libplayer
        libcodec
        ${log-lib})
...

То есть мне нужно указать log либу в двух модулях.

Вопрос - почему линкер не видит в libcodec, почему нужно добавлять дополнительный блок:

target_link_libraries( # Specifies the target library.
        libcodec
        ${log-lib}
        )

чтоб сделать эту либу видимой для libcodec модуля?

P.S. В VisualStudio если у тебя есть проект А и две либы В и С то ты их включаешь в проект и все, можно в В использовать С и так далее. Тебе не нужно для того, чтоб методы из С использовать в В добавлять С в В, достаточно того, что эти две либы включены в основной проект А.

Answer 1

Чтобы то, что написано работало как задумано:

target_link_libraries(libcodec ${log-lib} )
target_link_libraries(libplayer libcodec)

Можно сделать две вещи: либо прописать libcodec как статическую библиотеку, либо доступ к зависимостям libcodec сделать публичным:

target_link_libraries(libcodec PUBLIC ${log-lib} )

Собственно почему не работает с SHARED и без PUBLIC - эти зависимости попадают в INTERFACE_LINK_LIBRARIES, что не даёт явной линковки либ, а только отмечает, что она может потребоваться.

Небольшое замечание к коду. Не используйте в основном проекте find_library(log-lib log). Сделайте FindLog.cmake, если log-lib это сторонний не cmake проект, а если это ваш проект - сделайте нормальный экспорт конфигурации. Тогда

find_package(LogLib)
target_link_libraries(libcodec PUBLIC log::log)

избавит от необходимости искать файл либы и добавлять путь до хедеров.

Answer 2

Так посмотрите документацию target_link_libraries().

Первый аргумент -- таргет, к которому линкуете остальные аргументы -- таргеты библиотек. Соответственно, 1 вызов линкует log_lib к libcodec, а второй -- libcodec и log_lib к libplayer.

Без первого вызова вы к libcodec ничего не линкуете, поэтому получаете ошибку.

READ ALSO
Двоичный код, как разделить по 4 символа

Двоичный код, как разделить по 4 символа

Я не понимаю как грамотно сделать, что бы при выводе ответа - символы делились по 4 части (не так(10101010) -> а вот так (1010 1010))

270
Считывание с клавиатуры в Windows Forms С++

Считывание с клавиатуры в Windows Forms С++

Как считать символ введенный с клавиатуры в Windows Forms С++(без из пользования консоли)?

153
Русские буквы в пути к файлу C++

Русские буквы в пути к файлу C++

Если пытаюсь прочитать где только английские символы в пути файл читается но если где русские ошибка открытиянапример

116
найти слова которое начинается с согласной буквы в массиве символов

найти слова которое начинается с согласной буквы в массиве символов

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

187