在CMake Superbuild中构建iOS的Boost - 构建后处理依赖性

时间:2017-10-22 07:31:27

标签: cmake

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

似乎我必须add_custom_command并致电cmake -P这使得这更加丑陋,尤其是因为我想要包含x86并将其扩展到Android。是否可以在ExternalProject_Add之后运行cmake脚本而不使用cmake -P

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 '\r\n'
    OUTPUT_VARIABLE XCODE_ROOT )

execute_process( COMMAND xcrun --sdk iphoneos --find clang++
    COMMAND tr -d '\r\n'
    OUTPUT_VARIABLE CLANG_PATH )

execute_process( COMMAND xcrun --sdk iphoneos --show-sdk-path
    COMMAND tr -d '\r\n'
    OUTPUT_VARIABLE XCODE_SYSROOT )

execute_process( COMMAND xcodebuild -showsdks
    COMMAND grep iphoneos 
    COMMAND egrep "[[:digit:]]+\.[[:digit:]]+" -o
    COMMAND tail -1
    COMMAND tr -d '\r\n'
    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 "[\r\n]+" ";" 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}" )

1 个答案:

答案 0 :(得分:0)

基本上,无论你喜欢什么,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 '\r\n' ' ' |
                                                 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}"