linux — проблемы компиляции c ++ для встроенной системы

У меня есть несколько связанных вопросов о моих проблемах с компиляцией для встроенной системы. Мои вопросы не только о том, КАК что-то сделать, но больше о ПОЧЕМУ, потому что у меня есть решения для моих проблем (но, может быть, есть и лучшие?), Но я понятия не имею, почему некоторые вещи работают в некоторых условиях и не работают в другие. Я уже провел некоторое время с этим, но до вчерашнего дня я делал что-то немного слепо, с пробами и ошибками, не зная, что я делаю. Время остановить это! Пожалуйста помоги.

сценарий

Я хочу разработать приложение для процессора Zilq ARM от Xilinx на Zedboard. Приложение будет включать в себя многопоточность, некоторые манипуляции с аудио и httpserver. Поэтому мне понадобятся библиотеки pthread, alsa, sndfile и microhttpd. Я создал rootfs с Yocto. В оригинальном файле conf.local я добавил / изменил эти строки:

BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"MACHINE ?= "zedboard-zynq7"PACKAGE_CLASSES ?= "package_deb"EXTRA_IMAGE_FEATURES = "debug-tweaks eclipse-debug"IMAGE_INSTALL_append = "libgcc alsa-utils mpg123 libstdc++ sthttpd libmicrohttpd libsndfile1"LICENSE_FLAGS_WHITELIST = "commercial_mpg123"

Мне также пришлось добавить несколько дополнительных слоев в bblayers.conf (и, конечно же, загрузить их):

meta-xilinx
meta-multimedia (from meta-openembedded)
meta-oe         (from meta-openembedded)
meta-webserver  (from meta-openembedded)

Наконец, я создал core-image-minimal с помощью bitbake.

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

1. Простое приложение с этим rootfs

Это приложение для Zynq, поэтому я использую XSDK, который является SDK от Xilinx на основе Eclipse. Я создал новый проект приложения. В диалоговом окне я выбрал Linux в качестве платформы, C ++ в качестве языка и указал путь к моим распакованным rootfs (точно тот, который загружается системой через NFS). Мой путь rootfs /home/stas/ZedboardPetalinuxFS (это не Petalinux, я просто использовал его, и это имя папки остается прежним). Это устанавливает правильные пути для поиска библиотеки и заголовков в rootfs.
Я начал с чего-то очень простого:

#include <pthread.h>

int main()
{
int i;
i = 1;
return 0;
}

Я также добавил библиотеку pthread для компоновщика (в настройках Eclipse). Связывание команды на этом этапе:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lpthread

На данный момент он компилируется. Но это останавливается, когда я добавляю библиотеку sndfile

#include <sndfile.h>

Это разумно, потому что у этого rootfs не все заголовки. Мне нужно добавить еще один путь для поиска заголовков. Поэтому я добавил путь в папку yocto tmp, в которой есть все заголовки, необходимые для сборки rootfs. После того, как я его добавлю, он снова успешно скомпилируется. Но проблемы начались, когда я добавил библиотеку sndfile для линковки. Вот связь команды и ошибки:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lpthread -lsndfile
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lsndfile

Я посмотрел на usr / lib, чтобы проверить, есть ли libsndfile.so, и нашел только libsndfile.so.1 и ibsndfile.so.1.27. Но это также относится и к pthread, и компоновщик не жалуется на это. Я решил создать libsndfile.so вручную (я связал его с libsndfile.so.1). Линкер перестал жаловаться на это, но начал жаловаться на его зависимость. Поэтому я также создал файлы .so для всех зависимостей и их зависимостей и добавил их для связывания. Тогда это удалось. В конце команда связывания выглядела так:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lpthread -lvorbisenc -lvorbis -logg -lFLAC -lsndfile

Итак, первый вопрос — почему мне не нужен .so файл для pthread, но он нужен для всех остальных библиотек? Или более общий — когда мне нужен файл .so, а когда файла .so.X достаточно?

2. Простое приложение — другой подход

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

