在 CMake 超级构建中为 iOS 构建 Boost - 构建后处理依赖项



我正在努力在超级构建中构建 Boost,但 Boost 坚持使用 -arch arm 进行编译(所有其他架构必须手动添加),其中包括二进制文件中的armv4t。因此,构建后,我想滚动库并使用 lipo 删除无效的架构。在CMake中没有办法在CMake中做到这一点吗?

看来我必须add_custom_command并调用cmake -P,这使它变得更加丑陋,特别是因为我想包含x86并将其扩展到Android。是否可以在没有cmake -P的情况下在ExternalProject_Add后运行 cmake 脚本?

include( ExternalProject )
set( NCPU 8 )
set( MIN_IOS_VERSION 8.0 )
set( BOOST_VERSION 1.63.0 )
set( BOOST_SHA_CHECKSUM 9f1dd4fa364a3e3156a77dc17aa562ef06404ff6 )
set( BOOST_COMPILE_LIBRARIES filesystem system date_time )
set( COMPILE_ARCHITECTURES armv6 armv7 armv7s arm64 )
set( ENABLE_BITCODE true )
string( REPLACE "." "_" BOOST_FILENAME "boost_${BOOST_VERSION}" )
set( boost_URL "http://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/${BOOST_FILENAME}.tar.bz2" )
set( boost_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/third_party/boost )
set( boost_INCLUDE_DIR ${boost_INSTALL}/include )
set( boost_LIB_DIR ${boost_INSTALL}/lib )
execute_process( COMMAND xcrun --sdk iphoneos --show-sdk-platform-path
    COMMAND tr -d 'rn'
    OUTPUT_VARIABLE XCODE_ROOT )
execute_process( COMMAND xcrun --sdk iphoneos --find clang++
    COMMAND tr -d 'rn'
    OUTPUT_VARIABLE CLANG_PATH )
execute_process( COMMAND xcrun --sdk iphoneos --show-sdk-path
    COMMAND tr -d 'rn'
    OUTPUT_VARIABLE XCODE_SYSROOT )
execute_process( COMMAND xcodebuild -showsdks
    COMMAND grep iphoneos 
    COMMAND egrep "[[:digit:]]+.[[:digit:]]+" -o
    COMMAND tail -1
    COMMAND tr -d 'rn'
    OUTPUT_VARIABLE IOS_SDK_VERSION )
message( STATUS "IOS SDK Version ${IOS_SDK_VERSION}" )
string( REPLACE ";" "," BOOST_WITH_LIBRARIES "${BOOST_COMPILE_LIBRARIES}" )
message( STATUS "Compile Boost libraries ${BOOST_WITH_LIBRARIES}" )
set( COMPILEFLAGS )
foreach( COMPILE_ARCHITECTURE ${COMPILE_ARCHITECTURES} )
    set( COMPILEFLAG "<compileflags>"-arch ${COMPILE_ARCHITECTURE}"" )
    list( APPEND COMPILEFLAGS ${COMPILEFLAG} )
