Build arm linux gnueabihf

Кросскомпиляция под ARM

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

В данном посте будут описаны:

Вводная

Одно из развивающихся направлений в современном IT это IoT. Развивается это направление достаточно быстро, всё время выходят всякие крутые штуки (типа кроссовок со встроенным трекером или кроссовки, которые могут указывать направление, куда идти (специально для слепых людей)). Основная масса этих устройств представляют собой что-то типа «блютуз лампочки», но оставшаяся часть являет собой сложные процессорные системы, которые собирают данные и управляют этим огромным разнообразием всяких умных штучек. Эти сложные системы, как правило, представляют собой одноплатные компьютеры, такие как Raspberry Pi, Odroid, Orange Pi и т.п. На них запускается Linux и пишется прикладной софт. В основном, используют скриптовые языки и Java. Но бывают приложения, когда необходима высокая производительность, и здесь, естественно, требуются C и C++. К примеру, может потребоваться добавить что-то специфичное в ядро или, как можно быстрее, высчитать БПФ. Вот тут-то и нужна кросскомпиляция.

Если проект не очень большой, то его можно собирать и отлаживать прямо на целевой платформе. А если проект достаточно велик, то компиляция на целевой платформе будет затруднительна из-за временных издержек. К примеру, попробуйте собрать Boost на Raspberry Pi. Думаю, ожидание сборки будет продолжительным, а если ещё и ошибки какие всплывут, то это может занять ох как много времени.

Поэтому лучше собирать на хосте. В моём случае, это i5 с 4ГБ ОЗУ, Fedora 24.

Инструменты

Для кросскомпиляции под ARM требуются toolchain и эмулятор платформы либо реальная целевая платформа.

Т.к. меня интересует компиляция для ARM, то использоваться будет и соответствующий toolchain.

Toolchain’ы делятся на несколько типов или триплетов. Триплет обычно состоит из трёх частей: целевой процессор, vendor и OS, vendor зачастую опускается.

  • *-none-eabi — это toolchain для компиляции проекта работающего в bare metal.
  • *eabi — это toolchain для компиляции проекта работающего в какой-либо ОС. В моём случае, это Linux.
  • *eabihf — это почти то же самое, что и eabi, с разницей в реализации ABI вызова функций с плавающей точкой. hf — расшифровывается как hard float.

Сперва я пытался использовать toolchain’ы, которые лежат в репах Fedora 24. Но был неприятно удивлён этим:

[gazpar@localhost ~]$ dnf info gcc-c++-arm-linux-gnu Last metadata expiration check: 3 days, 22:18:36 ago on Tue Jan 10 21:18:07 2017. Installed Packages Name : gcc-c++-arm-linux-gnu Arch : x86_64 Epoch : 0 Version : 6.1.1 Release : 2.fc24 Size : 18 M Repo : @System From repo : updates Summary : Cross-build binary utilities for arm-linux-gnu URL : http://gcc.gnu.org License : GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD Description : Cross-build GNU C++ compiler. : : Only the compiler is provided; not libstdc++. Support for cross-building : user space programs is not currently provided as that would massively multiply : the number of packages. 

Поискав, наткнулся на toolchain от компании Linaro. И он меня вполне устроил.

Второй инструмент- это QEMU. Я буду использовать его, т.к. мой Odroid-C1+ пал смертью храбрых (нагнулся контроллер SD карты). Но я таки успел с ним чуток поработать, что не может не радовать.

Читайте также:  Линукс настройка сети через консоль

Элементарная технология кросскомпиляции

Собственно, ничего необычного в этом нет. Просто используется toolchain в роли компилятора. А стандартные библиотеки поставляются вместе с toolchain’ом.

CC := g++ TOOLCHAIN := arm-linux-gnueabihf- PT := CFL := -Wextra -std=c++11 TPATH := /home/gazpar/toolchain/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf/bin/ LPATH := /home/gazpar/toolchain/sysroot-glibc-linaro-2.21-2016.05-arm-linux-gnueabihf/ ARCH := -march=armv7-a -mcpu=cortex-a5 --sysroot=$(LPATH) all: slc.cpp $(CC) $(CFL) -o eval slc.cpp cross: slc.cpp $(TPATH)$(TOOLCHAIN)$(CC) $(CFL) $(ARCH) slc.cpp -o acalc -static clear: rm -f *.o rm -f eval

