How can I make Cmake use specific compiler and flags when final compilation stage instead of detection?

eonil picture eonil · Jun 25, 2011 · Viewed 16.4k times · Source

I'm trying to cross-compiling from Mac OS X to iOS. It was easy using clang to cross-compile a source to iOS target. We need only 3 parameters get it to work.

clang
-arch armv6
-isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk
-miphoneos-version-min=4.3

But the problem is I have to build a library (Bullet Physics) packaged with Cmake. And as far as I know, Cmake has no iOS support yet.

So, I made a toolchain file.

SET (CMAKE_SYSTEM_NAME      "Generic")
SET (CMAKE_SYSTEM_VERSION   "4.3")
SET (CMAKE_SYSTEM_PROCESSOR "arm")
SET (CMAKE_CROSSCOMPILING   TRUE)

SET (SDKVER "4.3")
SET (DEVROOT "/Developer/Platforms/iPhoneOS.platform/Developer")
SET (SDKROOT "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk")
SET (CMAKE_OSX_SYSROOT "${SDKROOT}")
SET (CMAKE_OSX_ARCHITECTURES "armv6" "armv7")

SET (CMAKE_C_COMPILER   "${DEVROOT}/usr/bin/clang")
SET (CMAKE_CXX_COMPILER "${DEVROOT}/usr/bin/clang++")
SET (CMAKE_C_FLAGS      "-arch armv6 -arch armv7 -isysroot ${SDKROOT} -std=c99 -x objective-c -DNDEBUG=1")
SET (CMAKE_CXX_FLAGS    "-arch armv6 -arch armv7 -isysroot ${SDKROOT} -x objective-c++ -DNDEBUG=1")

SET (CMAKE_EXE_LINKER_FLAGS    "-miphoneos-version-min=${SDKVER}")
SET (CMAKE_SHARED_LINKER_FLAGS "-miphoneos-version-min=${SDKVER}")
SET (CMAKE_MODULE_LINKER_FLAGS "-miphoneos-version-min=${SDKVER}")

SET (CMAKE_FIND_ROOT_PATH              "${SDKROOT}" "${DEVROOT}")
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

And executed.

cmake   -DCMAKE_TOOLCHAIN_FILE=../CMAKE_IPHONEOS_TOOLCHAIN.cmake ../bullet-2.78

cmake itself done well. make done well. All build complete without any error. However built binary was x64 non-fat binary instead of armv6/armv7 fat binary. Generated Makefile doesn't work for cross-compile. It doesn't seem to use compiler and flags (including -isysroot) when building. How can I make it use the parameters?

Answer

eonil picture eonil · Jun 25, 2011

I solved this and built Bullet Physics for iOS.

Solution

Here's toolchain configuration that I used.

INCLUDE(CMakeForceCompiler)

SET (CMAKE_CROSSCOMPILING   TRUE)
SET (CMAKE_SYSTEM_NAME      "Darwin")
SET (CMAKE_SYSTEM_PROCESSOR "arm")

SET (SDKVER     "4.3")
SET (DEVROOT    "/Developer/Platforms/iPhoneOS.platform/Developer")
SET (SDKROOT    "/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDKVER}.sdk")
SET (CC         "${DEVROOT}/usr/bin/clang")
SET (CXX        "${DEVROOT}/usr/bin/clang++")

CMAKE_FORCE_C_COMPILER          (${CC} CLang)
CMAKE_FORCE_CXX_COMPILER        (${CXX} CLang)

SET (CMAKE_FIND_ROOT_PATH               "${SDKROOT}" "${DEVROOT}")
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM  NEVER)
SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY  ONLY)
SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE  ONLY)

And the build script. This is important!

PKG_NAME=bullet-2.78
BUILD_DIR=build

rm      -rf ${PKG_NAME} ${BUILD_DIR}
tar     -x -f ${PKG_NAME}-r2387.tar

mkdir   build
cd      build

DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
SYSROOT=$DEVROOT/SDKs/iPhoneOS4.3.sdk
CC=$DEVROOT/usr/bin/clang
CXX=$DEVROOT/usr/bin/clang++
CFLAGS="-arch armv6 -arch armv7 -isysroot $SYSROOT -miphoneos-version-min=4.0"
CXXFLAGS=$CFLAGS
LDFLAGS=$CFLAGS

export  CC=$CC
export  CXX=$CXX
export  CFLAGS=$CFLAGS
export  CXXFLAGS=$CXXFLAGS
export  LDFLAGS=$LDFLAGS

cmake   ../$PKG_NAME -DCMAKE_TOOLCHAIN_FILE=../CMAKE_IPHONEOS_TOOLCHAIN.cmake
make
lipo    -info src/LinearMath/libLinearMath.a

This is very minimal configuration. However you got the idea.

Description

First, the toolchain configuration is just a stage figuring out features available on target machine. But cross compilation to iOS require some special compiler flags, and this is exception situation described on Cmake wiki.

So I just forced specific compiler, and Cmake will skip compiler verification stage.

Second, all compiler flags needed for cross compilation offered via shell variable export in build script. This is very rough options, however important is we have to pass via shell variables. Not with toolchain configuration.

However some kind of toolchain configuration affects on generated Makefile. We have to specify correct CMAKE_SYSTEM_NAME (Darwin) and CMAKE_SYSTEM_PROCESSOR (arm).


Update

There is another trials. Anyway these don't work for me anymore.

Here's one more. This looks promising.

Update 2

Now Bullet includes a build script for iOS platforms. Anyway it's inconvenient because it does not handle special needs for simulator stuffs, and I wrote another build script which makes far library for debug/release mode.

https://github.com/Eonil/Bullet-PhysicsEngine-BuildScript