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

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

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

  1. Инструменты
  2. Элементарная технология кросскомпиляции
  3. И, собственно, HOW2

Кому это интересно, прошу под кат.

Вводная


Одно из развивающихся направлений в современном 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.

Описанное выше справедливо для gcc и сделанных на его базе toolchain'ах.

Сперва я пытался использовать 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 <iostream>
#include <string>
#include <vector>


// Function to check input expression
bool checkExpression(std::string exp){
	for(uint i=0; i<exp.length(); i++){
		char c = exp[i];
		if(c < '(' || c > '9' || c == '\''){
			if(c != ' ') return false;
		}
	}
	return true;
}


// Template function to evaluate atomic expression
template<class T>
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<class T>
std::string evalExpWithoutBrackets(std::string exp){

	std::vector<T> operands;
	std::vector<char> operations;

	const uint explen = exp.length();

	// Allocating arguments and operations without ordering
	for(uint shift=0, position = 0; shift<explen; shift++){

		// This check need for situation when we didn't allocate last argument
		if(shift == explen-1){
			std::string expWithoutBrackets;
			expWithoutBrackets.assign(exp, position, explen - position + 1);
			operands.push_back((T) std::stod(expWithoutBrackets));
		}

		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++; shift<explen; shift++){
					if( exp[shift] == '+' || exp[shift] == '-' || exp[shift] == '*' || exp[shift] == '/' ){
						tempExp.assign(exp, position, shift-position);
						operations.push_back(exp[shift]);
						break;
					}
					if(shift == explen-1){
						tempExp.assign(exp, position, explen - position);
					}
			}
			operands.push_back((T)std::stod(tempExp));
			position = shift+1;
		}
	}

	// Calculator

	std::vector<uint> 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<T>(operands[evalOrder[i]], operands[evalOrder[i]+1], operations[evalOrder[i]]);
		}
		catch(char const *er){
				std::cout << er << std::endl;
		}

		// 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<T>
		operands[evalOrder[i]] = rexp;
	}

	return std::to_string(operands[0]);
}