endforeach( COMPILE_ARCHITECTURE )
if( ENABLE_BITCODE )
list( APPEND COMPILEFLAGS "<compileflags>-fembed-bitcode" )
endif( ENABLE_BITCODE )
string( REPLACE ";" "n" COMPILEFLAGS_FINAL "${COMPILEFLAGS}" )
set( USER_CONFIG_JAM
"using darwin : ${IOS_SDK_VERSION}~iphone :
${CLANG_PATH} :
<striper>
<root>${XCODE_ROOT}/Developer
<compileflags>-mios-version-min=${MIN_IOS_VERSION}
<compileflags>-std=c++11
<compileflags>-stdlib=libc++
<compileflags>-fvisibility-inlines-hidden
<compileflags>--sysroot=${XCODE_SYSROOT}
${COMPILEFLAGS_FINAL}
;
" )
file( WRITE ${CMAKE_BINARY_DIR}/user-config.jam ${USER_CONFIG_JAM} )
ExternalProject_Add( external_boost
        PREFIX boost
        URL ${boost_URL}
        URL_HASH SHA1=${BOOST_SHA_CHECKSUM}
        BUILD_IN_SOURCE 1
        CONFIGURE_COMMAND ./bootstrap.sh
            --with-libraries=${BOOST_WITH_LIBRARIES}
            --prefix=<INSTALL_DIR>
        COMMAND ${CMAKE_COMMAND} -E remove <SOURCE_DIR>/tools/build/src/user-config.jam
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/user-config.jam <SOURCE_DIR>/tools/build/src/user-config.jam
        BUILD_COMMAND ./b2
            -d+2
            -j${NCPU}
            --reconfigure
            architecture=arm
            address-model=32_64
            toolset=darwin
            target-os=iphone
            macosx-version=iphone-${IOS_SDK_VERSION}
            define=_LITTLE_ENDIAN
            link=static
            variant=release
            install
        INSTALL_COMMAND ""
        INSTALL_DIR ${boost_INSTALL} )
set( BOOST_LIBRARY_SUFFIX .a )
# Expected output filenames for the boost libraries
set( BOOST_RESULT_LIBRARIES )
foreach( BOOST_COMPILE_LIBRARY ${BOOST_COMPILE_LIBRARIES} )
    set( LIBRARY_NAME libboost_${BOOST_COMPILE_LIBRARY}${BOOST_LIBRARY_SUFFIX} )
    list( APPEND BOOST_RESULT_LIBRARIES ${LIBRARY_NAME} )
endforeach( BOOST_COMPILE_LIBRARY )
add_dependencies( BOOST_COMPILE_LIBRARY external_boost )
# Check each static library for the included architectures and toss anything that shouldn't be included
foreach( BOOST_RESULT_LIBRARY ${BOOST_RESULT_LIBRARIES} )
    execute_process( COMMAND lipo -info ${boost_LIB_DIR}/${BOOST_RESULT_LIBRARY}
        COMMAND egrep "armv?[[:digit:]]+[[:lower:]]*" -o
        OUTPUT_VARIABLE ARCHIVE_LIBRARY_ARCHITECTURES )
    string(REGEX REPLACE "[rn]+" ";" ARCHIVE_LIBRARY_ARCHITECTURES ${ARCHIVE_LIBRARY_ARCHITECTURES} )
    set( REMOVE_ARCHITECTURES )
    foreach( ARCHIVE_LIBRARY_ARCHITECTURE ${ARCHIVE_LIBRARY_ARCHITECTURES} )
        list( FIND COMPILE_ARCHITECTURES ${ARCHIVE_LIBRARY_ARCHITECTURE} CONTAINS_ARCHITECTURE )
        if( NOT CONTAINS_ARCHITECTURE )
            list( APPEND REMOVE_ARCHITECTURES ${ARCHIVE_LIBRARY_ARCHITECTURE} )
        endif( NOT CONTAINS_ARCHITECTURE )
    endforeach( ARCHIVE_LIBRARY_ARCHITECTURE )
    foreach( REMOVE_ARCHITECTURE ${REMOVE_ARCHITECTURES} )
        execute_process( COMMAND lipo -remove ${REMOVE_ARCHITECTURE} -output ${BOOST_RESULT_LIBRARY} )
    endforeach( REMOVE_ARCHITECTURE )
endforeach( BOOST_RESULT_LIBRARY )
message( STATUS "${LIBRARY_ARCHITECTURES}" )
基本上

,无论您喜欢什么,Boost都会始终注入-arch arm。最后,我改用 shell 脚本来构建 Boost 并清理它。鉴于Boost有自己的构建系统,这可能已经足够好了。

以下代码使用 cmake 下载并启动 Boost 编译脚本。

boost.cmake

include( ExternalProject )
set_property( DIRECTORY PROPERTY EP_BASE third_party )
set( BOOST_URL "http://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.tar.bz2" )
set( BOOST_SHA1 "9f1dd4fa364a3e3156a77dc17aa562ef06404ff6" )
set( BOOST_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/boost )
set( BOOST_INCLUDE_DIR ${BOOST_INSTALL}/include )
set( BOOST_LIB_DIR ${BOOST_INSTALL}/lib )
list( APPEND DEPENDENCIES external_boost )
set( DEPENDENCIES "${DEPENDENCIES}" PARENT_SCOPE )
ExternalProject_Add( external_boost
        PREFIX boost
        URL ${BOOST_URL}
        BUILD_IN_SOURCE 1
        CONFIGURE_COMMAND ""
        COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/cmake/lipo-library.sh <SOURCE_DIR>
        BUILD_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/boost-compile.sh <SOURCE_DIR> <INSTALL_DIR>
        INSTALL_COMMAND ""
        INSTALL_DIR ${BOOST_INSTALL} )
list( APPEND EXTRA_CMAKE_ARGS
        -DBOOST_ROOT=${BOOST_INSTALL}
        -DBoost_NO_SYSTEM_PATHS=ON )
set( EXTRA_CMAKE_ARGS "${EXTRA_CMAKE_ARGS}" PARENT_SCOPE )

boost-compile.sh

#!/bin/bash
SOURCE_DIR="$1"
INSTALL_DIR="$2"
BOOST_MODULES=( "date_time" "system" "filesystem" )
VERBOSE_LOGGING=false
FORCE_REBUILD=true
NCPU=8
MIN_IOS_VERSION="8.0"
ENABLE_BITCODE=true
ARCHITECTURE_FAMILIES=( "arm" "x86" )
X86_COMPILE_ARCHITECTURES=( "i386" "x86_64" )
ARM_COMPILE_ARCHITECTURES=( "armv7" "armv7s" "arm64" )
ALL_ARCHITECTURES=( "${X86_COMPILE_ARCHITECTURES[@]}" "${ARM_COMPILE_ARCHITECTURES[@]}" )
echo "Building Boost libraries ${BOOST_MODULES[*]}"
RESULTS_DIRECTORIES=()
for ARCHITECTURE_FAMILY in "${ARCHITECTURE_FAMILIES[@]}"; do
    SDK=""
    TARGET_OS="iphone"
    if [[ "${ARCHITECTURE_FAMILY}" == "arm" ]]; then
        SDK="iphoneos"
        SDK_SHORT="iphone"
    elif [[ "${ARCHITECTURE_FAMILY}" == "x86" ]]; then
        SDK="iphonesimulator"
        SDK_SHORT="iphonesim"
    fi
    XCODE_PLATFORM_PATH="$(xcrun --sdk ${SDK} --show-sdk-platform-path )"
    XCODE_IOS_CLANG_PATH="$( xcrun --sdk ${SDK} -f clang++ )"
    XCODE_SDK_VERSION="$( xcrun --sdk ${SDK} --show-sdk-version )"
    PLATFORM_NAME="darwin"
    TOOLSET_PREFIX="${PLATFORM_NAME}"
    TOOLSET_SUFFIX="${XCODE_SDK_VERSION}~${SDK_SHORT}"
    TOOLSET="${TOOLSET_PREFIX}-${TOOLSET_SUFFIX}"
    MACOSX_VERSION="${SDK_SHORT}-${XCODE_SDK_VERSION}"
    if [[ "${ARCHITECTURE_FAMILY}" == "arm" ]]; then
        SDK_LONG="iPhoneOS${XCODE_SDK_VERSION}.sdk"
#        TOOLSET="${TOOLSET_PREFIX}"
    elif [[ "${ARCHITECTURE_FAMILY}" == "x86" ]]; then
        SDK_LONG="iPhoneSimulator${XCODE_SDK_VERSION}.sdk"
    fi
    echo "Using toolset ${TOOLSET}"
    RESULTS_DIRECTORY="${INSTALL_DIR}/${SDK_LONG}-${ARCHITECTURE_FAMILY}"
    mkdir -p "${RESULTS_DIRECTORY}"
    CXXFLAGS=()
    if [[ "${ARCHITECTURE_FAMILY}" == "arm" ]]; then
        for ARM_COMPILE_ARCHITECTURE in "${ARM_COMPILE_ARCHITECTURES[@]}"; do
            CXXFLAGS+=( "-arch ${ARM_COMPILE_ARCHITECTURE}" )
        done
    fi
    USER_CONFIG_JAM=()
    USER_CONFIG_JAM+=( "using ${TOOLSET_PREFIX} : ${TOOLSET_SUFFIX} :" )
    USER_CONFIG_JAM+=( "${XCODE_IOS_CLANG_PATH} :" )
    USER_CONFIG_JAM+=( "<striper>" )
    USER_CONFIG_JAM+=( "<root>${XCODE_PLATFORM_PATH}/Developer" )
    USER_CONFIG_JAM+=( "<compileflags>-std=c++11" )
    USER_CONFIG_JAM+=( "<compileflags>-stdlib=libc++" )
    USER_CONFIG_JAM+=( "<compileflags>-fvisibility-inlines-hidden" )
    USER_CONFIG_JAM+=( "<compileflags>-mios-version-min=${MIN_IOS_VERSION}" )
    if [[ "${ENABLE_BITCODE}" ]]; then
        USER_CONFIG_JAM+=( "<compileflags>-fembed-bitcode" )
    fi
    USER_CONFIG_JAM+=( ": <architecture>${ARCHITECTURE_FAMILY} <target-os>${TARGET_OS}" )
    USER_CONFIG_JAM+=( ";" )
    USER_CONFIG_STRING=$( IFS=$'n'; echo "${USER_CONFIG_JAM[*]}" )
    echo "Creating ${SOURCE_DIR}/tools/build/src/user-config.jam"
    echo "${USER_CONFIG_STRING}" > "${SOURCE_DIR}/tools/build/src/user-config.jam"
    WITH_LIBRARIES=$( IFS=$','; echo "${BOOST_MODULES[*]}" )
    echo "Boostrap Boost"
    BOOTSTRAP_OPTIONS=()
    BOOTSTRAP_OPTIONS+=( "--with-libraries=${WITH_LIBRARIES}" )
    BOOTSTRAP_OPTIONS+=( "--prefix=${RESULTS_DIRECTORY}" )
    ./bootstrap.sh "${BOOTSTRAP_OPTIONS[@]}"
    ./b2 --clean-all
    echo "B2 Boost"
    B2_OPTIONS=()
    if [[ "${VERBOSE_LOGGING}" ]]; then
        B2_OPTIONS+=( "-d+2" )
    fi
    if [[ "${FORCE_REBUILD}" ]]; then
        B2_OPTIONS+=( "-a" )
    fi
    B2_OPTIONS+=( "-j${NCPU}" )
    B2_OPTIONS+=( "--reconfigure" )
    B2_OPTIONS+=( "architecture=${ARCHITECTURE_FAMILY}" )
    B2_OPTIONS+=( "address-model=32_64" )
    B2_OPTIONS+=( "toolset=${TOOLSET}" )
    B2_OPTIONS+=( "target-os=${TARGET_OS}" )
    if [[ "${#CXXFLAGS[@]}" -gt 0 ]]; then
        B2_OPTIONS+=( "cxxflags=${CXXFLAGS[*]}" )
    fi
    B2_OPTIONS+=( "macosx-version=${MACOSX_VERSION}" )
    if [[ "${ARCHITECTURE_FAMILY}" == "arm" ]]; then
        B2_OPTIONS+=( "define=_LITTLE_ENDIAN" )
    fi
    B2_OPTIONS+=( "link=static" )
    B2_OPTIONS+=( "threading=single" )
    B2_OPTIONS+=( "variant=release" )
    B2_OPTIONS+=( "install" )
    echo "./b2 ${B2_OPTIONS[*]}"
    ./b2 "${B2_OPTIONS[@]}"
    RESULTS_DIRECTORIES+=( "${RESULTS_DIRECTORY}" )
done
echo "Create FAT Boost libraries"
FAT_INSTALL_INCLUDE_DIR="${INSTALL_DIR}/include"
FAT_INSTALL_LIBARY_DIR="${INSTALL_DIR}/lib"
mkdir -p "${FAT_INSTALL_INCLUDE_DIR}" "${FAT_INSTALL_LIBARY_DIR}"
BOOST_LIBRARIES=()
for BOOST_MODULE in "${BOOST_MODULES[@]}"; do
    BOOST_LIBRARIES+=( "libboost_${BOOST_MODULE}.a" )
done
FAT_LIBBOOST_MODULE_INSTALL_PATHS=()
for BOOST_LIBRARY in "${BOOST_LIBRARIES[@]}"; do
    FAT_LIBBOOST_MODULE_INSTALL_PATH="${FAT_INSTALL_LIBARY_DIR}/${BOOST_LIBRARY}"
    rm -rf "${FAT_LIBBOOST_MODULE_INSTALL_PATH}"
    FAT_LIBBOOST_MODULE_INSTALL_PATHS=( "${FAT_LIBBOOST_MODULE_INSTALL_PATH}" )
    INCLUDES_DIRS=()
    INTERMEDIATES=()
    for RESULTS_DIRECTORY in "${RESULTS_DIRECTORIES[@]}"; do
        INCLUDES_DIRS+=( "${RESULTS_DIRECTORY}/include/" )
        INTERMEDIATES+=( "${RESULTS_DIRECTORY}/lib/${BOOST_LIBRARY}" )
    done
    for INCLUDES_DIR in "${INCLUDES_DIRS[@]}"; do
        cp -R "${INCLUDES_DIR}" "${FAT_INSTALL_INCLUDE_DIR}"
    done
    if [[ "${#INTERMEDIATES[@]}" -gt 0 ]]; then
        lipo -output "${FAT_LIBBOOST_MODULE_INSTALL_PATH}" -create "${INTERMEDIATES[@]}"
    fi
done
echo "Cleaning up Boost build intermediates ${RESULTS_DIRECTORIES[*]}"
rm -rf "${RESULTS_DIRECTORIES[@]}"
echo "Validate Boost libraries contain desired architectures ${ALL_ARCHITECTURES[*]}"
SUCCESS=1
for FAT_LIBBOOST_MODULE_INSTALL_PATH in "${FAT_LIBBOOST_MODULE_INSTALL_PATHS[@]}"; do
    "${SOURCE_DIR}/lipo-library.sh" "${FAT_LIBBOOST_MODULE_INSTALL_PATH}" "${ALL_ARCHITECTURES[@]}"
    SUCCESS=$?
    if [[ ${SUCCESS} -ne 0 ]]; then
        break
    fi
done
exit "${SUCCESS}"

lipo-library.sh

#!/bin/bash
contains() {
    local match="$1"
    shift
    local list=( "${@}" )
    for item in "${list[@]}"; do
        if [[ "${item}" == "${match}" ]]; then
            echo true
            return 1
        fi
    done
    echo false
    return 0
}
library="$1"
shift
valid_architectures=( "${@}" )
if [ -z "${library}" ] || [ ! "${#valid_architectures[@]}" -gt 0 ]; then
    echo "Usage: $0 <library> <architecture ...>"
    exit 1
fi
echo "Library to check ${library}"
echo "Required architectures ${valid_architectures[*]}"
# Check static library for the included architectures and toss anything that shouldn't be included
declare -a archive_library_architectures=()
# Handle finding the architectures in a static library, fat or not.
read -r -a archive_library_architectures <<< "$( lipo -detailed_info "${library}" |
                                                 grep architecture |
                                                 sed -e 's/.*architecture:{0,1} {0,1}//' |
                                                 tr 'rn' ' ' |
                                                 xargs echo -n )"
