aarch64-linux-gnu-gcc: руководство по кросс-компиляции под ARM64

Команда aarch64-linux-gnu-gcc запускает кросс-компилятор GCC, который собирает исполняемые файлы для 64-битной архитектуры ARM (AArch64) прямо на обычном x86-64 компьютере с Linux. Если при сборке проекта вы видите ошибку вида «aarch64-linux-gnu-gcc: command not found», это означает, что кросс-тулчейн просто не установлен в системе, и проблема решается установкой соответствующего пакета.

Такой инструмент нужен разработчикам встраиваемых систем, сборщикам ядер Linux для ARM-плат (Raspberry Pi, серверные ARM-платы, одноплатные компьютеры) и всем, кто готовит ПО для устройств, где нет возможности или смысла компилировать код локально. Ниже разберём, что скрывается за именем тулчейна, как его поставить и как избежать типовых ошибок.

Что означает имя aarch64-linux-gnu-gcc

Имя кросс-компилятора — это не случайный набор слов, а триплет целевой платформы плюс название инструмента. Каждый сегмент несёт конкретный смысл:

  • 🧩 aarch64 — целевая архитектура: 64-битный ARM (ARMv8-A и новее);
  • 🐧 linux — целевая операционная система, то есть Linux;
  • 🔧 gnu — ABI и стандартная библиотека: GNU libc (glibc) и соглашения GNU;
  • ⚙️ gcc — сам компилятор из набора GNU Compiler Collection.

Рядом могут существовать похожие варианты: aarch64-none-elf-gcc для «голого железа» без ОС, или aarch64-linux-musl-gcc для систем на musl libc. Путать их нельзя: бинарник, собранный под glibc, не запустится на системе с musl, и наоборот.

Установка кросс-компилятора

В Debian, Ubuntu и производных тулчейн доступен из штатных репозиториев. Установка выполняется одной командой:

sudo apt update

sudo apt install gcc-aarch64-linux-gnu

Если нужен ещё и компилятор C++, добавьте пакет g++-aarch64-linux-gnu. Для Fedora и родственных дистрибутивов пакет обычно называется gcc-aarch64-linux-gnu и ставится через dnf. Точное имя пакета зависит от дистрибутива, поэтому при неудаче поищите его через apt search aarch64 или аналог вашего пакетного менеджера.

Проверить результат можно запросом версии:

aarch64-linux-gnu-gcc --version

Если команда выводит версию компилятора — тулчейн на месте. Если снова «command not found», проверьте, что пакет действительно установился, и что каталог /usr/bin присутствует в переменной PATH.

📊 Для какой цели вы используете aarch64-linux-gnu-gcc?
Сборка ядра Linux для ARM-платы
Кросс-компиляция прикладных программ
Разработка под встраиваемые системы
Изучение архитектуры ARM64

Первая кросс-компиляция программы

Начните с минимального примера, чтобы убедиться, что вся цепочка работает. Создайте файл hello.c с обычным выводом строки и скомпилируйте его:

aarch64-linux-gnu-gcc hello.c -o hello

Убедиться, что получился именно ARM64-бинарник, поможет утилита file:

file hello

В выводе должно быть указано ELF 64-bit LSB executable, ARM aarch64. Обратите внимание: запустить такой файл на x86-машине напрямую не получится — ядро сообщит об ошибке формата. Для локального запуска используют эмуляцию через qemu-user либо копируют файл на целевое устройство.

☑️ Проверка рабочего тулчейна

Выполнено: 0 / 5

Статическая и динамическая линковка

По умолчанию компилятор линкует программу динамически, и на целевом устройстве потребуются совместимые версии glibc и динамического загрузчика. Если версии библиотек на хосте сборки и устройстве различаются, программа может не запуститься с ошибкой вида «version GLIBC_X.XX not found».

Для простых утилит удобен выход — статическая сборка:

aarch64-linux-gnu-gcc -static hello.c -o hello

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

⚠️ Внимание: статическая линковка с glibc имеет известные ограничения — функции, связанные с NSS (разрешение имён пользователей и хостов), могут вести себя иначе, чем при динамической сборке. Для сетевых демонов тестируйте такой вариант особенно тщательно.

Сборка проектов с Makefile и CMake

Реальные проекты редко собираются одной командой. Для Makefile-сборки обычно достаточно переопределить переменные компилятора:

make CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++

