I'm trying to build Google protobuf project for iOS, but it's unclear how to enable iOS-specific flags such as -fembed-bitcode
and BITCODE_GENERATION_MODE=bitcode
with autotool. I've tried with the following script:
#!/bin/bash
## Environments
ScriptDir="$( cd "$( dirname "$0" )" && pwd )"
cd - &> /dev/null
# Exit the build pass if any command returns a non-zero value
#set -o errexit
# Echo commands
set -x
# 13.4.0 - Mavericks
# 14.0.0 - Yosemite
# 15.0.0 - El Capitan
# 16.0.0 - Sierra
DARWIN=darwin`uname -r`
MIN_SDK_VERSION=8.0
IPHONEOS_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path`
IPHONESIMULATOR_SYSROOT=`xcrun --sdk iphonesimulator --show-sdk-path`
# Verbose clang output
#CLANG_VERBOSE="--verbose"
CC=clang
CXX=clang
SILENCED_WARNINGS="-Wno-unused-local-typedef -Wno-unused-function"
# NOTE: Google Protobuf does not currently build if you specify 'libstdc++'
# instead of `libc++` here.
STDLIB=libc++
CFLAGS="${CLANG_VERBOSE} ${SILENCED_WARNINGS} -DNDEBUG -g -O0 -pipe -fPIC -fcxx-exceptions"
CXXFLAGS="${CFLAGS} -std=c++11 -stdlib=${STDLIB}"
LDFLAGS="-stdlib=${STDLIB}"
LIBS="-lc++ -lc++abi"
PROTOC=`which protoc`
PROTOBUF_SOURCE_DIR="$ScriptDir"
PREFIX="$ScriptDir"/_build
if [ -d ${PREFIX} ]
then
rm -rf "${PREFIX}"
fi
mkdir -p "${PREFIX}/platform" &> /dev/null
## Functions
build-arch() {
HOST=$1
ARCH=$2
PLATFORM_CFLAGS=$3
PLATFORM_NAME=${ARCH}
SYSROOT=${IPHONEOS_SYSROOT}
make distclean
./configure \
--build=x86_64-apple-${DARWIN} \
--host=${HOST} \
--with-protoc=${PROTOC} \
--disable-shared \
--prefix=${PREFIX} \
--exec-prefix=${PREFIX}/platform/${PLATFORM_NAME} \
"CC=${CC}" \
"CFLAGS=${CFLAGS} -miphoneos-version-min=${MIN_SDK_VERSION} -arch ${ARCH} -isysroot ${SYSROOT} ${PLATFORM_CFLAGS}" \
"CXX=${CXX}" \
"CXXFLAGS=${CXXFLAGS} -miphoneos-version-min=${MIN_SDK_VERSION} -arch ${ARCH} -isysroot ${SYSROOT}" \
LDFLAGS="-arch ${ARCH} -miphoneos-version-min=${MIN_SDK_VERSION} ${LDFLAGS}" \
"LIBS=${LIBS}"
make -j8
make install
}
build-i386-simulator() {
ARCH=i386
HOST=${ARCH}-apple-${DARWIN}
PLATFORM_NAME=${ARCH}-simulator
SYSROOT=${IPHONESIMULATOR_SYSROOT}
make distclean
./configure \
--build=x86_64-apple-${DARWIN} \
--host=${HOST} \
--with-protoc=${PROTOC} \
--disable-shared \
--prefix=${PREFIX} \
--exec-prefix=${PREFIX}/platform/${PLATFORM_NAME} \
"CC=${CC}" \
"CFLAGS=${CFLAGS} -mios-simulator-version-min=${MIN_SDK_VERSION} -arch ${ARCH} -isysroot ${SYSROOT}" \
"CXX=${CXX}" \
"CXXFLAGS=${CXXFLAGS} -mios-simulator-version-min=${MIN_SDK_VERSION} -arch ${ARCH} -isysroot ${SYSROOT}" \
LDFLAGS="-arch ${ARCH} -mios-simulator-version-min=${MIN_SDK_VERSION} ${LDFLAGS}" \
"LIBS=${LIBS}"
make -j8
make install
}
build-x86_64-simulator() {
ARCH=x86_64
PLATFORM_NAME=${ARCH}-simulator
SYSROOT=${IPHONESIMULATOR_SYSROOT}
make distclean
./configure --prefix=${PREFIX} \
--exec-prefix=${PREFIX}/platform/${PLATFORM_NAME} \
--with-sysroot=${SYSROOT} \
--with-protoc=`which protoc` \
--enable-static \
--disable-shared
make -j8
make install
}
build-fat-lib() {
OUT=${PREFIX}/universal
mkdir -p ${OUT}
PLATFORM_ROOT=${PREFIX}/platform
LIPO=lipo
LIB=libprotobuf.a
${LIPO} ${PLATFORM_ROOT}/arm64/lib/${LIB} \
${PLATFORM_ROOT}/armv7/lib/${LIB} \
${PLATFORM_ROOT}/x86_64-simulator/lib/${LIB} \
${PLATFORM_ROOT}/i386-simulator/lib/${LIB} \
-create \
-output ${OUT}/${LIB}
LIB_LITE=libprotobuf-lite.a
${LIPO} ${PLATFORM_ROOT}/arm64/lib/${LIB_LITE} \
${PLATFORM_ROOT}/armv7/lib/${LIB_LITE} \
${PLATFORM_ROOT}/x86_64-simulator/lib/${LIB_LITE} \
${PLATFORM_ROOT}/i386-simulator/lib/${LIB_LITE} \
-create \
-output ${OUT}/${LIB_LITE}
}
## Build pass
cd ${PROTOBUF_SOURCE_DIR}
./autogen.sh
build-x86_64-simulator
build-i386-simulator
build-arch arm arm64 "BITCODE_GENERATION_MODE=bitcode -fembed-bitcode"
build-arch armv7-apple-${DARWIN} armv7 -fembed-bitcode
build-fat-lib
echo DONE!
In the above script, I tried to pass my intended options through CFLAGS, which didn't work: The build of protobuf libs via this script passes, but linking against the output Universal libs with another Xcode project fails. So clearly the bitcode wasn't included, i.e., the flags didn't work.
I wonder if it's impossible to achieve what I do with autotool alone. Should I create a real Xcode project for this purpose?
The Autotools provide a framework for building and maintaining build systems. They do provide some standardization, but to a large extent, the capabilities of an Autotools-based build system are project specific.
But with that said, your script is not passing anything to configure
via CFLAGS
, CC
, or any of the rest. These are environment variables recognized by configure
, but you are attempting to convey them as arguments, instead. That's the best way to do it if you want to inject those arguments at the make
step, but it does not by default work at all for configure
. Shell syntax requires variable assignments to precede the command name, so, for example:
"CC=${CC}" \
"CFLAGS=${CFLAGS} -miphoneos-version-min=${MIN_SDK_VERSION} -arch ${ARCH} -isysroot ${SYSROOT} ${PLATFORM_CFLAGS}" \
"CXX=${CXX}" \
"CXXFLAGS=${CXXFLAGS} -miphoneos-version-min=${MIN_SDK_VERSION} -arch ${ARCH} -isysroot ${SYSROOT}" \
LDFLAGS="-arch ${ARCH} -miphoneos-version-min=${MIN_SDK_VERSION} ${LDFLAGS}" \
"LIBS=${LIBS}" \
./configure \
--build=x86_64-apple-${DARWIN} \
--host=${HOST} \
--with-protoc=${PROTOC} \
--disable-shared \
--prefix=${PREFIX} \
--exec-prefix=${PREFIX}/platform/${PLATFORM_NAME}
Or you could just set and export
those variables via one or more separate commands preceding configure
.
Also, as an aside, make distclean
doesn't do what you want when there is no makefile, which is the case in an Autotools project that has not yet been configured. You ought to protect against failures there by making execution of that command conditional on the existence of the top-level makefile.