#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}
)