Кросс-компилятор
Кросс-компилятор (англ. cross compiler) — это компилятор, который способен создавать исполняемый код для платформы, отличной от той, на которой запущен сам компилятор.
Кросс-компилятор удобен для сборки кода под разные платформы с одного рабочего места. Прямая компиляция на целевой платформе может быть невозможной, например, на встраиваемых системах с ограниченными вычислительными ресурсами.
Применение
Основное назначение кросс-компилятора — разделить среду разработки и целевую среду выполнения. Это полезно в различных ситуациях:
- Встраиваемые компьютеры, где устройство имеет крайне ограниченные ресурсы. Например, микроволновая печь оснащена очень маломощным компьютером, который обрабатывает сигналы с клавиатуры и датчика двери, управляет дисплеем и динамиком и осуществляет контроль за работой самой печи. Обычно он не обладает достаточными ресурсами для запуска компилятора, файловой системы или среды разработки.
- Компиляция для разных устройств. Например, компания может захотеть поддерживать несколько версий операционных систем или разные операционные системы. Использование кросс-компилятора позволяет настраивать единое окружение сборки для каждого из этих вариантов.
- Компиляция на серверной ферме. Аналогично предыдущему случаю — сложная сборка, состоящая из множества этапов компиляции, может быть распределена между любыми доступными машинами, независимо от аппаратной платформы или версии операционной системы.
- Загрузка компилятора (bootstrapping) на новую платформу. При разработке программ для новой платформы или эмулятора будущей платформы используется кросс-компилятор для создания необходимых инструментов, таких как собственная операционная система и нативный компилятор.
- Компиляция нативного кода для эмуляторов устаревших платформ, таких как Commodore 64 или Apple II, энтузиастами, использующими кросс-компиляторы, работающие на современных платформах (например, MS-DOS-кросс-компиляторы Aztec C для MOS Technology 6502 под Windows XP).
Использование виртуальных машин (например, JVM для Java) частично решает задачи, ради которых создавались кросс-компиляторы. Подход с виртуальными машинами позволяет использовать один и тот же результат компиляции на нескольких целевых системах, однако этот вариант не всегда предпочтителен: виртуальные машины обычно медленнее, а скомпилированная программа может выполняться только на компьютерах, где установлена соответствующая виртуальная машина.
Обычно различается аппаратная архитектура (например, программа для MIPS компилируется на компьютере x86), но кросс-компиляция возможна и тогда, когда отличается лишь операционная система, например, программа для FreeBSD, собираемая под Linux, или просто системная библиотека (например, сборка программ с uClibc на хосте с glibc).
Canadian Cross
Canadian Cross — это методика сборки кросс-компиляторов для других машин, когда исходная машина значительно медленнее или менее удобна, чем целевая. Предположим, имеются три машины: A, B и C. Машина A (например, под управлением Windows XP на процессоре IA-32) используется для сборки кросс-компилятора, который будет работать на машине B (например, под macOS на процессоре x86-64) и создавать исполняемые файлы для машины C (например, Android на ARM-процессоре). Практическое преимущество: машина A медленная, но есть проприетарный компилятор; машина B быстрая, но компилятора нет вовсе; машина C настолько медленная, что компилировать на ней неэффективно.
При использовании Canadian Cross в связке с GCC может быть задействовано четыре компилятора:
- Проприетарный нативный компилятор для машины A (1) (например, компилятор из Microsoft Visual Studio) используется для сборки нативного компилятора gcc для машины A (2).
- Нативный компилятор gcc для машины A (2) используется для сборки кросс-компилятора gcc с машины A на машину B (3).
- Кросс-компилятор gcc с машины A на машину B (3) используется для сборки кросс-компилятора gcc с машины B на машину C (4).
Итоговый кросс-компилятор (4) не может работать на машине A; он предназначен для запуска на машине B, где будет использоваться для сборки и создания приложений, исполняемых уже на машине C.
Например, NetBSD содержит POSIX-сценарий оболочки Unix под названием build.sh, который сначала собирает собственную сборочную цепочку с помощью компилятора хоста; затем она используется для создания кросс-компилятора, который служит для сборки всей системы.
Термин Canadian Cross возник потому, что во время обсуждения этих вопросов в Канаде в стране было три основных политических партии[1].
Хронология ранних кросс-компиляторов
- 1969 — Первая версия UNIX была разработана Кеном Томпсоном на PDP-7, однако из-за отсутствия инструментов и по стоимости она компилировалась на системе GECOS и переносилась с помощью перфоленты. Это был первый практически реализованный случай кросс-компиляции при разработке ОС[2].
- 1979 — Компилятор ALGOL 68C генерировал ZCODE, что облегчало перенос компилятора и других приложений ALGOL 68 на другие платформы. Для сборки самого компилятора ALGOL 68C требовалось около 120 КБ памяти. У Z80 было лишь 64 КБ, чего недостаточно для компиляции; поэтому для Z80 компилятор компилировался кросс-компиляцией на большем CAP-компьютере или IBM System/370.
- 1980-е — Aztec C предлагал собственную и кросс-компиляцию для домашних компьютеров, таких как Apple II и Commodore 64.
GCC и кросс-компиляция
GCC — свободный комплект компиляторов, который можно настроить для кросс-компиляции и поддерживает множество платформ и языков программирования.
Для каждого целевого окружения необходимо собирать отдельную версию binutils, особенно важно наличие GNU ассемблера. Binutils должны быть собраны с параметром --target=нужная-платформа для скрипта configure. Аналогично, GCC также необходимо настраивать с этим параметром. После этого GCC можно запускать в обычном порядке, если все утилиты, собранные binutils, доступны в PATH. Пример для UNIX-подобных систем с bash:
PATH=/путь/к/binutils/bin:${PATH} make
При кросс-компиляции GCC на хосте должна быть доступна часть стандартной библиотеки C для целевой платформы. Разработчик может пересобрать всю библиотеку, но этот способ ненадёжен. Альтернатива — использовать newlib, небольшую реализацию C-библиотеки, содержащую только самые необходимые компоненты.
Пакеты GNU Autotools (autoconf, automake, libtool) используют понятия build platform (где собирается компилятор), host platform (где будет запускаться артефакт компилятора), target platform (для кросс-компиляционных компиляторов — код, который будет генерироваться). В большинстве случаев build сбрасывается по умолчанию из host. Например, при кросс-компиляции игры под Dreamcast: рабочая машина — build, а Dreamcast — host[3]. Названия host и target зависят от контекста и могут меняться по принципу вложенности[4].
Другой распространённый в разработке embedded-Linux способ — использовать GCC совместно со специализированными песочницами вроде Scratchbox, Scratchbox 2 или PRoot. Они создают изолированную среду (chroot), позволяя собирать необходимые инструменты, библиотеки и libc, не настраивая отдельные пути. Среда позволяет запускать сценарии и конфигурационные утилиты так, будто это целевой CPU (например, ARM); однако Scratchbox медленнее и требует переноса многих инструментов хоста в песочницу.
Кросс-компиляторы Manx Aztec C
Компания Manx Software Systems из Шрусбери (Нью-Джерси) с 1980-х выпускала C-компиляторы для профессиональных разработчиков под различные платформы — до IBM PC и Mac.
Язык программирования Aztec C реализован для множества платформ, в том числе MS-DOS, Apple II, DOS 3.3 и ProDOS, Commodore 64, Macintosh (68k)[5] и Amiga.
С 1980-х и по 1990-е годы, пока Manx Software Systems не прекратила существование, MS-DOS-версия Aztec C[6] предлагалась как в виде собственного, так и кросс-компилятора для разных процессоров, включая Commodore 64[7] и Apple II[8]. До сих пор доступны дистрибутивы Aztec C, включая MS-DOS-кросс-компиляторы.
Aztec C86, собственный компилятор для Intel 8086 под MS-DOS, также был кросс-компилятором: он создавал бинарные исполняемые файлы для «устаревших» ОС семейства 8086 (не только для самого хоста), хотя не компилировал под другой процессор, как Aztec C65 для 6502.
На старте IBM PC поддерживала выбор ОС (CP/M-86, IBM PC DOS). Aztec C86 поставлялась с набором библиотек для обеих ОС. Позже (версии 3.xx, 4.xx, 5.xx) Aztec C86 поддерживала MS-DOS «переходные» версии 1 и 2[9], которые были менее надёжными, чем «базовая» версия 3 и последующие, на которые ориентировалась Aztec C86 до прекращения выпуска.
Aztec C86 позволял создавать ROM-исполняемый HEX-код, который затем записывался с помощью ROM-программатора прямо в микросхему на базе 8086. Паравиртуализация стала привычной практикой позже, но в те годы ручное создание низкоуровневого ROM-кода было массово распространено, а разработку драйверов часто осуществляли обычные прикладные программисты под конкретные задачи или устройства.
Томас Фенвик и Джеймс Гудноу II были ключевыми разработчиками Aztec-C. Позже Фенвик стал автором Microsoft Windows CE ядра (NK — «New Kernel»)[10].
Кросс-компиляторы Microsoft C
Microsoft C (MSC) начал развиваться с 1980-х годов[11]. Первые компиляторы C для Microsoft были разработаны сторонней компанией (Lattice C), а затем выпускались под брендом Microsoft, до версии MSC 4, которую Microsoft уже создала самостоятельно[12].
В 1987 многие разработчики перешли с других C-компиляторов на Microsoft C, чему способствовало развитие Microsoft Windows. Появились продукты — Clipper, позже Clarion, которые позволяли строить базы данных, комбинируя код на разных языках и компилируя его с помощью Microsoft C.
Borland C был доступен на рынке ранее, чем Microsoft выпустила первый собственный C-компилятор.
Традиционно C-программы комбинировались с модулями на ассемблере. Большинство компиляторов C предоставляли промежуточный этап генерации ассемблерного кода.
В компиляторах вроде Aztec-C каждый модуль явно проходил стадию генерации ассемблера и ассемблирования, что славилось эффективностью создаваемого кода. К 1987 году в Microsoft C был внедрён эффективный оптимизатор; большинство критичных участков кода оставались только для ручной доработки. На этом этапе C занял роль «самого низкоуровневого» языка — программные проекты сильно выросли и охватили как интерфейсы, так и базы данных; потому возросла потребность в смешанном программировании, что актуально и сегодня.
С выходом MSC 5.1 (1987) Microsoft предложила смешанную среду разработки для MS-DOS: 16-разрядные объектные файлы от MASM (ассемблер), а также коды, сгенерённые компиляторами QuickBASIC, Pascal и Fortran можно было связать воедино (approach — «Mixed Language Programming», позже «InterLanguage Calling»)[13]. Для поддержки внутренней среды BASIC требовалось, чтобы основной модуль был именно на BASIC, как это сделано в QBasic.
Ключевая особенность соглашения вызовов C — передача параметров в «обратном порядке» через стек и возврат значений тоже через стек, а не через регистр. Эта схема стала доминирующей для смешанного программирования на Windows (16- и 32-разрядных), OS/2 и актуальна до сих пор (известна как Pascal calling convention).
Другой тип кросс-компиляции с Microsoft C — сборка приложений для ручных систем, таких как PDT3100 от Symbol Technologies, работавших на Intel 8088. Программа собиралась на хосте и передавалась по каналу связи в устройство, аналогично современной модели с Windows Mobile.
С версиями MSC 6 (ANSI C-совместимый компилятор) Microsoft сосредоточилась на Windows, OS/2, основном интерфейсе к API и GUI. Поддержка смешанного программирования с моделями MS-DOS оставалась до версии 6, после чего API для Windows 3.0/3.1 и выше писались уже только на MSC. Также появилась поддержка 32-разрядных сборок, «прокси»-механизмов перехода между 16- и 32-разрядными процессами (так называемые thunk) и связанного динамического связывания. MS-DOS и 16-бит поддерживались до MSC 8.00c, который уже входил в комплект Microsoft C++ и Microsoft Application Studio 1.5 — предшественника Microsoft Visual Studio.
MSC 12 поставлялся с Visual Studio 6 и уже не поддерживал сборку 16-битных MS-DOS-программ, а создавал только 32-битные приложения под Windows 95/98, Windows NT. Были доступны библиотеки для других процессоров Windows, что сохраняется и сегодня.
MSC 13 (Visual Studio 2003) и MSC 14 (Visual Studio 2005) могли собирать код для устаревших систем (например, Windows 95), а также для разных целевых платформ, включая мобильные устройства и архитектуру ARM.
В 2001 году Microsoft создала Common Language Runtime (CLR), ставший ядром компилятора .NET Framework и Visual Studio. Это слой-прослойка в API, который позволяет смешивать разработку на разных языках и компилировать её кроссплатформенно.
CLR обеспечивает универсальный доступ к функциям процессора и устройств целевой системы. Командный C-компилятор Visual Studio компилирует нативный код для различных процессоров и может использоваться для сборки базовых системных рутин.
Также возможна кросс-компиляция под мобильные целевые системы (например, Windows Mobile на ARM), причём вместе с эмуляторами и удалённым развёртыванием, практически не требующими ручной настройки. Библиотеки совместимости, например Mono, обеспечивают совместимость кросс-компилированного .NET-программного обеспечения с ОС Linux.
Другие библиотеки, такие как Qt и предшественники (XVT), дают возможности кросс-платформенной разработки на уровне исходного кода, при этом для Windows используется компилятор Microsoft C. Популярностью пользуется и MinGW, совместимый со многими UNIX-системами, что позволяет разрабатывать для всех платформ в привычной среде.
Free Pascal
Free Pascal с самого начала разрабатывался как кросс-компилятор. Исполняемый файл компилятора (ppcXXX, где XXX — код целевой платформы) способен создавать исполняемые файлы (или объектные, если нет собственного средства компоновки, или ассемблерный текст — если нет внутреннего ассемблера) под все ОС той же архитектуры. Например, ppc386 умеет собирать программы для i386-linux, i386-win32, i386-go32v2 (DOS) и других ОС[14]. Для других архитектур требуется создать специальную версию со словом cross: например, если сборка производится для x64, файл будет называться ppcrossx64.
Для выбора нужной платформы компиляции используются ключи -P и -T для драйвера компилятора fpc или параметры CPU_TARGET и OS_TARGET для запуска через make. Если у Free Pascal нет собственных средств компоновки и ассемблирования для платформы, требуются GNU assembler и linker целевой платформы.
Clang
Clang изначально является кросс-компилятором: при сборке можно указать набор архитектур, которые Clang должен поддерживать.
Plan 9
Примечания
Литература
- Ritchie, D. M. (октябрь 1984). “The UNIX System: The Evolution of the UNIX Time-sharing System”. AT&T Bell Laboratories Technical Journal [англ.]. 63 (8): 1577—1593. DOI:10.1002/j.1538-7305.1984.tb00054.x. Проверьте дату в
|date=(справка на английском) - 4.9 Canadian Crosses. CrossGCC. — «This is called a `Canadian Cross' because at the time a name was needed, Canada had three national parties.» Дата обращения: 8 августа 2012. Архивировано 9 октября 2004 года.
- Free Pascal Supported Platform List (англ.). Platform List. — «i386». Дата обращения: 17 июня 2010.
Ссылки
- Cross Compilation Tools — руководство по настройке GNU-кросс-компиляционных инструментов
- Сборка кросс-цепочки инструментов с помощью GCC — вики с дополнительной информацией по кросс-компиляции GCC
- Scratchbox — комплект инструментов для кросс-компиляции на Linux для платформ ARM и x86
- Grand Unified Builder (GUB) — система для Linux, позволяющая кросс-компилировать сразу для нескольких архитектур (напр., Win32/Mac OS/FreeBSD/Linux) и используемая, например, в GNU LilyPond
- Crosstool — скрипты для создания Linux-окружения кросс-компиляции, в том числе для встраиваемых систем
- crosstool-NG — современная версия Crosstool для создания toolchain-цепочек.
- buildroot — система для сборки toolchain, базирующегося на uClibc, используется, в частности, в OpenWrt.
- ELDK (Embedded Linux Development Kit) — используется в Das U-Boot.
- T2 SDE — скрипты для создания Linux-систем на базе GNU libC, uClibc или dietlibc для всех архитектур.
- Cross Linux from Scratch Project
- IBM: Учебное пособие по кросс-сборке GCC-toolchain (PDF)
- (фр.) Cross-компиляция с GCC 4 под Windows для Linux — статья о создании кросс-компилятора GCC с Windows-платформы для Linux (редкий случай)