Какие ключи у toolchain’а можно посмотреть на сайте gnu, в соответствующем разделе.

HOW2

Для начала нужно запустить эмуляцию с интересующей платформой. Я решил съэмулировать Cortex-A9.

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

Ну сперва, само собою, нужно заиметь QEMU. Установил я его из стандартных репов Fedor’ы.

Далее создаём образ жёсткого диска, на который будет установлен Debian.

qemu-img create -f raw armdisk.img 8G

По этой ссылке скачал vmlinuz и initrd и запустил их в эмуляции.

qemu-system-arm -m 1024M -sd armdisk.img \ -M vexpress-a9 -cpu cortex-a9 \ -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.gz \ -append "root=/dev/ram" -no-reboot \ -net user,hostfwd=tcp::10022-:22 -net nic

Далее просто устанавливаем Debian на наш образ жёсткого диска (у меня ушло ~1.5 часа).

После установки нужно вынуть из образа жёсткого диска vmlinuz и initrd. Делал я это по описанию отсюда.

Сперва узнаём смещение, где расположен раздел с нужными нам файлами:

[gazpar@localhost work]$ fdisk -l armdisk.img Disk armdisk.img: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x000e5fe1 Device Boot Start End Sectors Size Id Type armdisk.img1 * 2048 499711 497664 243M 83 Linux armdisk.img2 499712 15958015 15458304 7.4G 83 Linux armdisk.img3 15960062 16775167 815106 398M 5 Extended armdisk.img5 15960064 16775167 815104 398M 82 Linux swap / Solaris
[gazpar@localhost work]$ bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. 512*2048 1048576

Теперь по этому смещению примонтируем нужный нам раздел.

[gazpar@localhost work]$ sudo mount -o loop,offset=1048576 armdisk.img qemu-mnt/
[gazpar@localhost work]$ ls -la qemu-mnt/ total 5174 drwxr-xr-x. 3 root root 1024 Jan 14 09:30 . drwxrwxr-x. 19 gazpar gazpar 4096 Jan 14 10:35 .. -rw-r--r--. 1 root root 79252 Jan 1 01:13 config-3.2.0-4-vexpress lrwxrwxrwx. 1 root root 27 Jan 14 08:47 initrd.img -> initrd.img-3.2.0-4-vexpress -rw-r--r--. 1 root root 1991475 Jan 14 09:30 initrd.img-3.2.0-4-vexpress drwxr-xr-x. 2 root root 12288 Jan 14 08:30 lost+found -rw-r--r--. 1 root root 1130676 Jan 1 01:13 System.map-3.2.0-4-vexpress lrwxrwxrwx. 1 root root 24 Jan 14 08:47 vmlinuz -> vmlinuz-3.2.0-4-vexpress -rw-r--r--. 1 root root 2051760 Jan 1 01:13 vmlinuz-3.2.0-4-vexpress

Копируем файлы vmlinuz и initrd и размонтируем жёсткий диск.

[gazpar@localhost work]$ sudo umount qemu-mnt/

Теперь можно запустить эмуляцию.

qemu-system-arm -m 1024M -M vexpress-a9 \ -kernel vmlinuz -initrd initrd.img \ -append "root=/dev/mmcblk0p2" \ -sd armdisk.img \ -net user,hostfwd=tcp::10022-:22 -net nic

И вот заветное приглашение:

Теперь с хоста по SSH можно подцепиться к симуляции.

[gazpar@localhost work]$ ssh -p10022 arm@localhost arm@debian:~$ arm@debian:~$ uname -a Linux debian 3.2.0-4-vexpress #1 SMP Debian 3.2.84-1 armv7l GNU/Linux

