Как находить библиотеки с помощью CMake?

290
27 декабря 2017, 21:14

У меня в проекте используются библиотеки Boost и WebRTC. При попытке собрать проект возникает проблема со сборкой WebRTC вот скриншот.

CMakeLists.cmake:

cmake_minimum_required(VERSION 3.9)
project(webrtc-server)
if(EXISTS "${CMAKE_SOURCE_DIR}/LocalConfig.cmake")
  include(LocalConfig.cmake)
else()
  message(FATAL_ERROR "Local config is absent")
endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
set (Boost_USE_MULTITHREADED ON)
set (Boost_USE_STATIC_LIBS ON)
set (Boost_USE_STATIC_RUNTIME OFF)
set (BOOST_ALL_DYN_LINK OFF)
include(CMake/CMakeFindExtensions.cmake)
include(CMake/CMakeHelpers.cmake)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
find_package(Boost 1.65.1 REQUIRED COMPONENTS program_options system)
find_package(WebRTC REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
include_directories(${WEBRTC_INCLUDE_DIR})
message(SOURSE " ${Boost_LIBRARIES}")
message(SOURSE " ${Boost_INCLUDE_DIRS}")
if(Boost_FOUND)
    add_executable(webrtc-server
            src/webrtc_server.cpp
            src/webrtc_observers.h
    )
    target_link_libraries(webrtc-server
            ${Boost_LIBRARIES}
            ${WEBRTC_LIBRARIES}
    )
endif()

LocalConfig.cmake:

set(BOOST_ROOT ExternalLibs/boost_1_65_1)
set(WEBRTC_ROOT_DIR ExternalLibs/WebRTC)

Tree :

.
├── CMake
│   ├── CMakeFindExtensions.cmake
│   ├── CMakeHelpers.cmake
│   └── FindWebRTC.cmake
├── CMakeLists.txt
├── ExternalLibs
│   ├── boost_1_65_1
│   └── WebRTC
├── LocalConfig.cmake
├── README.md
├── scripts
│   ├── install_boost.sh
│   └── install_webrtc.sh
├── src
│   ├── webrtc_observers.h
│   └── webrtc_server.cpp
└── temp

P.S. В шапке верная версия. Советую внимательно смотреть на регистр переменных - имеет очень важное значение.

Answer 1

Поиск библиотек в CMake происходит с использованием базовых команд самого CMake, для поиска по файловой системе. Это такие команды как: find_path, find_library и т.д. Обычному пользователю, как правило, эти команды не нужны, потому что уже кто-то заранее написал скрипт CMake, состоящий из этих команд, который находит всю необходимую информацию по библиотеке/фреймворку.

Обычно такие скрипты имеют вид FindXXX.cmake, где XXX это имя библиотеки. Эти скрипты используются тогда, когда пользователь в своём CMake скрипте использует команду find_package. К примеру, find_package(Boost REQUIRED) ожидает найти файл FindBoost.cmake и когда находит его, то исполняет всё, что находится внутри этого файла.

CMake поставляется с целым набором таких файлов, которые можно найти в директории, где он установлен: share/cmake-xxx/Modules. Имея это список файлов мы можем посмотреть, что за библиотеки поддерживаются CMake из коробки, а также посмотреть, что могут потребовать соответствующие скрипты на вход, чтобы помочь найти ту или иную библиотеку.

Итак, мы перешили в эту директорию и нашли FindBoost.cmake. Благо этот скрипт имеет неплохую документацию, и из него мы сразу узнаём, что для помощи в нахождении boost, ему необходимо знать где находится папка с оным. Для этого он ждёт переменную BOOST_ROOT. Эта переменная может быть установлена как локально в скрипте CMake, так и глобально, как переменная окружения.

Т.е. для того, чтобы нам найти boost, мы можем написать следующее:

set(BOOST_ROOT /home/koshachok/proj/ExternalLibs/Boost_1_65_1)
find_package(Boost REQUIRED COMPONENTS program_options system)

Но явно прописывать путь в общем файле это неправильно, лучше используйте переменную окружения или же некоторый обходной путь, который я опишу дополнительно позже.

Заметьте, что каждый скрипт уникален и то, что ожидает скрипт для boost, может отличаться от того, что требует другая библиотека. Поэтому всегда нужно смотреть документацию к скрипту, чтобы понять, чего он от тебя хочет. Если у скрипта хорошая документация, то всё сразу будет понятно. Если нет, тогда придётся из его содержимого понять самостоятельно, чего же он хочет (обычно это не так сложно).

Вооружившись всем вышеописанным идём искать FindWebRTC.cmake в директории CMake и не находим его. Что делать? Первым делом вбиваем в Яндекс FindWebRTC.cmake и, как правило, находим немало вариантов уже готового файла, один из котороых можно выбрать под свои нужды. Я взял первый попавшийся, и он ожидает установленной WEBRTC_ROOT_DIR в качестве помощи в поиске. Но как нам использовать этот файл, как сделать так, чтобы find_package его использовал? Очень просто: помещаем его в дерево исходников, скажем в 3rdParty/cmake. После чего добавляем в наш скрипт (до find_package) такую строку:

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdParty/cmake")

После чего, скрипт должен находиться и выполняться. Нам же остаётся использовать его результаты (WEBRTC_INCLUDE_DIR, WEBRTC_LIBRARIES).

Пару слов хочется сказать по поводу того, как и где прописывать полные пути к директориям библиотек, которые помогают скриптам в поиске. Для этого я использую следующий механизм. В основном скрипте CMake добавляем такой код:

if(EXISTS "${CMAKE_SOURCE_DIR}/LocalConfig.cmake")
   include(LocalConfig.cmake)
else()
   message(FATAL_ERROR "Local config is absent")
endif()

После чего добавляем файл LocalConfig.cmake со следующим содержимым:

set(BOOST_ROOT /home/koshachok/proj/ExternalLibs/Boost_1_65_1)
set(WEBRTC_ROOT_DIR /home/koshachok/proj/ExternalLibs/WebRTC)

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

READ ALSO
Реализация функций empty и clear для вектора

Реализация функций empty и clear для вектора

Правильно я сделала функции?

227
Кракозябры сообщений компилятора в QtCreator

Кракозябры сообщений компилятора в QtCreator

При использовании компилятора Microsoft в Qt-проекте в окне сборки выводятся сообщения об ошибках и предупреждениях с поломанной кодировкойНапример:

280
Реализация reserve для вектора

Реализация reserve для вектора

Правильно я сделала функцию?

212