CMake find_* не ищет подкаталоги

#c #linux #cmake #cross-compiling

#c #linux #cmake #перекрестная компиляция

Вопрос:

Я довольно долго пытался заставить мой набор инструментов для кросс-компиляции из моего WSL Ubuntu в RasberryPi работать. Поскольку версия GCC моего RaspberryPi 4B 8.3.0, я совсем недавно пытался использовать набор инструментов Buster из здесь. Моя текущая структура папок выглядит следующим образом:

 Test
  -> CMakeLists.txt
  -> main.cpp
Toolchain
  -> arm-linux-gnueabihf
  -> bin
  -> include
  -> lib
  -> libexec
  -> share
raspi_root
  -> lib
  -> usr
  

Тестовая папка содержит простой тестовый проект для запуска набора инструментов. Реальный целевой проект немного больше. Набор инструментов — это набор инструментов для кросс-компиляции, загруженный из репозитория, и, наконец, папка raspi_root является копией из lib и usr папок из Raspberry Pi.
The main.cpp выглядит довольно просто:

 #include <iostream>
#include <bluetooth>

int main(int argc, char** argv)
{
    std::cout << "Hello World" << std::endl;
}
  

Обратите внимание, что он включает заголовок Bluetooth, поскольку это одна из библиотек, с которыми у меня возникают проблемы.

Мой CMakeLists.txt выглядит так:

 set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

SET(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREF "/home/user/workspace/toolchain/bin/arm-linux-gnueabihf-")
SET(CMAKE_C_COMPILER "${COMPILER_PREF}gcc")
set(CMAKE_CXX_COMPILER "${COMPILER_PREF}g  ")

set(SYSROOT "${SOURCE_DIR}/../raspi_root")
set(CMAKE_FIND_ROOT_PATH "${SYSROOT}")
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

cmake_minimum_required(VERSION 3.0) # setting this is required

set(project_target Test)
project(${project_target})            # this sets the project name

set(SOURCES main.cpp)

find_library(BLUETOOTH bluetooth REQUIRED)

add_executable(${project_target} ${SOURCES})
set_property(TARGET ${project_target} PROPERTY CXX_STANDARD 17)

target_link_libraries(${project_target} PUBLIC
    # ${SYSROOT}/usr/lib/arm-linux-gnueabihf/libbluetooth.so
    ${BLUETOOTH}
)
  

Я старался сделать это как можно проще, чтобы заставить его скомпилировать мою программу hello world с помощью набора инструментов и связать библиотеку Bluetooth, чтобы заставить ее работать на моем Raspberry Pi.

Теперь возникает следующая проблема: Когда я делаю cmake . , он не находит файлы библиотеки Bluetooth:

 Please set them or make sure they are set and tested correctly in the CMake files:
BLUETOOTH
    linked by target "Test" in directory /home/user/workspace/Test
  

Они находятся прямо под ${SYSROOT}/usr/lib/arm-linux-gnueabihf
Найдены только библиотеки в традиционных каталогах, таких как ${SYSROOT}/usr/lib или ${SYSROOT}/lib . Когда я создаю символическую ссылку из одного из этих каталогов на libbluetooth.so похоже, что cmake находит библиотеку, хотя позже при связывании я получаю дополнительные ошибки.
Я также попытался заменить, find_library указав полный путь к библиотеке под target_link_libraries , но затем библиотека найдена, но заголовки, конечно, отсутствуют. Я полагаю, они должны быть включены отдельно.

Однако мой вопрос в том, почему find_* функция CMake не просматривает другие подкаталоги? Это также происходит при связывании boost-библиотек. find_package(boost) находит заголовки, но не связывает библиотеки.

___ РЕДАКТИРОВАТЬ: ___

Благодаря Цывареву я смог успешно скомпилировать и выполнить свою программу hello world. Теперь для следующего шага я хотел включить библиотеку boost thread, которая вызвала большинство проблем в моем другом проекте. Итак, я добавил #include <boost/thread.hpp> в свой main.cpp и find_package(Boost COMPONENTS thread REQUIRED) , ${Boost_INCLUDE_DIRS} в target_include_directories и ${Boost_LIBRARIES} в target_link_libraries в моем CMakeLists.txt . Теперь он находит мои библиотеки с помощью cmake . -DCMAKE_TOOLCHAIN_FILE=Toolchain и генерирует файлы сборки. Но с make я получаю следующие ошибки связывания:

 <path to toolchain linker>/ld: warning: librt.so.1, needed by ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so, not found (try using -rpath or -rpath-link)
<path to toolchain linker>/ld: warning: libpthread.so.0, needed by ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so, not found (try using -rpath or -rpath-link)
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_setspecific@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_condattr_setclock@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_key_create@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_join@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_detach@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_getspecific@GLIBC_2.4'
<path to toolchain linker>/ld: ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so: undefined reference to `pthread_create@GLIBC_2.4'
<path to toolchain linker>/ld: /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_chrono.so: undefined reference to `clock_gettime@GLIBC_2.4'
  

