sunkehappy / icu-ios

This is a ICU sub project for iOS project integration.
13 stars 3 forks source link

extended your scripts into a single script with various targets possible, and builds an XCFramework #2

Open dbquarrel opened 3 years ago

dbquarrel commented 3 years ago

Using your scripts, I have kind of a hackery here but it will do some various things:

  1. mac OS library build for x86, arm, and also universal (fat) for the two
  2. mac catalyst library build
  3. iOS simulator build (x86)
  4. iOS device (arm) build

Missing an Apple Silicon build as I don't have that for testing.

The last thing it can do is to take the Catalyst + iOS simulator + iOS device libraries and combine them into an XCFramework, otherwise trying to incorporate the various libs into XCode causes problems due to overlapping device architectures.

This is not tested so well and I think would be better as a makefile. I'm putting it here in case anyone wants to use or build on it. I waive copyright rights and make no claims for this being done right! Use as you wish for any purpose or not.

#!/bin/bash -x

# this should be a makefile

# these switches are what you want most likely for targetting iOS apps
# you can't build the tools on iOS since they use some system calls 
APP_CONFIG="--enable-static=yes --enable-shared=no --enable-tests=no --enable-tools=no --with-data-packaging=static"

MIN_IOS_V=13.0
MIN_MACOS_V=10.15
MIN_IOS="-miphoneos-version-min=${MIN_IOS_V}"
MIN_MACOS="-mmacosx-version-min=${MIN_OSX_V}"

ICU_ROOT=$(pwd)/../icu4c

# you should build this from a folder parallel to the ICU installation

# ..
# icu4c 
# icu4c-xcframework <- put this script in here and build from here

FRAME_ROOT=$(pwd)

# how many CPUs to be using 
JJOBS=16
export MAKEFILES="-j${JJOBS}"
OPT=-O
ICU_PATH="${ICU_ROOT}/icu"
CONFIGURE="sh $ICU_PATH/source/configure"

# we need this for building everything else

function build_host {
    cd $FRAME_ROOT
    export CFLAGS="${OPT}"
    export CXXFLAGS="-stdlib=libc++ -std=c++11 ${OPT}"
    export OTHER_CONFIG="--enable-static=yes  --enable-shared=no --with-data-packaging=static  "
    echo "---------------------------------------------------------------"
    mkdir -p build-host && cd build-host
    ${CONFIGURE} --enable-static --disable-shared ${OTHER_CONFIG}
    make -j${JJOBS}
}

# builds library for normal use on mac, doesn't go into iOS framework
function build_mac_x86_64 {
    export OTHER_CONFIG="--enable-static=yes --enable-shared=no --with-data-packaging=static  "
    cd $FRAME_ROOT
    echo "---------------------------------------------------------------"
    BB="mac_x86_64"
    ARCH="x86_64"
    mkdir -p build-${BB} && cd build-${BB}
    export CLAGS="-arch x86_64 ${OPT}"
    export CXXFLAGS="${CFLAGS}"
    export LDFLAGS="-stdlib=libc++ -Wl,-dead_strip -lstdc++ -arch ${ARCH}"
    ${CONFIGURE} --enable-static --disable-shared ${OTHER_CONFIG}
    make -j${JJOBS}
}

# builds library for normal use on mac, doesn't go into iOS framework
function build_mac_arm64 {
    export OTHER_CONFIG="--enable-static=yes --enable-shared=no --with-data-packaging=static"
    cd $FRAME_ROOT
    echo "---------------------------------------------------------------"
    ARCH="arm64"
    BB="mac_${ARCH}"
    export CFLAGS="-arch $ARCH ${OPT}"
    export CXXFLAGS="-stdlib=libc++ -std=c++11 -arch $ARCH"
    export LDFLAGS="-stdlib=libc++ -Wl,-dead_strip -lstdc++ -arch ${ARCH}"
    mkdir -p build-${BB} && cd build-${BB}
    ${CONFIGURE} --host arm-apple-darwin --enable-static --disable-shared ${OTHER_CONFIG} -with-cross-build=${FRAME_ROOT}/build-host
    make -j${JJOBS}
}

# builds a fat library, don't need to use this for the framework
function build_mac_universal {
    export OTHER_CONFIG="--enable-static=yes    --enable-shared=no  --with-data-packaging=static  "
    cd $FRAME_ROOT
    echo "---------------------------------------------------------------"
    BB="mac_universal"
    ARCHS="-arch x86_64 -arch arm64"
    export CFLAGS="${ARCHS} ${OPT}"
    export CXXFLAGS="-stdlib=libc++ -std=c++11 ${ARCHS} ${OPT}"
    export LDFLAGS="-stdlib=libc++ -Wl,-dead_strip -lstdc++ ${ARCHS}"
    mkdir -p build-${BB} && cd build-${BB}
#    --host arm-apple-darwin
    ${CONFIGURE}  --enable-static --disable-shared ${OTHER_CONFIG} -with-cross-build=${FRAME_ROOT}/build-host
    make -j${JJOBS}
}

###
### Beginning of iOS stuff
###

export ICU_FLAGS="-I${ICU_PATH}/source/common/ -I${ICU_PATH}/source/tools/tzcode/ "