EXTRA_IMAGE_FEATURES = "debug-tweaks eclipse-debug dev-pkgs"

Опция dev-pkgs добавляет пакеты -dev для всех установленных пакетов.
Так что теперь у меня есть rootfs со всеми необходимыми заголовками и .so файлы, указывающие, где они должны.
Перед компиляцией я удалил ненужный путь «Включить», оставив только один из корневых файлов, и удалил все библиотеки, кроме pthread и sndfile. Но тогда я получаю новые ошибки:

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" -o "test.elf"  ./src/main.o   -lsndfile -lpthread
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find /lib/libpthread.so.0
makefile:48: polecenia dla obiektu 'test.elf' nie powiodły się (commands for ‘test.elf’ did not succeed)
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find /usr/lib/libpthread_nonshared.a

Я заметил, что он ищет библиотеки в моей корневой папке. Быстрый поиск в Google (и SO 🙂 сказал мне, что я должен установить переменную –sysroot. Таким образом, я добавил его в опцию Eclipse (в разделе Miscelenious в опциях Linker) следующим образом:

--sysroot=/home/stas/ZedboardPetalinuxFS

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

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" --sysroot=/home/stas/ZedboardPetalinuxFS -o "test.elf"  ./src/main.o   -lsndfile -lpthread

И все получится! Я также написал простой пример, который использует pthreads и sndfile, и это тоже сработало. Но почему? Это приводит меня ко второму вопросу:
Зачем мне нужна опция —sysroot в этом случае? Когда мне нужно использовать эту опцию в целом? И почему в этот раз мне не пришлось добавлять все зависимости в команду связывания?

3. Еще одна идея

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

arm-linux-gnueabihf-g++ -L"/home/stas/ZedboardPetalinuxFS/usr/lib" -L"/home/stas/ZedboardPetalinuxFS/lib" --sysroot=/home/stas/ZedboardPetalinuxFS -o "test.elf"  ./src/main.o   -lpthread -lvorbisenc -lvorbis -logg -lFLAC -lsndfile
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find crt1.o: No such file or directory
makefile:48: polecenia dla obiektu 'test.elf' nie powiodły się
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find crti.o: No such file or directory
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lpthread
/opt/Xilinx/SDK/2016.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lm

Итак, третий вопрос — что означают эти ошибки?

Большое спасибо заранее!

0

Решение

почему мне не нужен .so файл для pthread, но он нужен для всех остальных библиотек?

Кросс-компилятор обычно поставляется с C Runtime (включая pthread), обычно в каталоге, который является частью кросс-компиляционной установки.

Компоновщик имеет встроенные пути поиска для библиотек. Это относится к sysroot, который по умолчанию будет настроен на поиск собственной целевой среды выполнения C кросс-компилятора. Если вы добавили какие-либо -L варианты, он будет искать эти сначала, а затем перейти к этим заранее определенным каталогам.

Когда вы связаны с pthread нашел бы хотя бы libpthread.a в каталоге библиотеки кросс-компилятора.

Или более общий — когда мне нужен файл .so, а когда файла .so.X достаточно?

Общие библиотеки в Linux обычно имеют основной и вспомогательный номер версии. Библиотеки совместимы с ABI между различными дополнительными версиями с одной и той же основной версией, но не между основными версиями. Иногда существует три уровня версий, но основной принцип похож.

При установке библиотек обычно устанавливается фактический файл с полным именем, например. libmy.so.1.2, а затем предоставьте символические ссылки на libmy.so.1 а также libmy.so,

Если вы связываете приложение, оно может работать с любой версией библиотеки, тогда вам просто нужно указать имя, например. -lmy, В этом случае вам понадобятся символические ссылки из libmy.so в libmy.so.1,

Если вам нужна конкретная версия, вы бы поставили -l:libmy.so.1, «:» Обозначает буквальное имя файла.

Сценарии компоновщика могут влиять на вещи и могут привести к тому, что будут выбраны конкретные версии, даже если вы укажете короткое имя.

Зачем мне нужна опция —sysroot в этом случае? Когда мне нужно использовать
этот вариант вообще?

Какие --sysroot «do» — это указание указанного пути во всех каталогах поиска, которые обычно используются для поиска включений и библиотек. Это наиболее полезно при кросс-компиляции (как вы делаете сейчас), чтобы заставить компилятор и компоновщик искать внутри целевого корня вместо собственного корня узла сборки.

Если вы указали sysroot, вам, вероятно, не нужно указывать пути включения через -I или пути компоновщика через -L, предполагая, что файлы находятся в пределах своих нормальных мест внутри целевого корня.

И почему в этот раз мне не пришлось добавлять все зависимости в команду связывания?

Одним из возможных сценариев является то, что в первый раз, sndfile для статически, а не динамически связаны. Это произошло бы, если бы ваше первое корневое изображение имело только sndfile.a в директории lib или в другом месте пути поиска. Чтобы затем удовлетворить требования sndfile.a Вам также нужно будет связать другие библиотеки.

При связывании с sndfile.so зависимости будут автоматически загружены через процесс динамического связывания.

Это просто рабочая теория в настоящее время.

Итак, третий вопрос — что означают эти ошибки?

Они означают, что он не может найти даже библиотеку времени выполнения C для ссылки.

Как описано для первого вопроса, ранее он находил среду выполнения C в предопределенном пути поиска (относительно предопределенного sysroot), в котором находилась среда выполнения C, предоставляемая кросс-компилятором.

Вы нарушили это, поставив свой собственный системный корень. Теперь он только искал целевой корень. Так как на этой целевой корневой файловой системе не были установлены библиотеки разработки, там не было времени выполнения C для поиска.

1

Другие решения

  1. «Почему мне не нужен .so файл для pthread, но он нужен для всех
    другие библиотеки?

    На самом деле вам нужен файл pthread.so. Вы включили pthread.h, но не связались с -lpthread. Так что нормально, вы не видите ошибок компоновщика.

    «Когда мне нужен файл .so, а когда файла .so.X достаточно»

    Когда вы задаете параметр «-lNAME» для g ++, компилятор указывает компоновщику найти libNAME.so в путях поиска библиотеки. Поскольку может существовать несколько версий одной и той же библиотеки (libNAME.so.1, libNAME.so.1.20), файлы * .so ссылаются на нужный файл библиотеки. (Управление версиями общих объектов, страницы man ld)

  2. «Зачем мне нужна опция —sysroot в этом случае? Когда мне нужно вообще использовать эту опцию? И почему на этот раз мне не пришлось добавлять все зависимости в команду связывания?»

    «Dev-pkgs» в EXTRA_IMAGE_FEATURES неявно меняет ваш системный корень, чтобы позволить вам ссылаться на пакеты dev (особенности изображения yoctoproject). Вот почему вам нужен параметр -sysroot. Эта опция обычно нужна при кросс-компиляции, чтобы обеспечить рут для стандартных путей поиска для заголовков и библиотек. Вам это не нужно, потому что у вас не было функции образа dev-pkgs, которая изменяет ваш системный корень

  3. «Итак, третий вопрос — что означают эти ошибки?»

    Даже ваш самый простой код hello world связывается со стандартной библиотекой c (если вы не указали иначе). Файлы libm.so, libpthread.so и crt1.o являются частью библиотеки libc и поставляются с пакетом libc dev. Таким образом, компоновщик не может видеть каталоги стандартной библиотеки, когда он выглядит из вашего старого sysroot

2

Вы делаете несколько вещей неправильно:

  1. Похоже, вы не используете переменные окружения, а вызываете кросс-компилятор напрямую. Таким образом, вместо компиляции с arm-linux-gnueabihf-g++ ..., ты должен сделать $CXX ..., CXX — это переменная окружения, установленная скриптом yocto для установки среды для кросс-компиляции. Используя CXX, вам не нужно вручную передавать —sysroot
  2. Вы не должны связываться напрямую с библиотекой pthread -lpthread, Вы должны использовать -потоковой
0
По вопросам рекламы [email protected]