Особенности национальной кросс-компиляции |
12.05.2007 Золотов Алексей, http://zolotov.h14.ru |
В данной статье рассматриваются вопросы кросс-компиляции программ с помощью компилятора FreePascal, в частности вопросы компиляции и кросс-компиляции FPC (FreePascal Compiler).
Прежде чем приступать к рассмотрению кросс-компиляции уточним пару терминов, которые используются в данной статье.
Хостовая система – операционная система, на которой производиться кросс-компиляция.
Целевая система – операционная система, для которой производиться кросс-компиляция.
Примечание. В случае обычной компиляции хостовая система совпадает с целевой.
Примечание. В данной статье рассматривается только кросс-компиляция на одном процессоре (i386-совместимом), для кросс-компиляции с одного процессора для другого, возможно, будет немного иначе. У автора нет возможности проверить кросс-компиляцию с одного процессора на другой.
Прежде чем приступать к кросс-компиляции, нужно обзавестись несколькими утилитами. Далее перечисляются все необходимые утилиты, которые вам могут потребоваться, с небольшими комментариями.
Рабочий компилятор FPC на хостовой системе, т.к. без компилятора, естественно компилировать будет просто нечем. Если вы собираетесь перекомпилировать сам FPC, то вам нужен только собственно компилятор (один исполняемый файл), исходные тексты компилируемой версии FPC, а так же пакеты binutils и GNU утилит описываемых далее.
Пакет binutils. В данном пакете находятся ассемблер (as), компоновщик (ld), библиотекарь (ar) и некоторые другие полезные утилиты для разработчика. На Unix-системах, в частности Linux, binutils как правило установлен по умолчанию, даже в тех дистрибутивах, в которых нет или (по умолчанию не ставиться) пакет компиляторов GCC. В случае с Windows, нужно устанавливать binutils для Windows. Все необходимые утилиты из binutils входят в состав скомпилированного пакета FPC для Windows, поэтому если у вас установлен FPC для Windows, то у вас уже есть и binutils и необходимые GNU утилиты (см. далее). Тем не менее, для кросс-компиляции потребуется так же специальная версия bintuils для кросс-компиляции. Нужную версию binutils вы можете найти на FTP сервере ftp://ftp.freepascal.org/fpc/contrib/cross/.
GNU make. Утилита для интеллектуальной сборки программ из исходных текстов. Она потребуется для компиляции FPC и некоторых других программ. Если вы не собираетесь компилировать FPC, то можно обойтись и без нее.
Пакет GNU утилит. Это родные утилиты для Unix-систем. Сюда входят такие утилиты как pwd (выводит текущий каталог), rm (удаляет один или несколько файлов), mv (копирование файлов) и несколько других, не будем на них отвлекаться. Они требуются для перекомпиляции FPC с помощью утилиты make. Можно конечно обойтись и без них и без make и компилировать FPC вручную, но это долго и сложно, мы не будем рассматривать этот путь. Как было уже сказано, эти утилиты для Unix родные и, если у вас Unix-система, то они у вас, скорее всего, есть. Если у вас Windows, то их нужно устанавливать отдельно. Все необходимые утилиты входят в пакет FPC для Windows, поэтому если вы устанавливали FPC из скомпилированного пакета, то они у вас, скорее всего, уже есть, если же нет, то придется их устанавливать отдельно. Если вы не собираетесь компилировать FPC, то они вам и не понадобятся.
Все описанные выше утилиты должны быть доступны в командной строке без указания полного пути, т.е. они должны быть прописаны в переменной окружения PATH. Для FPC это не обязательно, т.к. при компиляции FPC с помощью make можно указать полный путь к компилятору (см. далее).
Для начала рассмотрим кросс-компиляцию простых проектов. Компилятор FPC поддерживает достаточно большой набор платформ. Чтобы посмотреть все поддерживаемые платформы можно ввести в консоли следующую команду:
fpc –i
Команда fpc – это лишь оболочка, которая запускает настоящий компилятор FPC. Настоящее имя компилятора иное, например для i386-совместимых процессоров компилятор будет называться ppc386. В общем случае имя компилятора состоит из префикса ppc, за которым следует имя архитектуры и в конце суффикс (расширение), который зависит от ОС, для которой он предназначен.
Но сам FPC только компилирует, но не компонует программы. Поэтому нужен так же пакет binutils, который содержит утилиты для работы с объектными и исполняемыми файлами целевой системы.
Рассмотрим кросс-компиляцию на простом примере. Что может быть проще Hello world?
// файл: hello.pas program Hello; begin writeln(‘Hello world’); end;
Программа простая, можно откомпилировать ее обычным способом:
fpc hello.pas
Все должно откомпилироваться и после запуска вы должны увидеть то самое Hello world. Теперь перейдем к кросс-компиляции. Для кросс-компиляции FPC поддерживает специальную опцию –T (от слова target – цель). Эта опция указывает, для какой системы нужно откомпилировать программу. Чтобы узнать какие именно значения можно передать в параметре –T можно попросить FPC вывести подсказку:
fpc –h
Среди прочих параметров, будет и описание параметра –T со списком всех поддерживаемых опций, например:
-TTarget operating system: -Temx OS/2 via EMX (including EMX/RSX extender) -Tfreebsd FreeBSD -Tgo32v2 Version 2 of DJ Delorie DOS extender -Tlinux Linux -Tnetbsd NetBSD -Tnetware Novell Netware Module (clib) -Tnetwlibc Novell Netware Module (libc) -Topenbsd OpenBSD -Tos2 OS/2 / eComStation -Tsunos SunOS/Solaris -Twatcom Watcom compatible DOS extender -Twdosx WDOSX DOS extender -Twin32 Windows 32 Bit
Так, например, для компиляции под Linux нужно указать
fpc –Tlinux hello.pas
Попробуйте. При указании системы отличной от хостовой, вы, скорее всего, получите сообщение об ошибке:
Compiling hello.pas Fatal: Can't find unit System Fatal: Compilation aborted
Причина – отсутствие модуля System. Все правильно, просто FPC не может найти RTL (Runtime library – библиотека времени выполнения) для целевой системы. Использовать RTL хостовой системы FPC не может, т.к. для разных систем RTL и (другие модули и библиотеки) отличаются. Поэтому для успешной компиляции потребуется RTL хостовой системы и настроить FPC. RTL можно взять готовый или получить перекомпиляцией. В последнем случае вам понадобятся исходные тексты компилятора (или только RTL). В следующей части статьи рассматривается компиляция RTL.
Для компиляции RTL потребуются исходные тексты компилятора (или только RTL). RTL можно компилировать двумя способами: первый – компилировать только RTL, второй – компилировать RTL вместе с компилятором. Какой путь выбирать решать вам. Нужно только учитывать то, что версии RTL и компилятора должны совпадать (т.е. должны быть из одного пакета). Поэтому если у вас одна версия компилятора, а исходные тексты другой версии, то лучше перекомпилировать и компилятор и RTL и использовать их для кросс-компиляции. Процесс компиляции компилятора рассматривается в последующих частях, в этой же части рассмотрим компиляцию одной RTL.
Компиляция довольно проста: переходим в каталог с исходными текстами RTL и запускаем утилиту make (компиляция вручную выходит за рамки статьи):
make OS_TARGET=target clean make OS_TARGET=target
Первая команда удалит из исходных текстов старые объектные файлы. Если вы уверены, что у вас чистые исходные тексты, то первую команду можно пропустить.
Параметр OS_TARGET указывает целевую систему, для которой нужно откомпилировать RTL, target – название целевой системы. Например, для компиляции под Linux команда примет следующий вид:
make OS_TARGET=linux clean make OS_TARGET=linux
В случае успешной компиляции в папке units появиться папка i386-linux (название зависит от выбранной целевой системы). В ней находятся объектные модули RTL. Можно убедиться есть ли system.ppu.
После того, как вы получили RTL для целевой системы, нужно указать компилятору, где нужно искать RTL. Можно это сделать непосредственно в командной строке:
fpc –Tlinux –Fu < путь к RTL> hello.pas
Например, если RTL лежит в папке d:\fpc_src\rtl\units\i386-linux, то команда примет следующий вид:
fpc –Tlinux –Fud:\fpc_src\rtl\units\i386-linux hello.pas
После чего FPC опять на вас поругается: RTL он теперь нашел, но компоновщик (ld) не умеет работать с используемым форматом. Причина – fpc пытается использовать ld хостовой системы, поэтому нам нужно указать, что нужно использовать ld из пакета binutils для кросс-компиляции. Для этого в FPC есть опция –FD, которая указывает где нужно искать соответствующие утилиты. Таким образом, команда перепишется в виде:
fpc –Ttarget –Fu<путь к RTL> -FD<путь к кросс-binutls> hello.pas
Следуя примеру, если у нас кросс-binutils лежит в d:\bin\i386-linux то, команда перепишется в виде:
fpc –Tlinux –Fud:\fpc_src\rtl\units\i386-linux –FDd:\bin\i386-linux hello.pas
Вот на этот раз все должно скомпилироваться и получиться рабочий бинарный файл. Остается только проверить работоспособность на целевой системе.
Каждый раз прописывать пути для кросс-компиляции не удобно. Решить данную проблему можно с помощью конфигурационного файла. В данной статье описывается лишь часть возможностей настройки компилятора с помощью конфигурационного файла. За более подробной информацией обращайтесь к соответствующей документации.
Можно, конечно же, создать несколько файлов конфигурации: один для обычной компиляции, другой для кросс-компиляции. Но лучше настроить так, чтобы один конфигурационный файл можно было использовать как для обычной компиляции, так и для кросс-компиляции. Для этого мы привлечем механизм макросов, поддерживаемый FPC, и приведем файловое дерево FPC к определенному виду.
Итак, у нас есть установленный рабочий компилятор FPC. По умолчанию он устанавливается в Windows в каталог D:pp (у вас может быть другой диск, например, C) и в Unix-системах в /usr/local/pp. Далее в примерах будем считать, что FPC установлен d:pp (замените его на свой каталог). Сам компилятор и другие вспомогательные утилиты лежат в каталоге d:/pp/bin/$FPCTARGET (d:/pp/bin/i386-win32). Утилиты binutils для кросс-компиляции будем хранить в каталоге d:/pp/bin/$FPCTARGET, где $FPCTARGET название целевой платформы (фактически это макрос автоматически создаваемый FPC).
Например, для поддержки кросс-компиляции из Windows в Linux в каталоге d:/pp/bin у нас будет следующая структура:
d:\pp\bin \i386-win32\ (здесть все остаеться как было) \i386-linux\ \ld.exe \as.exe \ar.exe \objdump.exe \strip.exe <и т.д.>
В папке d:\pp\bin\i386-linux у нас лежат кросс-версии binutils (Windows -> Linux).
Модули и RTL лежат в папке d:ppunits$FPCTARGET. В данном примере будет d:\pp\units\i386-win32, скопируем в папку d:ppunits RTL модули, полученные для других целевых систем. У нас должна получиться следующая структура:
d:\pp\units\ \i386-win32\ \rtl (RTL скомпилированная для Windows) \<другие папки с модулями для Windows> \i386-linux\ \rtl (RTL скомпилированная для Linxu) \<другие папки с модулями для Linux> \<и т.д.>
Теперь, когда структура готова, нужно подправить конфигурационный файл. В Windows, глобальный конфигурационный файл лежит в том же, каталоге где лежит сам компилятор (в нашем случае d:\pp\bin\i386-win32\fpc.cfg) и имеет имя fpc.cfg. В него нужно внести ряд изменений. Для упрощения рассмотрим минимальный конфигурационный файл. Все остальные опции вы можете добавить самостоятельно на свой вкус.
# пути к RTL и прочим модулям -Fud:\pp\units\$FPCTARGET\ -Fud:\pp\units\$FPCTARGET\* -Fud:\pp\units\$FPCTARGET\rtl # пути к утилитам компилятора (binutils) -FDd:\pp\bin\$FPCTARGET\
Вот теперь использовать кросс-компиляцию будет значительно проще. Для кросс-компиляции нашего примера будет достаточно ввести команду:
fpc –Tlinux hello.pas
Если все было сделано правильно, то FPC должен произвести рабочий исполняемый файл.
Примечание. Есть второй способ выбора пакета binutils, основанный на префиксах – имя каждой утилиты начинается на префикс, указывающий целевую платформу. Например, компоновщик ld для i386-win32 будет назваться i386-win32-ld, а для i386-linux будет i386-linux-ld. Чтобы компилятор FPC мог правильно выбрать утилиту ему нужно указать опцию –XP<префикс>, поэтому в конфигурационном файле мы прописываем
-XP$FPCTARGET-
А опцию -FDd:\pp\bin\$FPCTARGET\ убираем или переопределяем так, чтобы она указывала, где нужно искать binutils, но проще поместить все утилиты в каталог, прописанный в переменной окружения PATH, а опцию –FD убрать.
Рассмотренный пример прост до безобразия, и не имеет ни какой практической ценности. При кросс-компиляции более сложных примеров у вас снова возникнут сложности. И связанны они опять с наличием модулей. Дело в том, что мы компилировали только RTL, а в реальных проектах, как правило, требуются дополнительные модули и их тоже нужно перекомпилировать для целевой системы и поместить на свое место в d:\pp\units, чтобы FPC мог найти правильные версии модулей.
В данном разделе мы рассмотрим только компиляцию FCL и других дополнительных модулей распространяемых вместе с FPC.
Компиляция пакетов packages/base.Эти пакеты требуются для FCL. Открываем консоль в папке packages/base и исполняем команды:
make OS_TARGET=target clean make OS_TARGET=target make OS_TARGET=target install
Последняя команда установит все модули на свое законное место.
Или для нашего примера Windows -> Linux
make OS_TARGET=linux clean make OS_TARGET=linux make OS_TARGET=linux install
Компиляция FCL так же проста:
cd fcl make OS_TARGET=target clean make OS_TARGET=target make OS_TARGET=target install
Примечание. Если вы устанавливали FPC в какой-то каталог отличный от стандартного, то вам придется так же указать параметр INSTALL_PREFIX=<путь к папке pp>.
Примечание. RTL тоже можно установить с помощью make install.
Примечание. FCL может и не скомпилироваться, т.к. FCL зависит от некоторых модулей из packages, более надежный способ см. ниже.
make OS_TARGET=linux clean make OS_TARGET=linux make OS_TARGET=linux install
Компиляция пакетов packages/extra:
cd packages/extra make OS_TARGET=linux clean make OS_TARGET=linux make OS_TARGET=linux install
После этих действий в d:\pp\units\i386-linux должны быть все модули, распространяемые вместе с FPC и соответственно можно использовать кросс-компиляцию для более сложных проектов, которые требуют наличия данных модулей. Точно так же по аналогии можно устанавливать все необходимые модули сторонних разработчиков.
Все приведенные выше рассуждения полезны скорее для понимания сути. Для реального использования все можно сделать быстрее в автоматическом режиме.
Допустим, что мы уже установили компилятор FPC для Windows, внесли описанные выше изменения в fpc.cfg, создали каталог d:\pp\bin\i386-linux и поместили туда binutils для кросс-компиляции из Windows в Linux.
Если все это выполнено, то напишем небольшой командный файл (mkcross.bat):
make OS_TARGET=%1 clean @if errorlevel 1 goto exit0 make OS_TARGET=%1 all @if errorlevel 1 goto exit0 cd rtl make OS_TARGET=%1 install cd ../fcl make OS_TARGET=%1 install cd ../packages make OS_TARGET=%1 install :exit cd .. :exit0
Поместим его в папку с исходными тестами, перейдем в каталог и выполним команду:
mkcross linux
И все будет сделано автоматически. Такой вариант, пожалуй, самый надежный, но долгий, т.к. компилироваться будет все, в том числе и IDE fp. Чтобы сократить ожидание можно переписать mkcross.bat следующим образом:
@rem make RTL cd rtl make OS_TARGET=%1 clean @if errorlevel 1 goto exit1 make OS_TARGET=%1 @if errorlevel 1 goto exit1 make OS_TARGET=%1 install @if errorlevel 1 goto exit1 @rem make packages/base cd ../packages/base make OS_TARGET=%1 clean @if errorlevel 1 goto exit2 make OS_TARGET=%1 @if errorlevel 1 goto exit2 make OS_TARGET=%1 install @if errorlevel 1 goto exit2 @rem make fcl cd ../../fcl @if errorlevel 1 goto exit1 make OS_TARGET=%1 @if errorlevel 1 goto exit1 make OS_TARGET=%1 install @if errorlevel 1 goto exit1 @rem make packages/extra cd ../packages/extra @if errorlevel 1 goto exit2 make OS_TARGET=%1 @if errorlevel 1 goto exit2 make OS_TARGET=%1 install @if errorlevel 1 goto exit2 :exit2 cd .. :exit1 cd .. :exit0
В предыдущих частях мы подробно рассмотрели кросс-компиляцию в общих чертах. В этой части мы рассмотрим кросс-компиляцию самого компилятора. Все достаточно просто благодаря тому, что разработчики позаботились сделать Makefile, поддерживающий кросс-компиляцию.
Есть два способа кросс-компиляции FPC и всех программ и модулей распространяемых вместе с FPC. Первый – кросс-компиляция всего на хостовой системе, второй – кросс-компиляция компилятора с последующей компиляцией всего остального на целевой системе.
При кросс-компиляции FPC используется опция –XP, рассмотренная выше. Поэтому при кросс-компиляции утилиты binutils должны иметь префикс, например, i386-linux (для кросса из Windows в Linux) и i386-win32 (для кросса из Linux в Windows).
Кросс-компиляция всего пакета на хостовой системе. Теоретически здесь все просто: распаковываем исходные тексты в некоторый каталог, открываем в консоли каталог с исходными текстами и исполняем команды:
make OS_TARGET=target clean make OS_TARGET=target all
Первая производит очистку (можно опустить, если вы уверены, что у вас чистые исходные тексты), вторая производит кросс-компиляцию. После кросс-компиляции если все хорошо, то переносим все эти исходные тексты и все полученные исполняемые файлы и модули, которые лежат в том же каталоге, в целевую систему. Уже на целевой системе устанавливаем: переходим в папку, где у нас лежат исходные тексты и скомпилированные файлы, и выполняем одну команду:
make install
Естественно, команда make и GNU утилиты должны быть на целевой системе уже уставлены и доступны.
Но на практике данный способ не много проще второго, т.к. прежде чем делать make install, возможно, потребуется выполнить дополнительные действия... оставляю эту часть в качестве упражнения для любопытствующих.
Второй способ более надежен. Сначала нужно просто кросс-компилировать сам компилятор и затем уже им на целевой системе компилировать все остальное, так сказать в родной обстановке.
Теоретически все должно выглядеть примерно так. Исходные тексты распаковываются в некоторую папку. Затем открываем в консоль, переходим в папку с исходными текстами компилятора и исполняем команды:
make OS_TARGET=< target> PP=< compiler> clean make OS_TARGET=< target> PP=< compiler> cycle
Первая команда очищает исходные тексты от ранее скомпилированных текстов. Как, всегда, если вы уверены в чистоте исходных текстов, эту команду можно пропустить. Параметры OS_TARGET нам уже известен, а вот параметр PP задает компилятор, который следует использовать для компиляции. В большинстве случаев, если у вас корректно установлен FPC, то make сам его найдет и указывать параметр PP не нужно. Его следует указывать, если make не может его найти самостоятельно или находит компилятор неподходящей версии.
Вторая строчка запускает цикл компиляции FPC. Обратите внимание, что нужно указать цель cycle. Если все хорошо, то в папке будет лежать готовый компилятор. Теперь этот компилятор можно использовать для компиляции всего остального. Для этого нужно все исходные тексты и сам компилятор перенести на целевую систему. Далее открываем в консоли папку на целевой системе с исходными текстами и выполняем команды:
make PP=< compiler> clean make PP=< compiler> all make PP=< compiler> install
В данном случае указывать параметр обязательно, т.к. наш компилятор еще не установлен.
Примечание. Компилятор можно прописать в переменной PATH, тогда параметр PP указывать будет не нужно.
Последняя команда установит компилятор, RTL и другие утилиты и модули на свои привычные места.
И последний этап – настройка FPC – создание конфигурационного файла. Все настройки на ваш вкус, частично вопрос настройки уже рассматривался в части «Кросс-компиляция сложных примеров».
Так должно быть в общем случае. Теперь кратко рассмотрим нюансы кросс-компиляции из Windows в Linux обратно.
Будем читать, что все приготовления, описанные во второй части данной статьи, проделаны. Приведу лишь ссылку на нужный нам пакет binutils для кросс-компиляции: ftp://ftp.freepascal.org/fpc/contrib/cross/mingw/binutils-2.15-win32-i386-linux.zip.
Собственно кросс-компиляция как в теории. Распакуем исходные тексты в какой-нибудь каталог, например, d:\fpc_src. Затем откроем консоль:
d: cd d:\fpc_src\compiler make OS_TARGET=linux clean make OS_TARGET=linux cycle
В результате в папке d:\fpc_src\compiler появиться файл ppc386 (без раширения) – это и есть наш компилятор.
Вторая часть – компиляция под Linux. Скопируем (или распакуем из архива) исходные тексты, например в папку ~/fpc_src (для новичков в мире Unix/Linux: знак ~ обозначает домашний каталог). В отдельный временный каталог (например, ~/tmp) поместим наш компилятор, полученный на первом этапе. Возможно, придется поправить права доступа: компилятор должен иметь право на исполнение, на все остальное должны быть права на чтение/запись.
После этого можно компилировать:
cd ~/fpc_src make PP=~/tmp/ppc386 clean make PP=~/tmp/ppc386 all
После того, как все откомпилировалось можно устанавливать. Устанавливать нужно c правами root.
cd /home/user/fpc_src make PP=/home/user/fpc_src/ppc386 install
Где /home/user – домашний каталог пользователя, под которым производилась компиляция. После установки компилятор во временном каталоге можно удалить.
Примечание. Возможно, у вас, как и у меня, при установке компилятор ppc386 не будет перемещён на свое место. Это нужно будет подправить вручную:
cp /home/user/fpc_src/ppc386 /usr/local/bin