И тут приходит время для кросскомпиляции библиотеки для 5 архитектур: armv7, armv7s, arm64, i386, x86_64. И тут есть много подводных камней, на которые не хотелось бы наступать, когда есть уже проверенные решения. В этом коротком посте я расскажу о автоматизации сборки библиотек на примере protobuf и sqlite3.
Прежде чем что-то делать, нам надо определиться с тем что же нам надо на выходе.
- Автоматизация процесса сборки нескольких библиотек
- Удобство добавления новых библиотек
- Распространение решения внутри репозитория
- Сохранение заголовочных файлов для всех архитектур
Исходя из этих требований получилось следующее решение. Makefile, который управляет скачиванием, распаковкой, патчингом и сборкой библиотек. Код его не большой, так что можно привести тут и обсудить. (Или скачать c github и запустить, а потом читать дальше.)
Определяем путь к самому новому SDK в системе и в build_arches: запускаем этот же Makefile до arch: с заполнеными переменными ARCH и IOS_PLATFORM. После того как build_arches: отработает, запустится скрипт, который соберет для каждой из библиотек жирную fat версию.
XCODE_DEVELOPER = $(shell xcode-select --print-path) IOS_PLATFORM ?= iPhoneOS # Pick latest SDK in the directory IOS_PLATFORM_DEVELOPER = ${XCODE_DEVELOPER}/Platforms/${IOS_PLATFORM}.platform/Developer IOS_SDK = ${IOS_PLATFORM_DEVELOPER}/SDKs/$(shell ls ${IOS_PLATFORM_DEVELOPER}/SDKs | sort -r | head -n1) all: build_arches mkdir -p lib # Make fat libraries for all architectures for file in build/armv7/lib/*.a; \ do name=`basename $$file .a`; \ ${IOS_PLATFORM_DEVELOPER}/usr/bin/lipo -create \ -arch armv7 build/armv7/lib/$$name.a \ -arch armv7s build/armv7s/lib/$$name.a \ -arch arm64 build/arm64/lib/$$name.a \ -arch i386 build/i386/lib/$$name.a \ -arch x86_64 build/x86_64/lib/$$name.a \ -output lib/$$name.a \ ; \ done; echo "Making fat libs" # Build separate architectures build_arches: ${MAKE} arch ARCH=armv7 IOS_PLATFORM=iPhoneOS ${MAKE} arch ARCH=armv7s IOS_PLATFORM=iPhoneOS ${MAKE} arch ARCH=arm64 IOS_PLATFORM=iPhoneOS ${MAKE} arch ARCH=i386 IOS_PLATFORM=iPhoneSimulator ${MAKE} arch ARCH=x86_64 IOS_PLATFORM=iPhoneSimulator
Когда make будет работать над зависимостями указанными в цели arch: переменные окружения будут проинициализированы для той архитектуры, которая собирается в настоящий момент. Обратите внимание, что мы заполнили PREFIX и make install библиотек установит результат сборки в папки ./build/armv7, ./build/armv7s и т.д.
Цель arch: указывает на цели от которых она зависит. В нашем случае это библиотеки, которые мы собираем. При добавлении новых библиотек — их цели надо будет добавить в зависимости arch: иначе они не соберутся.
PREFIX = ${CURDIR}/build/${ARCH} LIBDIR = ${PREFIX}/lib INCLUDEDIR = ${PREFIX}/include CXX = ${XCODE_DEVELOPER}/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ CC = ${XCODE_DEVELOPER}/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang CFLAGS = -isysroot ${IOS_SDK} -I${IOS_SDK}/usr/include -arch ${ARCH} -miphoneos-version-min=5.0 CXXFLAGS = -stdlib=libc++ -isysroot ${IOS_SDK} -I${IOS_SDK}/usr/include -arch ${ARCH} -miphoneos-version-min=5.0 LDFLAGS = -stdlib=libc++ -isysroot ${IOS_SDK} -L${LIBDIR} -L${IOS_SDK}/usr/lib -arch ${ARCH} -miphoneos-version-min=5.0 LIBTOOLFLAGS = -arch_only ${ARCH} arch: ${LIBDIR}/libsqlite3.a ${LIBDIR}/libprotobuf.a
В последней части осталось самое простое. Цели сборки библиотек, которые зависят от целей скачивания исходников. Именно тут можно указать кастомные ключи для ./configure или добавить поддержку arm64 в protobuf.
${LIBDIR}/libsqlite3.a: ${CURDIR}/sqlite3 cd sqlite3 && env CXX=${CXX} CC=${CC} CFLAGS="${CFLAGS}" \ CXXFLAGS="${CXXFLAGS} -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61" \ LDFLAGS="${LDFLAGS}" ./configure --host=arm-apple-darwin --disable-shared --prefix=${PREFIX} && ${MAKE} clean install ${LIBDIR}/libprotobuf.a: ${CURDIR}/protobuf cd protobuf && env CXX=${CXX} CC=${CC} CFLAGS="${CFLAGS}" CXXFLAGS="${CXXFLAGS}" LDFLAGS="${LDFLAGS}" \ ./configure --host=arm-apple-darwin --disable-shared --with-protoc=/usr/local/bin/protoc --prefix=${PREFIX} && ${MAKE} clean install ${CURDIR}/sqlite3: curl https://www.sqlite.org/2014/sqlite-autoconf-3080403.tar.gz > sqlite3.tar.gz tar xzvf sqlite3.tar.gz rm sqlite3.tar.gz mv sqlite-autoconf-3080403 sqlite3 touch sqlite3 ${CURDIR}/protobuf: curl https://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz > protobuf.tar.gz tar xzvf protobuf.tar.gz rm protobuf.tar.gz mv protobuf-2.5.0 protobuf # add arm64 support https://code.google.com/p/protobuf/issues/detail?id=575 patch -p0 <protobuf_arm64.patch touch protobuf clean: rm -rf build lib sqlite3 protobuf
Минимальная комманда для сборки библиотеки — это
cd libname && env CXX=${CXX} CC=${CC} CFLAGS="${CFLAGS}" CXXFLAGS="${CXXFLAGS}" LDFLAGS="${LDFLAGS}" \ ./configure --host=arm-apple-darwin --disable-shared --prefix=${PREFIX} && ${MAKE} clean install
На выходе: в папке /lib лежат fat версии библиотек, а в build/{$ARCH}/include заголовочные файлы, которые могут пригодится в работе.
Заголовочные файлы для каждой архитектуры раздельно нужны не всегда, но встречаются библиотеки, которые на этапе ./configure в явном виде сохраняют размеры системных типов в заголовочный файл, например в config.h. Когда мы используем такой файл для arm64 и armv7 одновременно, есть риск, что что-то пойдет не так на каком-то этапе работы. И именно чтобы не гадать поломается что-то в логике работы библиотеки или или нет и не включать в проект дополнительное тестирование библиотеки на всех архитектурах в поисках проблем совместимости, я для всех fat библиотек использую раздельные версии заголовочных файлов. Сделать это просто, в Header Search Path нужно добавить "$(SRCROOT)/../../libs/build/$(arch)/include". Где /../../libs/build/ путь к папке build относительно файла xcodeproj.
Этот способ сборки я подсмотрел в github репозитории сборки растрового рендера mapnik, там же можно посмотреть более сложный вариант Makefile, когда одна библиотека зависит от нескольких других.
Файлы этого поста можно скачать с github и полюбоваться на бегущие строчки кросскомпиляции. Достаточно набрать make.
ссылка на оригинал статьи http://habrahabr.ru/post/222343/
Добавить комментарий