# builds for the mac catalyst target
function build_mac_catalyst {
    # security issues if we don't do this
    cd $FRAME_ROOT
    export OTHER_CONFIG=${APP_CONFIG}
    echo "---------------------------------------------------------------"
    BB="mac_catalyst"
    ARCH="x86_64"
    ARCHS="-arch ${ARCH} -target x86_64-apple-ios${MIN_IOS_V}-macabi"
    export CFLAGS="${ARCHS} ${ICU_FLAGS}  ${OPT}  "
    export CXXFLAGS="-stdlib=libc++ -std=c++11 ${ARCHS} ${ICU_FLAGS} ${OPT}"
    export LDFLAGS="-stdlib=libc++ -Wl,-dead_strip ${MIN_IOS} -lstdc++"
    mkdir -p build-${BB} && cd build-${BB}
    [ -e Makefile ] && make distclean
    ${CONFIGURE} --host=i686-apple-darwin11 ${OTHER_CONFIG} --with-cross-build=${FRAME_ROOT}/build-host
    # for some reason this one section refuses to turn on data
    mlreplace '#DATASUBDIR = data' 'DATASUBDIR = data' Makefile
    make -j${JJOBS}
}

# now we build the host for cross compilation
build_host

# and the catalyst build
build_mac_catalyst

##############################
##### iOS
##############################

DEVELOPER="$(xcode-select --print-path)"
export CXX="$DEVELOPER/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++"
export CC="$DEVELOPER/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"

# builds for iOS devices
function build_ios_arm64 {
    cd $FRAME_ROOT
    export OTHER_CONFIG=${APP_CONFIG}
    echo "---------------------------------------------------------------"
    SDKROOT="$(xcodebuild -version -sdk iphoneos | grep -E '^Path' | sed 's/Path: //')"
    ARCH="arm64"
    BB="ios_${ARCH}"
    export CFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/ -I./include/ -arch $ARCH ${MIN_IOS} $ICU_FLAGS ${OPT}"
    export CXXFLAGS="-stdlib=libc++ -std=c++11 -isysroot $SDKROOT -I$SDKROOT/usr/include/ -I./include/ -arch $ARCH ${MIN_IOS} $ICU_FLAGS"
    export LDFLAGS="-stdlib=libc++ -L$SDKROOT/usr/lib/ -isysroot $SDKROOT -Wl,-dead_strip ${MIN_IOS} -lstdc++"

    mkdir -p build-$BB && cd build-$BB

    [ -e Makefile ] && make distclean

    ${CONFIGURE} --host=arm-apple-darwin --enable-static --disable-shared ${OTHER_CONFIG} --with-cross-build=${FRAME_ROOT}/build-host

    make -j${JJOBS}
}

# builds for the iOS simulator on x86
function build_ios_x86_64 {
    cd $FRAME_ROOT
    export OTHER_CONFIG=${APP_CONFIG}
    echo "---------------------------------------------------------------"
    SDKROOT="$(xcodebuild -version -sdk iphonesimulator | grep -E '^Path' | sed 's/Path: //')"
    ARCH="x86_64"
    BB="ios_${ARCH}"
    export CFLAGS="-isysroot $SDKROOT -I$SDKROOT/usr/include/ -I./include/ -arch $ARCH ${MIN_IOS} $ICU_FLAGS ${OPT}"
    export CXXFLAGS="-stdlib=libc++ -std=c++11 -isysroot $SDKROOT -I$SDKROOT/usr/include/ -I./include/ -arch $ARCH ${MIN_IOS} $ICU_FLAGS"
    export LDFLAGS="-stdlib=libc++ -L$SDKROOT/usr/lib/ -isysroot $SDKROOT -Wl,-dead_strip ${MIN_IOS} -lstdc++"

    mkdir -p build-$BB && cd build-$BB

    [ -e Makefile ] && make distclean

    ${CONFIGURE} --host=i686-apple-darwin11 --enable-static --disable-shared ${OTHER_CONFIG} --with-cross-build=${FRAME_ROOT}/build-host

    make -j${JJOBS}
}

# uses all of the libraries above to create an XCFramework that can
# be dropped into your XCode project, this will allow you to target
# iOS devices, iOS simulator, Mac Catalyst as needed without libraries
# causing conflicts

function build_framework {
    cd $FRAME_ROOT
    # libicutu.a) libicuio.a
    LIBS="libicuuc.a libicui18n.a libicuio.a libicudata.a"
    ARCHS=( ios_arm64 ios_x86_64 mac_catalyst )
    LINK=""
    start=$(pwd)
    target=libICU.a
    for arch in "${ARCHS[@]}" ; do
    echo "--- ${arch}"
    src=build-$arch/lib
    cd $src
    libtool -static -o ${target} ${LIBS}
    cd ${start}
    LINK="${LINK} -library $src/${target} "
    LINK="${LINK} -headers ${ICU_ROOT}/include" 
    done
    FRAMEWORK="ICU.xcframework"
    rm -rf ${FRAMEWORK}
    xcodebuild -create-xcframework \
           ${LINK} \
           -output ${FRAMEWORK}
}

# time to build iOS devices
build_ios_arm64
# time to build iOS simulator
build_ios_x86_64

# everything done, we can now construct the framework
build_framework

# now just drag and drop the framework into your project
dbquarrel commented 3 years ago

I've since formalized the above into a total makefile to handle all universal builds (arm+x86) under macOS, Catalyst, iOS, and iOS Simulator.

https://github.com/dbquarrel/icu4c-xcframework

sunkehappy commented 3 years ago

@dbquarrel Great. Sorry this part in my project has not been updated for a long time. I'll take a look at yours if needed.