Теперь можно и собрать программку. По Makefile’у ясно, что будет калькулятор. Простенький.

#include #include #include // Function to check input expression bool checkExpression(std::string exp) < for(uint i=0; i'9' || c == '\'') < if(c != ' ') return false; >> return true; > // Template function to evaluate atomic expression template T eval(int a, int b, const char op) < switch(op)< case '+':< return a+b; >case '-': < return a-b; >case '*': < return a*b; >case '/': < return a/b; >default: throw("atomEval: Undefined math operation"); > >; // Function to evaluate expression without brackets template std::string evalExpWithoutBrackets(std::string exp) < std::vectoroperands; std::vector operations; const uint explen = exp.length(); // Allocating arguments and operations without ordering for(uint shift=0, position = 0; shift if( exp[shift] == '+' || exp[shift] == '-' || exp[shift] == '*' || exp[shift] == '/') < std::string expTemp; expTemp.assign(exp, position, shift-position); operands.push_back((T) std::stod(expTemp)); operations.push_back(exp[shift]); std::string tempExp; position = shift+1; for(shift++; shiftif(shift == explen-1) < tempExp.assign(exp, position, explen - position); >> operands.push_back((T)std::stod(tempExp)); position = shift+1; > > // Calculator std::vector evalOrder; // Order of operations uint highPriority = 0, lowPriority = 0; // Ordering operations // First of all we need operations with high priority for(uint i=0; i < operations.size(); i++)< if(operations[i] == '*' || operations[i] == '/')< evalOrder.push_back(i); highPriority++; >> // Now we need to order low priority operations for(uint i=0; i < operations.size(); i++)< if(operations[i] == '-' || operations[i] == '+')< evalOrder.push_back(i); lowPriority++; >> // Evaluating epression by order for(uint i=0; i < evalOrder.size(); i++)< T rexp = (T)NULL; try< rexp = eval(operands[evalOrder[i]], operands[evalOrder[i]+1], operations[evalOrder[i]]); > catch(char const *er) < std::cout // Erasing operations and operands, because operands[evalOrder[i]] and operands[evalOrder[i]+1] // became single argument after completing operations[evalOrder[i]] operation if(evalOrder[i] < operands.size()-1)< operands.erase(operands.begin()+evalOrder[i]+1); operations.erase(operations.begin()+evalOrder[i]); >// Recallculating order for(uint j = i; j < evalOrder.size(); j++)< if(evalOrder[j] >evalOrder[i]) evalOrder[j]--; > // Storing result of eval operands[evalOrder[i]] = rexp; > return std::to_string(operands[0]); > template std::string evalExpression(std::string exp) < uint open = 0, close = 0; for(uint i=0; iif(open != close) return (std::string)"error: Expression have uncoupled brackets"; // Divide expression to the blocks if there are any brackets for(uint closeBracketPosition=0; closeBracketPosition > > > return evalExpWithoutBrackets(exp);; > int main(int argc, char **argv) < std::string evalexp(argv[1]); // Check input expression for unhandling symbols if(!checkExpression(evalexp)) return -1; // Clear expression from spaces for(uint i=0 ; i < evalexp.length(); i++)< if(evalexp[i] == ' ')< evalexp.erase(evalexp.begin() + i); if(i >0) i--; > > std::cout (evalexp)

Собираем на хосте исполняемый файл.

[gazpar@localhost slcalc]$ make cross /home/gazpar/toolchain/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ -Wextra -std=c++11 -march=armv7-a -mcpu=cortex-a5 --sysroot=/home/gazpar/toolchain/sysroot-glibc-linaro-2.21-2016.05-arm-linux-gnueabihf/ slc.cpp -o acalc -static [gazpar@localhost slcalc]$ ls -la drwxrwxr-x. 2 gazpar gazpar 4096 Jan 15 16:35 . drwxrwxr-x. 7 gazpar gazpar 4096 Aug 15 07:56 .. -rwxrwxr-x. 1 gazpar gazpar 9704352 Jan 15 16:35 acalc -rwxrwxrwx. 1 gazpar gazpar 59 Jan 10 22:04 .directory -rwxrwxrwx. 1 gazpar gazpar 469 Jan 14 11:14 Makefile -rwxrwxrwx. 1 gazpar gazpar 4951 Jan 13 21:15 slc.cpp