Я полагаю, что неопределенные ссылки будут разрешены, как только библиотеки будут найдены правильно? CMakeCache.txt говорит, что найденная библиотека потоков libpthread.a нет libpthread.so . Также при запуске make VERBOSE=1 это команда связывания (с перерывами для удобства чтения):

 /home/felix/workspace/toolchain/bin/arm-linux-gnueabihf-g      
    -rdynamic CMakeFiles/Test.dir/main.cpp.o  
    -o Test
    -Wl,-rpath,/home/felix/workspace/Test/../raspi_root/usr/lib/arm-linux-gnueabihf:/home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf
    ../raspi_root/usr/lib/arm-linux-gnueabihf/libboost_thread.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_chrono.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_system.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_date_time.so
    /home/felix/workspace/raspi_root/usr/lib/arm-linux-gnueabihf/libboost_atomic.so
    ../raspi_root/usr/lib/arm-linux-gnueabihf/libpthread.a
    ../raspi_root/usr/lib/arm-linux-gnueabihf/libbluetooth.so
  

Нужно ли мне выполнять поиск в CMake в общих библиотеках вместо статических? Как бы я это сделал? Если нет, то чего мне не хватает?

Спасибо за вашу помощь.

Комментарии:

1. «Однако мой вопрос в том, почему функция CMake find_ * не просматривает другие подкаталоги?» — Потому что это разработано так . Механизм поиска find_library и других find_* функций не является рекурсивным . Известны системные установочные префиксы типа /usr , библиотечные префиксы типа lib/ , поэтому CMake ищет только там. Если вы хотите, чтобы CMake выполнял поиск в ${SYSROOT}/usr/lib/arm-linux-gnueabihf , добавьте соответствующий каталог для поиска. Например. set(CMAKE_LIBRARY_PATH "/usr/lib/arm-linux-gnueabihf") .

2. Также обратите внимание, что в CMake настройки набора инструментов обычно отделены от CMakeLists.txt файла. Строки от SET(CMAKE_SYSTEM_NAME ...) до SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ...) обычно находятся в файле toolchain , который задается -DCMAKE_TOOLCHAIN_FILE=<path/to/file> параметром cmake . Дополнительную информацию см. в документации по кросс-компиляции.

3. Прежде всего, большое вам спасибо за быстрый ответ! Что касается разделения набора инструментов, я сделал так, как вы рекомендовали. Насколько я понимаю, это просто служит для того, чтобы иметь общий файл cmake для первоначальной сборки проекта, и в зависимости от того, какую среду кросс-компиляции я выбираю, я могу выбрать соответствующий файл toolchain. Это правильно? Или указание файла цепочки инструментов через переменную имеет другие побочные эффекты, которые заслуживают внимания, помимо включения отдельных переменных (CMAKE_SYSTEM_NAME в CMAKE_FIND_ROOT_PATH_MODE)

4. Помимо отделения проекта от среды сборки, помещение переменных, зависящих от среды, в отдельный файл цепочки инструментов надежно работает с командой try_compile (и связанными с ней функциями): когда CMake настраивает новый проект для проверки компиляции / компоновки, он также передает CMAKE_TOOLCHAIN_FILE переменную этому проекту, так что проект использует ту же цепочку инструментов (и ее настройки), что и ваш проект.

Ответ №1:

Хорошо, спасибо Tsyvarev за быстрые подсказки о том, чего мне не хватало. Оказывается, ответ более очевиден, чем я думал.

Как упоминал Цыварев в комментариях, CMake не выполняет рекурсивный поиск библиотек в указанном корневом каталоге. Вместо этого он выполняет поиск по стандартным путям, таким как /usr /lib, /lib и т.д. Дополнительные пути поиска могут быть добавлены путем добавления их к CMAKE_LIBRARY_PATH , как указано в документации. Итак, чтобы исправить свои ошибки, я сделал следующее: я добавил нужные мне пути к библиотекам в путь поиска.

 ...
set(SOURCES main.cpp)
set(CMAKE_LIBRARY_PATH 
    ${CMAKE_LIBRARY_PATH}
    "/lib/arm-linux-gnueabihf"
    "/usr/lib/arm-linux-gnueabihf"
)
add_executable(${project_target} ${SOURCES})
...
  

Затем я увидел, что забыл добавить какие-либо включенные каталоги:

 target_include_directories(${project_target} PUBLIC
    ${SYSROOT}/usr/include/bluetooth
    ${SYSROOT}/usr/include/arm-linux-gnueabihf
)
  

И я смог скомпилировать main.cpp .

Что касается РЕДАКТИРОВАНИЯ: чтобы правильно связать библиотеку потоков boost, мне также пришлось связать ее зависимости. Поэтому я поставил:

 find_package(Boost COMPONENTS thread REQUIRED)

...

target_include_directories(${project_target} PUBLIC
    ${SYSROOT}/usr/include/bluetooth
    ${SYSROOT}/usr/include/arm-linux-gnueabihf
    ${Boost_INCLUDE_DIRS}
)

target_link_libraries(${project_target} PUBLIC
    rt
    Threads::Threads
    ${Boost_LIBRARIES}
    ${BLUETOOTH}
)