Некоторое время назад я начал свой кроссплатформенный проект. Поскольку сижу я в основном за Windows, то для компиляции обычно использую cygwin, а для сборки билдов для тестеров под cygwin живет i686-w64-mingw. Все было хорошо, но вот пришла пора, и для вывода пары фраз текста я решил подключить к проекту libfreetype. При компиляции на cygwin проблем нет — ведь в репозитории есть соответствующий пакет, ну а для mingw, естественно, придется собирать либу самому.
Дабы ко мне не было вопросов, я решил подключать либу динамично, а все ее зависимости (чтобы не тащить кучу левых файлов) линковать статично. О моем горьком опыте я здесь и расскажу.
Для начала немного теории. В любом проекте на autotools кросс-компиляция легко реализуется с помощью двух основных параметров:
--build
— указывает имя среды, в которой мы компилируем--host
— указывает имя среды, в которой результат будет запускаться
Важно не путать эти ключи, устанавливать оба в mingw32 — тоже не лучший вариант (ведь он и правда поверит, что вы работаете в MSYS).
В итоге, строка конфигурации будет выглядеть следующим образом:
1 |
LDFLAGS="-static-libgcc" ./configure --prefix=/usr/local/freetype --host=i686-w64-mingw32 --build=i686-pc-cygwin --disable-static |
Но не спешите ее выполнять.
freetype имеет 2 зависимости: libz и libbz2, — их статические версии для mingw мы уже как бы собрали ранее. И если сейчас попытаться скомпилировать freetype, libtool на них ругнется: мол, мы тут динамические библиотеки компилирует, нефиг тут статику мне совать. В чем то он прав, но нам все же придется как-то обойти это ограничение. Самое простое решение — передать ключи библиотек напрямую линкеру:
1 |
sed -i -e "s/LIBZ='-lz'/LIBZ='-Wl,-lz'/" -e "s/LIBBZ2='-lbz2'/LIBBZ2='-Wl,-lbz2'/" builds/unix/configure |
Запускаем сборку — все прекрасно! Только… почему-то в экспорте dll не только freetype, но и libz и libbz2! С чего бы это?
Причина кроется в ключе -no-undefined
. Есть два способа добавить функции на экспорт: специальные атрибуты у нужных функций и ключ -no-undefined
, тогда все функции будут в экспорте. Как с этим бороться? На помощь приходит -export-symbols
, чтобы его активировать, выполним:
1 |
sed -i -e "s/-no-undefined//" -e "s/# -export-symbols/-export-symbols/" builds/unix/unix-cc.in |
Если сейчас запустить сборку libtool ругнется что win32 не может иметь неопределенные символы в экспорте и соберет статическую либу. Чтобы отключить такое поведение нужен еще один патч:
1 |
sed -i "s/allow_undefined_flag=unsupported//" builds/unix/configure |
Но сборка все еще не работает. Все из-за того, что, повторюсь, win32 не может иметь неопределенные символы в экспорте. Он просто ругнется на несколько функций, которых у нас нет. А именно, относящиеся к Mac. Все, что надо сделать, удалить ненужный header:
1 |
echo > include/freetype/ftmac.h |
Последний штрих (активация улучшенных алгоритмов):
1 |
sed -i -r 's:.*(#.*SUBPIXEL.*) .*:\1:' include/freetype/config/ftoption.h |
Теперь все легко соберется!
Полный скрипт:
1 2 3 4 5 6 7 |
sed -i -r 's:.*(#.*SUBPIXEL.*) .*:\1:' include/freetype/config/ftoption.h sed -i -e "s/allow_undefined_flag=unsupported//" -e "s/LIBZ='-lz'/LIBZ='-Wl,-lz'/" -e "s/LIBBZ2='-lbz2'/LIBBZ2='-Wl,-lbz2'/" builds/unix/configure sed -i -e "s/-no-undefined//" -e "s/# -export-symbols/-export-symbols/" builds/unix/unix-cc.in echo > include/freetype/ftmac.h CFLAGS="-O3" LDFLAGS="-static-libgcc" ./configure --prefix=/usr/local/freetype --host=i686-w64-mingw32 --build=i686-pc-cygwin --disable-static make make install |
В конце можно стрипнуть либу (лежит в /usr/local/freetype/bin), сжать upx, обрубить с помощью rebuildpe, обновить скрипты pkg-config и aclocal и радоваться жизни! Надеюсь вы не будете наступать на мои грабли.
Удачи!