template<class T>
std::string evalExpression(std::string exp){
	uint open = 0, close = 0;
	for(uint i=0; i<exp.length(); i++){
		if(exp[i] == '(') open++;
		else if(exp[i] == ')') close++;
	}
	if(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<exp.length(); closeBracketPosition++){
		if(exp[closeBracketPosition] == ')'){
			uint openBracketPosition = closeBracketPosition;
			while(openBracketPosition--){
				if(exp[openBracketPosition] == '('){
					std::string expWithoutBrackets;                
					expWithoutBrackets.assign(exp, openBracketPosition + 1, closeBracketPosition - openBracketPosition - 1);

					std::string atomExpResult = evalExpression<T>(expWithoutBrackets);
					
					std::string leftPartExp, rightPartExp;

					leftPartExp.assign(exp, 0, openBracketPosition);
					rightPartExp.assign(exp, closeBracketPosition + 1, exp.length() - closeBracketPosition);
					
					return evalExpression<T>( leftPartExp + atomExpResult + rightPartExp);
				}
			}
		}
	}
	return evalExpWithoutBrackets<T>(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 << "Evaluating expression is: \"" << evalexp << "\"" << std::endl;

	std::cout << "Result is: " << evalExpression<int>(evalexp) << std::endl;
	return 0;
}

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

[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, если нет особого желания предаваться плотским утехам с библиотеками на целевой платформе.

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

[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.
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 23
  • +3
    Я тут недавно тоже вплотную озадачился кросскомпиляцией под ARM, так как оказалось, что под мой Toshiba AC100 ни одного нормального (современного) бинарного дистрибутива нет. И в итоге оказалось, что в Gentoo Linux с этим все не просто хорошо, а замечательно:
    https://wiki.gentoo.org/wiki/Cross_build_environment
    https://wiki.gentoo.org/wiki/Distcc/Cross-Compiling
    В Gentoo-вики по Raspberry Pi тоже можно найти много полезного (и далеко не только RPi-специфичного):
    https://wiki.gentoo.org/wiki/Raspberry_Pi

    Что меня поразило — делать полную виртуалку с ARM-системой совсем не обязательно, современный qemu позволяет (при соответствующей настройке системы, конечно же) на обычном x86_64 компьютере запускать ARM'овые бинарники, что, в соединении с chroot'ом, для меня оказалось гораздо эффективнее и удобнее, чем «настоящая» виртуалка. Ну и не стоит забывать про distcc.
    • 0
      А можно уточнить в чем смысл эмуляции embedded процессоров на x86, если основные задачи, для которых их используют, обычно связаны с обменом данными через i2c, spi, дрыгание gpio и прочие спец фичи контроллеров? Разве можно проэмулировать это под линукс на обычном ПК?
      • 0
        Ну для меня смысл в том, что тот же GCC не получится собрать на ARM'овой железке которая у меня есть потому, что у нее не хватает памяти. Кросс-компиляция тоже не всегда работает, так как тот же GCC хочет бутстрапа, т.е. скомпилировать самого себя пару-тройку раз (пока процесс не сойдется). Потому и остается эмуляция.
        • 0

          Crosstool-NG ?

          • 0
            Нене, мне не нужен кросскомпилятор, для этого у меня есть sys-devel/crossdev. Но некоторые пакеты кросскомпиляцией не собрать (Ну или может собрать в итоге и получится, но перед этим долго мучиться и понимать, что с ним не так), потому на помощь приходит виртуализация.
          • +1
            тот же GCC хочет бутстрапа,

            А если RTFM?
            Building a native compiler
            For a native build, the default configuration is to perform a 3-stage bootstrap of the compiler when ‘make’ is invoked.
            It can be disabled with the --disable-bootstrap parameter to ‘configure'

            Building a cross compiler
            When building a cross compiler, it is not generally possible to do a 3-stage bootstrap of the compiler.
            • 0
              Чукча не читатель мануалов, чукча просто хотел поставить пакет с GCC на свой Toshiba AC-100.
              За ссылку спасибо =)
              GCC я привел только как пример, в той же Gentoo есть много пакетов, которые кросскомпиляцией не собрать, Часть вываливаются с:
              configure: error: cannot run test program while cross compiling
              У части — просто жестко прописаны пути к cc или либам. Понятно, что 99% всего этого я мог бы починить, а заодно заслать патч разработчику, только уж слишком много таких пакетов и слишком мало у меня желания этим заниматься.
          • +3

            Вы путаете процессоры и микроконтроллеры. Cortex-A, про которые идёт речь в этом топике — полноценные general purpose cpu, на них спокойно может крутиться linux и вещи типа дёрганья каких-либо gpio, spi/i2c/i2s/uart осуществляется из ядра ОС, т. е. через драйвер с точки зрения userspace.


            А эмулировать можно и такие процессоры, и контроллеры. Естественно, для части вещей придётся описывать эмуляцию периферии. Одним из полезных кейсов, когда вполне может быть модульное тестирование. Другим — интеграционное тестирование с сетью (я как-то писал для этого эмулятор сетевой карты enc28j60).

          • +7
            Toolchain'ы для ARM делятся на несколько типов. Основные это noneabi, eabi и eabihf.

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

            Это триплеты target-архитектур, которые вы, ко всему прочему, ещё и неправильно написали.


            Триплет обычно состоит из трёх частей: целевой процессор, vendor и OS, vendor зачастую опускается (и может в этом случае означать pc для x86 и x86_64; или unknown для почти всего остального). OS иногда состоит из двух частей, разделяемых также дефисом (e.g. linux-gnueabi, linux-androideabi) и означает API и ABI целевой платформы. В случае bare metal OS, как правило, none-*, т. е. для bare metal arm это выглядит как arm-unknown-none-eabi, что, как правило, сокращается до arm-none-eabi.


            eabi и eabihf отличаются, собственно, ABI вызова функций с плавающей точкой, а не наличием поддержки hardfloat целевой платформой (т. е. регулирует -mfloat-abi). Очевидно, что fpu необходим для eabihf, но никто не запрещает использовать hardfloat, но передавать аргументы функции не используя аппаратные регистры для floating point.


            В случае платформ типа raspberrypi с linux'ом на борту необходимо использовать aarch64-linux-gnueabi/arm-linux-gnueabi/arm-linux-gnueabihf в зависимости от того какое abi используется ОС, установленной на rpi.


            Стоит также понимать, что написанное выше справедливо для gcc и сделанных на базе (или мимикрирующих под) него тулчейнах. У clang/llvm свои триплеты, которые строятся по схожему принципу, но с несколько иным пониманием того, что такое target cpu. Например, у gcc триплеты arm-*-* включают очень разнородные cpu: от ARM7 (не путать с ARMv7*) и Cortex-M, которые предназначены для микроконтроллеров, обычно не имеют кэшей (исключение — новые Cortex-M на архитектуре ARMv8-M) до ARM11 и Cortex-A/R, которые являются полноценными процессорами. Выбор процессора, набора команд и других параметров кодогенерации осуществляется ключами типа -mcpu/-march/-mtune, -thumb и пр.


            В случае же llvm часть информации из -mcpu/-march/-mtune переехала в target. Например, вместо TARGET=arm-none-eabi и -march=cortex-m3 необходимо использовать TARGET=thumbv7m-none-eabi, если правильно помню.

            • +2

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


              Просто используется toolchain в роли компилятора.

              Компилятор — часть тулчейна. Обычно просто используется нативный тулчейн, для которого HOST и TARGET совпадают.


              А стандартные библиотеки поставляются вместе с toolchain'ом.

              Это зависит от мейнтейнеров конкретных пакетов, т. е. далеко не всегда так.

              • 0
                Благодарю за экскурс, очень познавательно.
            • –2
              Поэтому лучше собирать на хосте. В моём случае, это i5 с 4ГБ ОЗУ, Fedora 24.

              В этот момент статью закончило читать 90% разработчиков.
              На самом деле тут статья «из пушки по воробьям».
              Eclipse+GNU ARM делают это все «из коробки»
              Для поклонников Майкрософта и Вижуал Студио достаточно доставить в свою любимую среду VisualGDB и опять таки не заморачиваться.
              • 0
                В этот момент статью закончило читать 90% разработчиков.

                Ну это же хорошо.

                На самом деле тут статья «из пушки по воробьям».

                Не согласен.

                Eclipse+GNU ARM делают это все «из коробки»
                Для поклонников Майкрософта и Вижуал Студио достаточно доставить в свою любимую среду VisualGDB и опять таки не заморачиваться.

                Пользоваться этим и далее не понимать, как оно «вертится внутри».
              • –1
                До того, как познакомился с DS-5, кросс-компиляция под ARM была головной болью. Сейчас же это всё происходит без каких-либо проблем.

                Поддерживается как сборка под linux, так и под голый ARM. Можно отлаживаться через gdb или JTAG, в т. ч. и производить трассировку инструкций при условии поддержки этого как аппаратной платформой, так и отладчиком.

                P. S. Никак не связан с производителем, просто дейстивительно приятно использовать этот инструмент в работе. Если есть какие-то вопросы, отвечу на них
                • 0
                  Инструмент хорош, пока вам не нужен JTAG или baremetal. А как только они становятся нужны, то появляется проблема — DS-5 стоит весьма прилично. Есть конечно всякие DS-5 [CPU Vendor] Edition, но и они тоже стоят денег.
                  П.С. Сам живу на Altera edition оного, после допиливания (ага, там первые версии шли с корявейшими скриптами сборки и заливки через JTAG) оный становится очень вкусным.
                  • 0
                    DS-5 стоит прилично для одинокого радиолюбителя, для компании же эти затраты окупаются вмиг.
                • 0
                  Собственно, вот такая она, эта кросскомпиляция.

                  Собственно, это была вовсе и не кросскомпиляция.
                  • –2
                    В Википедии, по вашему, ошибаются?
                    • 0
                      В этом месте википедии всё нормально написано. Тем не менее, начиная с заголовка HOW2 в вашей статье описывается не кросс-компиляция, а нативная компиляция внутри эмулятора.

                      Ещё один вопрос: если у вас есть gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf, зачем танцы с ARM в QEMU?
                      • 0
                        Прошу прощения, нет больше вопросов. Вот что значит с утра не выпить кофе.
                        • 0
                          Бывает.
                    • +1
                      make CROSS_COMPILE=/usr/bin/arm-none-linux-gnueabihf- ARCH=arm all
                      

                      Обычно этого достаточно, чтобы компилятор начал сборку проекта тулчейном, а не нативно (Командоой выше я спокойно собираю ядро для arm-девайса на десктопе. Сам тулчейн — собранный вручную Linaro Crosstools)
                      С тестированием тож все легко: Собираем образ системы (debootstrap для debian-based систем), в системе ставим qemu-user-static, копируем /usr/bin/qemu-arm-static по томуже пути в чрут и можно туда заходить.
                      Что примечательно — внутри чрута можно выполнить «Нативную» компиляцию.

                      Ну или можно схитрить и использовать buildroot для сборки почти всего и настройкой через привычный menuconfig (какой-никакой GUI)
                      • 0
                        Обычно этого достаточно, чтобы компилятор начал сборку проекта

                        Этого достаточно, если Makefile проекта написан так, чтобы использовать переменную окружения CROSS_COMPILE. Вот как, например, Makefile ядра или U-Boot. С произвольным проектом это не работает.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.