В CMake принято использовать toolchain-файл, где задаются система, процессор и пути к компиляторам. Минимальный вариант такого файла:

set(CMAKE_SYSTEM_NAME Linux)

set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)

set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

Затем конфигурация запускается с параметром -DCMAKE_TOOLCHAIN_FILE=путь/к/файлу. Если проект зависит от сторонних библиотек, их тоже нужно собрать или раздобыть в ARM64-варианте и указать пути через CMAKE_FIND_ROOT_PATH — иначе сборка подхватит x86-библиотеки с хоста и упадёт на этапе линковки.

Типичные ошибки и их причины

ОшибкаВероятная причинаЧто проверить
command not foundТулчейн не установленУстановить пакет gcc-aarch64-linux-gnu
cannot find -l<имя>Нет ARM64-версии библиотекиСобрать зависимость кросс-компилятором или настроить sysroot
Exec format error при запускеЗапуск ARM-бинарника на x86Использовать qemu-aarch64 или целевое устройство
GLIBC_X.XX not foundНа устройстве старее glibc, чем на хостеСобрать статически или под систему устройства
undefined reference при линковкеПодхвачены библиотеки хостовой архитектурыПроверить пути поиска и CMAKE_FIND_ROOT_PATH
⚠️ Внимание: никогда не указывайте в кросс-сборке пути к библиотекам хоста вроде -L/usr/lib без sysroot — линкер может молча подхватить x86-64 объекты, и ошибка проявится только на последнем этапе сборки или вообще на устройстве.

Отдельный частый случай — сборка модулей ядра: внешний модуль должен компилироваться тем же тулчейном и с теми же заголовками ядра, что и само ядро целевой платы. Несовпадение версий приводит к отказу загрузки модуля с ошибкой о неверном формате или несоответствии vermagic.

Запуск и отладка через QEMU и GDB

Для запуска ARM64-программ без реального железа установите пакет qemu-user. Статически собранный бинарник запускается напрямую:

qemu-aarch64 ./hello

Для динамически слинкованных программ потребуется указать каталог с ARM-библиотеками через параметр -L. Отладка возможна связкой aarch64-linux-gnu-gdb на хосте и gdbserver на устройстве либо в QEMU: отладчик подключается по сети и позволяет ставить точки останова, смотреть переменные и стек вызовов как при обычной отладке.

Чем aarch64 отличается от armhf и armel

armel и armhf — тулчейны для 32-битного ARM (ARMv7 и старше), причём armhf использует аппаратную FPU. aarch64 — 64-битная архитектура ARMv8+, несовместимая с 32-битными бинарниками на уровне ABI. Выбирать тулчейн нужно строго под систему, установленную на устройстве: проверить её можно командой uname -m на самом устройстве (aarch64 или armv7l).

Часто задаваемые вопросы

Чем aarch64-linux-gnu-gcc отличается от обычного gcc?

Обычный gcc собирает код под архитектуру машины, на которой запущен (чаще x86-64). Кросс-компилятор aarch64-linux-gnu-gcc работает на хосте, но генерирует машинный код для 64-битного ARM. Сами исходники при этом могут быть одинаковыми.

Можно ли собрать ядро Linux этим тулчейном?

Да, это один из основных сценариев. При сборке ядра указывают ARCH=arm64 и CROSS_COMPILE=aarch64-linux-gnu- в команде make. Конфигурацию берут из defconfig целевой платы или из работающей системы устройства.

Почему программа не запускается на устройстве с ошибкой о GLIBC?

Возможная причина — на хосте сборки glibc новее, чем на целевой системе, и бинарник ссылается на символы, которых там нет. Варианты решения: статическая сборка, сборка в окружении со старой glibc (например, в контейнере) или использование sysroot с библиотеками устройства.

Нужен ли отдельный тулчейн для Raspberry Pi?

Для 64-битной ОС на Raspberry Pi подходит обычный aarch64-linux-gnu-gcc. Для 32-битных систем Raspberry Pi OS нужен тулчейн под armhf — это другая цель, и смешивать их нельзя. Проверьте разрядность системы командой uname -m на самом устройстве.

Как узнать, какие библиотеки нужны ARM-бинарнику?

Используйте aarch64-linux-gnu-objdump -p файл или readelf -d файл из пакета binutils — они покажут список зависимостей (NEEDED) без запуска программы. Обычный ldd на хосте для чужой архитектуры не подойдёт.