echo "${library} contains ${archive_library_architectures[*]}"
missing_architectures=()
for valid_architecture in "${valid_architectures[@]}"; do
    has_architecture=$( contains "${valid_architecture}" "${archive_library_architectures[@]}" )
    if [[ "${has_architecture}" = false ]]; then
        missing_architectures+=( "${valid_architecture}" )
    fi
done
if [ "${#missing_architectures[@]}" -gt 0 ]; then
    echo "${library} missing ${missing_architectures[*]}"
fi
invalid_architectures=()
for archive_library_architecture in "${archive_library_architectures[@]}"; do
    has_architecture=$( contains "${archive_library_architecture}" "${valid_architectures[@]}" )
    if [[ "${has_architecture}" = false ]]; then
        invalid_architectures+=( "${archive_library_architecture}" )
    fi
done
if [ "${#invalid_architectures[@]}" -gt 0 ]; then
    echo "${library} invalid ${invalid_architectures[*]}"
fi
for invalid_architecture in "${invalid_architectures[@]}"; do
    echo "lipo -remove ${invalid_architecture} -output ${library} $library"
    lipo -remove "${invalid_architecture}" -output "${library}" "$library"
done
lipo "${library}" -verify_arch "${valid_architectures[@]}"
result=$?
if [ "${result}" = 0 ]; then
    echo "Successfully built ${library} with desired architectures"
else
    echo "Failed to build ${library} with desired architectures"
fi
exit "${result}"

最新更新