Отмечу, что проще собрать с ключом -static, если нет особого желания предаваться плотским утехам с библиотеками на целевой платформе.

Читайте также:  What is jiffies linux

Копируем исполняемый файл на таргет и проверяем.

[gazpar@localhost slcalc]$ scp -P 10022 acalc arm@localhost:/home/arm/acalc
arm@debian:~$ ./acalc 12*13-11*(21-3) Evaluating expression is: "12*13-11*(21-3)" Result is: -42 

Собственно, вот такая она, эта кросскомпиляция.

UPD: Подправил информацию по toolchain’ам по комментарию grossws.

Источник

Install the ARM cross compiler toolchain on your Linux PC

This article illustrates how to install on a Linux PC the complete toolchain to cross compile the Linux Kernel, device drivers and applications for the Acme Systems Linux board.

This procedure has been tested on: Ubuntu 18.04.4 LTS and Debian Buster 10

Install the Cross Compilers, utilities, etc.

Install the GCC, G++ cross compilers and support programs by typing:

sudo apt update sudo apt install libc6-armel-cross libc6-dev-armel-cross binutils-arm-linux-gnueabi libncurses5-dev build-essential bison flex libssl-dev bc

If you are using an Acqua or RoadRunner board:

Now you are ready to cross-compile on your PC all the source available for the Acme Boards based on Microchip MPUs.

Try the cross C compiler

Let’s try to cross compile a Hello World example in C and running it on an Acme board.

#include "stdio.h" int main(void)

Compile it by typing, if you are using an Arietta, Aria or FOX G20 board:

or, if you are using an Acqua or RoadRunner board:

As you can see we are using the ARM version of gcc just installed on your PC. It will generate an executable file for your Linux board.

Copy the executable file on the board via ssh:

Then open a command session on your board and run the example:

Try the cross C++ compiler

Let’s try to cross compile a Hello World example in C++ and running it on an Acme board.

#include "iostream" using namespace std; int main(int argc, char *argv[])

Compile it typing, if you are using an Arietta, Aria or FOX G20 board:

Читайте также:  Безопасный сервер на linux

or, if you are using an Acqua or RoadRunner board:

As you can see we are using the ARM version of gcc just installed on your PC. It will generate an executable file for your Linux board.

Copy the executable file on the board via ssh:

Then open a command session on your board and run the example:

RoadRunner D2

  • CPU Microchip SAMA5D27
  • Cortex A5 @ 500 MHz
  • Very low power consumption:
    396mW in full speed mode
    198mW at Linux prompt
    17mW in standby mode
    10mW in suspend to RAM mode
  • Armhf architecture
  • DDR3L RAM 256 MB
  • QuadSPI 0/16/64/128MB
  • Size: 40×30 mm
  • Plug-in module
  • 200 pins 0.4 mm pitch
  • TFT parallel interface
  • Boot from internal Quad SPI or external uSD/eMMC
  • Linux Kernel 5.15 LTS
  • Debian, Buildroot and Yocto
  • Open source drivers

H10

  • Single Board Computer based on RoadRunner Linux SOM (Included)
  • Classic «Credit Card» form factor
  • Two USB Host 2.0 ports (one configurable as USB client on the USB-C connector)
  • One 10/100 Mbit/s Lan port
  • Two AcmeSensor ports
  • Double placements for 2.54mm pitch 20×2 pinstrips (not soldered) for GPIOS, SPI, I2C, Serial etc ports

  • All the circuitries you need to test the RoadRunner SOM
  • USB host, USB device, Ethernet port, MicroSD socket
  • Test points for power consumption measurements
  • All the Roadrunner signals exposed on 2.54mm pitch pins
  • On-board supercap for RTC and backup memory circuit

Источник

Оцените статью
Adblock
detector