Monday, November 28, 2016

How to build c++ libraries (boost & QuantLib) for iOS XCode 8/9

It is possible to skip the armv7, armv7s and i386 architectures if these binaries are not required. Just modify the relevant part of the scripts below



Updated Note
The macOS 10.14 SDK no longer contains support for compiling 32-bit applications. If developers need to compile for i386, Xcode 9.4 or earlier is required.


(1) Download boost 1.62.0 and extract source
shell script    Select all
# download boost source cd $HOME/Downloads curl -O https://nchc.dl.sourceforge.net/project/boost/boost/1.62.0/boost_1_62_0.tar.bz2 tar xjvf boost_1_62_0.tar.bz2 cd boost_1_62_0 # create the following user-config.jam at ~/Downloads/boost_1_62_0/tools/build/src/ cat > tools/build/src/user-config.jam << 'EOF' # ------------------ # darwin iphone configuration. # ------------------ local XCODE_ROOT = /Applications/Xcode.app/Contents/Developer ; # xcrun --sdk iphoneos --show-sdk-path local IPHONESDK = iPhoneOS.sdk ; local MACOSXSDK = MacOSX.sdk ; # xcrun --show-sdk-path # xcrun --sdk iphonesimulator --show-sdk-path local IPHONESIMULATORSDK = iPhoneSimulator.sdk ; using darwin : armv7 : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/$(IPHONESDK) <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/$(IPHONESDK)" <compileflags>"-arch armv7" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-miphoneos-version-min=7.0 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <architecture>arm <address-model>32 <target-os>iphone ; using darwin : armv7s : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/$(IPHONESDK) <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/$(IPHONESDK)" <compileflags>"-arch armv7s" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-miphoneos-version-min=7.0 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <architecture>arm <address-model>32 <target-os>iphone ; using darwin : arm64 : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/$(IPHONESDK) <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/$(IPHONESDK)" #lt;root>$(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK) #lt;compileflags>"-isysroot $(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK)" <compileflags>"-arch arm64" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-miphoneos-version-min=7.0 #<compileflags>-mmacosx-version-min=10.9 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <architecture>arm <address-model>64 <target-os>iphone ; using darwin : i386 : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/iPhoneSimulator.platform/Developer/SDKs/$(IPHONESIMULATORSDK) <compileflags>"-arch i386" <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/iPhoneSimulator.platform/Developer/SDKs/$(IPHONESIMULATORSDK)" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-miphoneos-version-min=7.0 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <architecture>x86 <address-model>32 <target-os>iphone ; using darwin : x86_64 : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/iPhoneSimulator.platform/Developer/SDKs/$(IPHONESIMULATORSDK) <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/iPhoneSimulator.platform/Developer/SDKs/$(IPHONESIMULATORSDK)" #lt;root>$(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK) #lt;compileflags>"-isysroot $(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK)" <compileflags>"-arch x86_64" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-miphoneos-version-min=7.0 #<compileflags>-mmacosx-version-min=10.9 <compileflags>-fvisibility=hidden <compileflags>-fvisibility-inlines-hidden <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <architecture>x86 <address-model>64 <target-os>iphone ; EOF


(2) patch boost_1_62_0/tools/build/src/tools/darwin.jam
~/Downloads/boost_1_62_0/tools/build/src/tools/darwin.jam    Select all
#change from case arm : { if $(instruction-set) { options = -arch$(_)$(instruction-set) ; } else { options = -arch arm ; } } #to case arm : { if $(instruction-set) { options = -arch$(_)$(instruction-set) ; } else if $(address-model) = 64 { options = -arch arm64 ; } else { options = -arch arm ; } }


(3) build boost libraries for iOS
shell script    Select all
# bootstrap cd $HOME/Downloads/boost_1_62_0 # apply this patch if bootstrap error: pushd tools/build; wget https://github.com/boostorg/build/commit/48e9017139dd94446633480661e5447c7e0d8b1b.patch; patch -p1 < 48e9017139dd94446633480661e5447c7e0d8b1b.patch; popd ./bootstrap.sh --with-libraries=atomic,chrono,date_time,exception,filesystem,graph,iostreams,math,program_options,random,regex,serialization,signals,system,test,thread,wave # clean and build for iOS, j option is num of cores x 1.5 rm -fr ios-build ./b2 -j6 --build-dir=ios-build --stagedir=ios-build/armv7 toolset=darwin-armv7 architecture=arm instruction-set=armv7 address-model=32 target-os=iphone threading=multi link=static stage ./b2 -j6 --build-dir=ios-build --stagedir=ios-build/armv7s toolset=darwin-armv7s architecture=arm instruction-set=armv7s address-model=32 target-os=iphone threading=multi link=static stage ./b2 -j6 --build-dir=ios-build --stagedir=ios-build/arm64 toolset=darwin-arm64 architecture=arm address-model=64 target-os=iphone threading=multi link=static stage ./b2 -j6 --build-dir=ios-build --stagedir=ios-build/i386 toolset=darwin-i386 architecture=x86 address-model=32 target-os=iphone threading=multi link=static stage ./b2 -j6 --build-dir=ios-build --stagedir=ios-build/x86_64 toolset=darwin-x86_64 architecture=x86 address-model=64 target-os=iphone threading=multi link=static stage # create libboost.a archive for each architecture cd $HOME/Downloads/boost_1_62_0 cd ios-build xcrun ar crus armv7/libboost.a boost/bin.v2/libs/*/build/darwin-armv7/release/instruction-set-armv7/link-static/target-os-iphone/threading-multi/*/*.o xcrun ar crus armv7s/libboost.a boost/bin.v2/libs/*/build/darwin-armv7s/release/instruction-set-armv7s/link-static/target-os-iphone/threading-multi/*/*.o xcrun ar crus arm64/libboost.a boost/bin.v2/libs/*/build/darwin-arm64/release/link-static/target-os-iphone/threading-multi/*/*.o xcrun ar crus i386/libboost.a boost/bin.v2/libs/*/build/darwin-i386/release/link-static/target-os-iphone/threading-multi/*/*.o xcrun ar crus x86_64/libboost.a boost/bin.v2/libs/*/build/darwin-x86_64/release/link-static/target-os-iphone/threading-multi/*/*.o # create FAT libboost.a archive mkdir -p lib xcrun lipo \ -arch armv7 "armv7/libboost.a" \ -arch armv7s "armv7s/libboost.a" \ -arch arm64 "arm64/libboost.a" \ -arch i386 "i386/libboost.a" \ -arch x86_64 "x86_64/libboost.a" \ -output "lib/libboost.a" \ -create # create link for include folder mkdir include cd include ln -s ../../boost .


(4) Create boost Framework for iOS
shell script    Select all
cd $HOME/Downloads/boost_1_62_0 cd ios-build #Create the following shell script for build-boostframework.sh cat > build-boostframework.sh << 'boostFrameworkEOF' #!/bin/bash # build-boostframework.sh VERSION_TYPE=Alpha FRAMEWORK_NAME=boost FRAMEWORK_VERSION=A FRAMEWORKDIR=. FRAMEWORK_CURRENT_VERSION=1.62.0 FRAMEWORK_COMPATIBILITY_VERSION=1.62.0 FRAMEWORK_BUNDLE=${FRAMEWORKDIR}/${FRAMEWORK_NAME}.framework rm -rf ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE}/Versions mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION} mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Resources mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Headers mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Documentation ln -s $FRAMEWORK_VERSION ${FRAMEWORK_BUNDLE}/Versions/Current ln -s Versions/Current/Headers ${FRAMEWORK_BUNDLE}/Headers ln -s Versions/Current/Resources ${FRAMEWORK_BUNDLE}/Resources ln -s Versions/Current/Documentation ${FRAMEWORK_BUNDLE}/Documentation ln -s Versions/Current/$FRAMEWORK_NAME ${FRAMEWORK_BUNDLE}/$FRAMEWORK_NAME FRAMEWORK_INSTALL_NAME=${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/${FRAMEWORK_NAME} echo "Framework: Lipoing library into ${FRAMEWORK_INSTALL_NAME}" /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch armv7 "armv7/libboost.a" \ -arch armv7s "armv7s/libboost.a" \ -arch arm64 "arm64/libboost.a" \ -arch i386 "i386/libboost.a" \ -arch x86_64 "x86_64/libboost.a" \ -output "${FRAMEWORK_INSTALL_NAME}" \ -create echo "Framework: Copying includes..." cp -r include/${FRAMEWORK_NAME}/* ${FRAMEWORK_BUNDLE}/Headers/ cat > ${FRAMEWORK_BUNDLE}/Resources/Info.plist <<InfoplistEOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>${FRAMEWORK_NAME}.org</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> InfoplistEOF echo "Done: ${FRAMEWORK_BUNDLE}" boostFrameworkEOF # build framework sh build-boostframework.sh


(5) Download and build QuantLib 1.12 for iOS
shell script    Select all
# download quantlib source cd $HOME/Downloads # latest is https://jaist.dl.sourceforge.net/project/quantlib/QuantLib/1.12/QuantLib-1.12.tar.gz (February 1st, 2018) export QL_VERSION=1.12 curl -O https://jaist.dl.sourceforge.net/project/quantlib/QuantLib/${QL_VERSION}/QuantLib-${QL_VERSION}.tar.gz # curl -O https://jaist.dl.sourceforge.net/project/quantlib/QuantLib/1.9/QuantLib-1.9.tar.gz tar xzvf QuantLib-${QL_VERSION}.tar.gz cd QuantLib-${QL_VERSION} #Create the following shell script for armv7 cat > ~/Downloads/QuantLib-${QL_VERSION}/build-armv7.sh << 'armv7EOF' #!/bin/bash # build-armv7.sh BUILD_DIR=ios-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" # XCODE_VERSION=Xcode-9.0 # XCODE_ROOT=/Applications/${XCODE_VERSION}.app/Contents/Developer XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk iphoneos --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk sysroot="`xcrun --sdk iphoneos --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch armv7 -std=c99 -miphoneos-version-min=7.0 -isysroot ${sysroot}" export CXXFLAGS="-arch armv7 -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -miphoneos-version-min=7.0 -O2 -g -fvisibility=hidden -fvisibility-inlines-hidden -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++" boost_include="`cd "../boost_1_62_0/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../boost_1_62_0/${BUILD_DIR}/armv7/lib";pwd`" make distclean ./configure --prefix=/armv7 --host=arm-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} armv7EOF #Create the following shell script for armv7s cat > ~/Downloads/QuantLib-${QL_VERSION}/build-armv7s.sh << 'armv7sEOF' #!/bin/bash # build-armv7s.sh BUILD_DIR=ios-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" # XCODE_VERSION=Xcode-9.0 # XCODE_ROOT=/Applications/${XCODE_VERSION}.app/Contents/Developer XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk iphoneos --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk sysroot="`xcrun --sdk iphoneos --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch armv7s -std=c99 -miphoneos-version-min=7.0 -isysroot ${sysroot}" export CXXFLAGS="-arch armv7s -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -miphoneos-version-min=7.0 -O2 -g -fvisibility=hidden -fvisibility-inlines-hidden -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++" boost_include="`cd "../boost_1_62_0/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../boost_1_62_0/${BUILD_DIR}/armv7s/lib";pwd`" make distclean ./configure --prefix=/armv7s --host=arm-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} armv7sEOF #Create the following shell script for arm64 cat > ~/Downloads/QuantLib-${QL_VERSION}/build-arm64.sh << 'arm64EOF' #!/bin/bash # build-arm64.sh ARCH=arm64 BOOST_FOLDER=boost_1_62_0 BUILD_DIR=ios-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk iphoneos --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk # sysroot="`xcrun --show-sdk-path`" sysroot="`xcrun --sdk iphoneos --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch ${ARCH} -std=c99 -miphoneos-version-min=7.0 -isysroot ${sysroot}" export CXXFLAGS="-arch ${ARCH} -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -miphoneos-version-min=7.0 -O2 -g -fvisibility=hidden -fvisibility-inlines-hidden -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++" boost_include="`cd "../${BOOST_FOLDER}/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../${BOOST_FOLDER}/${BUILD_DIR}/arm64/lib";pwd`" make distclean ./configure --prefix=/${ARCH} --host=${ARCH}-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} arm64EOF #Create the following shell script for i386 cat > ~/Downloads/QuantLib-${QL_VERSION}/build-i386.sh << 'i386EOF' #!/bin/bash # build-i386.sh BUILD_DIR=ios-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" # XCODE_VERSION=Xcode-9.0 # XCODE_ROOT=/Applications/${XCODE_VERSION}.app/Contents/Developer XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk iphonesimulator --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk sysroot="`xcrun --sdk iphonesimulator --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch i386 -std=c99 -miphoneos-version-min=7.0 -isysroot ${sysroot}" export CXXFLAGS="-arch i386 -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -miphoneos-version-min=7.0 -O2 -g -fvisibility=hidden -fvisibility-inlines-hidden -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++" boost_include="`cd "../boost_1_62_0/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../boost_1_62_0/${BUILD_DIR}/i386/lib";pwd`" make distclean ./configure --prefix=/i386 --host=i386-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} i386EOF #Create the following shell script for x86_64 cat > ~/Downloads/QuantLib-${QL_VERSION}/build-x86_64.sh << 'x86_64EOF' #!/bin/bash # build-x86_64.sh ARCH=x86_64 BOOST_FOLDER=boost_1_62_0 BUILD_DIR=ios-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk iphonesimulator --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk # sysroot="`xcrun --show-sdk-path`" sysroot="`xcrun --sdk iphonesimulator --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch ${ARCH} -std=c99 -miphoneos-version-min=7.0 -isysroot ${sysroot}" export CXXFLAGS="-arch ${ARCH} -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -miphoneos-version-min=7.0 -O2 -g -fvisibility=hidden -fvisibility-inlines-hidden -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++" boost_include="`cd "../${BOOST_FOLDER}/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../${BOOST_FOLDER}/${BUILD_DIR}/x86_64/lib";pwd`" make distclean ./configure --prefix=/${ARCH} --host=${ARCH}-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} x86_64EOF #run shell scripts to clean and build for iOS cd $HOME/Downloads cd QuantLib-${QL_VERSION} rm -fr ios-build sh build-armv7.sh sh build-armv7s.sh sh build-arm64.sh sh build-i386.sh sh build-x86_64.sh # create FAT libQuantLib.a archive cd $HOME/Downloads/QuantLib-${QL_VERSION} cd ios-build mkdir -p lib /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch armv7 "armv7/lib/libQuantLib.a" \ -arch armv7s "armv7s/lib/libQuantLib.a" \ -arch arm64 "arm64/lib/libQuantLib.a" \ -arch i386 "i386/lib/libQuantLib.a" \ -arch x86_64 "x86_64/lib/libQuantLib.a" \ -output "lib/libQuantLib.a" \ -create # create link for include folder mkdir include cd include ln -s ../arm64/include/ql .


(6) Create QuantLib Framework for iOS
shell script    Select all
export QL_VERSION=1.12 cd $HOME/Downloads/QuantLib-${QL_VERSION} cd ios-build #Create the following shell script for build-qlframework.sh cat > build-qlframework.sh << 'qlFrameworkEOF' #!/bin/bash # build-qlframework.sh VERSION_TYPE=Alpha FRAMEWORK_NAME=ql FRAMEWORK_VERSION=A FRAMEWORKDIR=. FRAMEWORK_CURRENT_VERSION=${QL_VERSION} FRAMEWORK_COMPATIBILITY_VERSION=${QL_VERSION} FRAMEWORK_BUNDLE=${FRAMEWORKDIR}/${FRAMEWORK_NAME}.framework rm -rf ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE}/Versions mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION} mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Resources mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Headers mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Documentation ln -s $FRAMEWORK_VERSION ${FRAMEWORK_BUNDLE}/Versions/Current ln -s Versions/Current/Headers ${FRAMEWORK_BUNDLE}/Headers ln -s Versions/Current/Resources ${FRAMEWORK_BUNDLE}/Resources ln -s Versions/Current/Documentation ${FRAMEWORK_BUNDLE}/Documentation ln -s Versions/Current/$FRAMEWORK_NAME ${FRAMEWORK_BUNDLE}/$FRAMEWORK_NAME FRAMEWORK_INSTALL_NAME=${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/${FRAMEWORK_NAME} echo "Framework: Lipoing library into ${FRAMEWORK_INSTALL_NAME}" /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch armv7 "armv7/lib/libQuantLib.a" \ -arch armv7s "armv7s/lib/libQuantLib.a" \ -arch arm64 "arm64/lib/libQuantLib.a" \ -arch i386 "i386/lib/libQuantLib.a" \ -arch x86_64 "x86_64/lib/libQuantLib.a" \ -output "${FRAMEWORK_INSTALL_NAME}" \ -create echo "Framework: Copying includes..." cp -r include/${FRAMEWORK_NAME}/* ${FRAMEWORK_BUNDLE}/Headers/ cat > ${FRAMEWORK_BUNDLE}/Resources/Info.plist <<InfoplistEOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>quantlib.org</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> InfoplistEOF echo "Done: ${FRAMEWORK_BUNDLE}" qlFrameworkEOF # build framework sh build-qlframework.sh


(7) Test build x86_64 for iOS frameworks with
shell script    Select all
#Create testql.cpp cd $HOME/Downloads cat > testql.cpp << 'testqlEOF' #include <ql/quantlib.hpp> int main() { std::cout << "BOOST version is " << BOOST_VERSION << std::endl; std::cout << "QL version is " << QL_VERSION << std::endl; #if __x86_64__ || __WORDSIZE == 64 std::cout << "This is 64 bits" << std::endl; #elif __i386__ || __WORDSIZE == 32 std::cout << "This is 32 bits" << std::endl; #else std::cout << "This is something else" << std::endl; #endif return 0; } testqlEOF # test build example using iOS frameworks export QL_VERSION=1.12 xcrun clang++ -std=c++11 -stdlib=libc++ -F $HOME/Downloads/QuantLib-${QL_VERSION}/ios-build -F $HOME/Downloads/boost_1_62_0/ios-build -framework ql -isysroot `xcrun --sdk iphonesimulator --show-sdk-path` -arch x86_64 -miphoneos-version-min=7.0 -fvisibility=hidden -o testql testql.cpp ./testql


(8) Build frameworks for macosx and build RQuantLib package from source
shell script    Select all
cd $HOME/Downloads/boost_1_62_0 # Append the following user-config.jam at ~/Downloads/boost_1_62_0/tools/build/src/ cat >> tools/build/src/user-config.jam << 'EOF' # ------------------ # darwin macosx configuration. # ------------------ local XCODE_ROOT = /Applications/Xcode.app/Contents/Developer ; # xcrun --sdk macosx --show-sdk-path local MACOSXSDK = MacOSX.sdk ; using darwin : i386~macosx : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK) <compileflags>"-arch i386" <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK)" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-mmacosx-version-min=10.9 <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <linkflags>-mmacosx-version-min=10.9 <architecture>x86 <address-model>32 <target-os>darwin ; using darwin : x86_64~macosx : $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ : <striper>$(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip <root>$(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK) <compileflags>"-arch x86_64" <compileflags>"-isysroot $(XCODE_ROOT)/Platforms/MacOSX.platform/Developer/SDKs/$(MACOSXSDK)" <compileflags>-fexceptions <compileflags>-frtti <compileflags>-fpic <compileflags>-DBOOST_SP_USE_SPINLOCK <compileflags>-std=c++11 <compileflags>-stdlib=libc++ <compileflags>-mmacosx-version-min=10.9 <compileflags>-O2 <compileflags>-g <compileflags>-Os <compileflags>-Wno-long-long <compileflags>-Wno-missing-field-initializers <compileflags>-Wno-unused-variable <linkflags>-stdlib=libc++ <linkflags>-mmacosx-version-min=10.9 <architecture>x86 <address-model>64 <target-os>darwin ; EOF # build boost libraries for macosx ./bootstrap.sh --with-libraries=atomic,chrono,date_time,exception,filesystem,graph,iostreams,math,program_options,random,regex,serialization,signals,system,test,thread,wave # clean and build for macosx, j option is num of cores x 1.5 rm -fr macosx-build ./b2 -j6 --build-dir=macosx-build --stagedir=macosx-build/i386 toolset=darwin-i386~macosx architecture=x86 address-model=32 target-os=darwin threading=multi link=static stage ./b2 -j6 --build-dir=macosx-build --stagedir=macosx-build/x86_64 toolset=darwin-x86_64~macosx architecture=x86 address-model=64 target-os=darwin threading=multi link=static stage # create libboost.a archive for each architecture cd $HOME/Downloads/boost_1_62_0/macosx-build xcrun --sdk macosx ar crus i386/libboost.a boost/bin.v2/libs/*/build/darwin-i386~macosx/release/link-static/threading-multi/*/*.o xcrun --sdk macosx ar crus x86_64/libboost.a boost/bin.v2/libs/*/build/darwin-x86_64~macosx/release/link-static/threading-multi/*/*.o # create FAT libboost.a archive mkdir -p lib /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch i386 "i386/libboost.a" \ -arch x86_64 "x86_64/libboost.a" \ -output "lib/libboost.a" \ -create # create link for include folder mkdir include cd include ln -s ../../boost . # build Boost Framework for macosx #Create the following shell script for build-boostframework.sh cd $HOME/Downloads/boost_1_62_0/macosx-build cat > build-boostframework.sh << 'boostFrameworkEOF' #!/bin/bash # build-boostframework.sh VERSION_TYPE=Alpha FRAMEWORK_NAME=boost FRAMEWORK_VERSION=A FRAMEWORKDIR=. FRAMEWORK_CURRENT_VERSION=1.62.0 FRAMEWORK_COMPATIBILITY_VERSION=1.62.0 FRAMEWORK_BUNDLE=${FRAMEWORKDIR}/${FRAMEWORK_NAME}.framework rm -rf ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE}/Versions mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION} mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Resources mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Headers mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Documentation ln -s $FRAMEWORK_VERSION ${FRAMEWORK_BUNDLE}/Versions/Current ln -s Versions/Current/Headers ${FRAMEWORK_BUNDLE}/Headers ln -s Versions/Current/Resources ${FRAMEWORK_BUNDLE}/Resources ln -s Versions/Current/Documentation ${FRAMEWORK_BUNDLE}/Documentation ln -s Versions/Current/$FRAMEWORK_NAME ${FRAMEWORK_BUNDLE}/$FRAMEWORK_NAME FRAMEWORK_INSTALL_NAME=${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/${FRAMEWORK_NAME} echo "Framework: Lipoing library into ${FRAMEWORK_INSTALL_NAME}" /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch i386 "i386/libboost.a" \ -arch x86_64 "x86_64/libboost.a" \ -output "${FRAMEWORK_INSTALL_NAME}" \ -create echo "Framework: Copying includes..." cp -r include/${FRAMEWORK_NAME}/* ${FRAMEWORK_BUNDLE}/Headers/ cat > ${FRAMEWORK_BUNDLE}/Resources/Info.plist <<InfoplistEOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>${FRAMEWORK_NAME}.org</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> InfoplistEOF echo "Done: ${FRAMEWORK_BUNDLE}" boostFrameworkEOF # build framework sh build-boostframework.sh # build QuantLib libraries for macosx export QL_VERSION=1.12 cd $HOME/Downloads/QuantLib-${QL_VERSION} #Create the following shell script for i386 cat > ~/Downloads/QuantLib-${QL_VERSION}/build-i386-macosx.sh << 'i386EOF' #!/bin/bash # build-i386-macosx.sh BUILD_DIR=macosx-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" # XCODE_VERSION=Xcode-9.0 # XCODE_ROOT=/Applications/${XCODE_VERSION}.app/Contents/Developer XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk macosx --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk sysroot="`xcrun --sdk macosx --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch i386 -std=c99 -mmacosx-version-min=10.7 -isysroot ${sysroot}" export CXXFLAGS="-arch i386 -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -mmacosx-version-min=10.9 -O2 -g -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++ -mmacosx-version-min=10.9" boost_include="`cd "../boost_1_62_0/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../boost_1_62_0/${BUILD_DIR}/i386/lib";pwd`" make distclean ./configure --prefix=/i386 --host=i386-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-intraday --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} i386EOF #Create the following shell script for x86_64 cat > ~/Downloads/QuantLib-${QL_VERSION}/build-x86_64-macosx.sh << 'x86_64EOF' #!/bin/bash # build-x86_64-macosx.sh BUILD_DIR=macosx-build mkdir -p ${BUILD_DIR} INSTALL_DIR="`pwd`/${BUILD_DIR}" YOUR_PATH_TO_INSTALL_DIR="`cd "${INSTALL_DIR}";pwd`" XCODE_ROOT=/Applications/Xcode.app/Contents/Developer YOUR_TOOLCHAIN=${XCODE_ROOT}/Toolchains/XcodeDefault.xctoolchain/usr/bin # xcrun --sdk macosx --show-sdk-path # sysroot=${XCODE_ROOT}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk sysroot="`xcrun --sdk macosx --show-sdk-path`" export CC=${YOUR_TOOLCHAIN}/clang export CXX=${YOUR_TOOLCHAIN}/clang++ export CPP=${YOUR_TOOLCHAIN}/cpp export AR=${YOUR_TOOLCHAIN}/ar export RANLIB=${YOUR_TOOLCHAIN}/ranlib export LD=${YOUR_TOOLCHAIN}/ld export CFLAGS="-arch x86_64 -std=c99 -mmacosx-version-min=10.7 -isysroot ${sysroot}" export CXXFLAGS="-arch x86_64 -fexceptions -frtti -fpic -std=c++11 -stdlib=libc++ -mmacosx-version-min=10.9 -O2 -g -Os -isysroot ${sysroot}" export LDFLAGS="-stdlib=libc++ -mmacosx-version-min=10.9" boost_include="`cd "../boost_1_62_0/${BUILD_DIR}/include";pwd`" boost_lib="`cd "../boost_1_62_0/${BUILD_DIR}/x86_64/lib";pwd`" make distclean ./configure --prefix=/x86_64 --host=x86_64-apple-darwin10 --with-sysroot=${sysroot} --with-boost-include=${boost_include} --with-boost-lib=${boost_lib} --enable-intraday --enable-static --enable-shared=no --disable-examples make -j6 make install DESTDIR=${YOUR_PATH_TO_INSTALL_DIR} x86_64EOF #run shell scripts to clean and build for macosx cd $HOME/Downloads/QuantLib-${QL_VERSION} rm -fr macosx-build sh build-i386-macosx.sh sh build-x86_64-macosx.sh # create FAT libQuantLib.a archive cd $HOME/Downloads/QuantLib-${QL_VERSION} cd macosx-build mkdir -p lib /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch i386 "i386/lib/libQuantLib.a" \ -arch x86_64 "x86_64/lib/libQuantLib.a" \ -output "lib/libQuantLib.a" \ -create # create link for include folder mkdir include cd include ln -s ../x86_64/include/ql . cd $HOME/Downloads/QuantLib-${QL_VERSION}/macosx-build # build QuantLib Framework for macosx #Create the following shell script for build-qlframework.sh cat > build-qlframework.sh << 'qlFrameworkEOF' #!/bin/bash # build-qlframework.sh VERSION_TYPE=Alpha FRAMEWORK_NAME=ql FRAMEWORK_VERSION=A FRAMEWORKDIR=. FRAMEWORK_CURRENT_VERSION=${QL_VERSION} FRAMEWORK_COMPATIBILITY_VERSION=${QL_VERSION} FRAMEWORK_BUNDLE=${FRAMEWORKDIR}/${FRAMEWORK_NAME}.framework rm -rf ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE} mkdir -p ${FRAMEWORK_BUNDLE}/Versions mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION} mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Resources mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Headers mkdir -p ${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/Documentation ln -s $FRAMEWORK_VERSION ${FRAMEWORK_BUNDLE}/Versions/Current ln -s Versions/Current/Headers ${FRAMEWORK_BUNDLE}/Headers ln -s Versions/Current/Resources ${FRAMEWORK_BUNDLE}/Resources ln -s Versions/Current/Documentation ${FRAMEWORK_BUNDLE}/Documentation ln -s Versions/Current/$FRAMEWORK_NAME ${FRAMEWORK_BUNDLE}/$FRAMEWORK_NAME FRAMEWORK_INSTALL_NAME=${FRAMEWORK_BUNDLE}/Versions/${FRAMEWORK_VERSION}/${FRAMEWORK_NAME} echo "Framework: Lipoing library into ${FRAMEWORK_INSTALL_NAME}" /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch i386 "i386/lib/libQuantLib.a" \ -arch x86_64 "x86_64/lib/libQuantLib.a" \ -output "${FRAMEWORK_INSTALL_NAME}" \ -create echo "Framework: Copying includes..." cp -r include/${FRAMEWORK_NAME}/* ${FRAMEWORK_BUNDLE}/Headers/ cat > ${FRAMEWORK_BUNDLE}/Resources/Info.plist <<InfoplistEOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>quantlib.org</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> InfoplistEOF echo "Done: ${FRAMEWORK_BUNDLE}" qlFrameworkEOF # build framework sh build-qlframework.sh # Test build example using macosx frameworks export QL_VERSION=1.12 clang++ -std=c++11 -stdlib=libc++ -F $HOME/Downloads/QuantLib-${QL_VERSION}/macosx-build -F $HOME/Downloads/boost_1_62_0/macosx-build -framework ql -arch x86_64 -o testql testql.cpp ./testql # Build RQuantLib for Mac OSX 10.12.6 (1) Build the above macosx x86_64 libraries for QuantLib and Boost. For Quantlib, it should be version >=1.8 and with --enable-intraday option. For Boost and QuantLib, should remove -fvisibility=hidden -fvisibility-inlines-hidden (2) Install R 3.4.4 from https://cran.r-project.org/bin/macosx/ and optionally install RStudio (3) Install clang 4.0 from http://r.research.att.com/libs/ sudo tar xzvf ${HOME}/Downloads/clang-4.0.0-darwin15.6-Release.tar.gz -C / (4) Create R/Makevars mkdir -p ${HOME}/.R cat > ${HOME}/.R/Makevars << 'EOF' CC=/usr/local/clang4/bin/clang CXX=/usr/local/clang4/bin/clang++ CXXFLAGS=-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -Wno-nonportable-include-path -Wno-unused-variable -I${HOME}/Downloads/QuantLib-1.12/macosx-build/x86_64/include LDFLAGS=-L/usr/local/clang4/lib -L${HOME}/Downloads/QuantLib-1.12/macosx-build/x86_64/lib EOF # if compile using clang6 under the latest R 3.5.0, should change path to /usr/local/clang6 accordingly. (5) Install QuantLib 1.12 to /usr/local export QL_VERSION=1.12 cd ${HOME}/Downloads/QuantLib-${QL_VERSION}/macosx-build/x86_64; tar czvf ../ql-${QL_VERSION}.tgz bin include lib share cd ${HOME}/Downloads/QuantLib-${QL_VERSION}/macosx-build sudo tar xzvf ql-${QL_VERSION}.tgz -C /usr/local (6) Build RQuantLib with R terminal session from source and install R install.packages("RQuantLib", configure.args = "--with-boost-include=${HOME}/Downloads/boost_1_62_0/macosx-build/include --with-boost-lib=${HOME}/Downloads/boost_1_62_0/macosx-build/x86_64/lib", type = "source") # installing to /Library/Frameworks/R.framework/Versions/3.4/Resources/library/RQuantLib/libs # build binary package (should install dependencies Rcpp and zoo first) using the following # curl -O https://cran.cnr.berkeley.edu/src/contrib/RQuantLib_0.4.4.tar.gz # R CMD INSTALL --build --configure-args="--with-boost-include=${HOME}/Downloads/boost_1_62_0/macosx-build/include --with-boost-lib=${HOME}/Downloads/boost_1_62_0/macosx-build/x86_64/lib" RQuantLib_0.4.4.tar.gz (7) Optionally, install https://www.xquartz.org/ if want to remove warning on : unable to load shared object '/Library/Frameworks/R.framework/Resources/modules//R_X11.so' # Install dependencies for testing RQuantLib R install.packages(c("Rcpp","zoo")) install.packages(c("rgl","RUnit"))


(9) Test RQuantLib binary package for R version 3.4.4 on Mac OSX 10.12.6
bond1.R  Select all
#Simple call with a flat curve require(RQuantLib) bond <- list(faceAmount=100, settlementDays=1, issueDate=as.Date("2014-11-30"), redemption=100)
scheduleparams <- list(effectiveDate=as.Date("2014-11-30"), maturityDate=as.Date("2018-11-30"), period=2, calendar="UnitedStates", businessDayConvention = 4, terminationDateConvention=4, dateGeneration=1, endOfMonth=1, dayCounter = 'Thirty360')
coupon.rate <- c(0.02875)
params <- list(tradeDate=as.Date('2014-2-15'), settleDate=as.Date('2014-2-19'), dt=.25, interpWhat="discount", interpHow="loglinear")
setEvaluationDate(as.Date("2014-11-22"))
discountCurve.flat <- DiscountCurve(params, list(flat=0.05))
FixedRateBond(bond=bond, rates=coupon.rate, schedule=scheduleparams, calc=list(dayCounter='ActualActual.ISMA',compounding='Compounded', freq='Annual', durationType='Modified'),discountCurve=discountCurve.flat)

FixedRateBondPriceByYield( settlementDays=1, yield=0.05127, faceAmount=100, effectiveDate=as.Date("2014-11-30"), maturityDate=as.Date("2018-11-30"), period=2, calendar="UnitedStates", rates=c(0.05), dayCounter=2, businessDayConvention=4, compound=0, redemption=100, issueDate=as.Date("2014-11-30"))

FixedRateBondYield( settlementDays=1, price=99.54593, faceAmount=100, effectiveDate=as.Date("2014-11-30"), maturityDate=as.Date("2018-11-30"), period=2, calendar="UnitedStates", rates=c(0.05), dayCounter=2, businessDayConvention=4, compound=0, redemption=100, issueDate=as.Date("2014-11-30"))





Sunday, September 11, 2016

How to split CSV in Swift

Below is Swift 2.1 code
Swift 3 code is here https://github.com/Daniel1of1/CSwiftV/blob/master/Sources/CSwiftV.swift
csvsplit.swift   Select all
//: Playground - noun: a place where people can play import Foundation public func split(string: String, _ separator: String = ",") -> [String] { // Swift 2.1 //public func split(_ string: String, _ separator: String = ",") -> [String] { // Swift 3 func oddNumberOfQuotes(string: String) -> Bool { // Swift 2.1 // func oddNumberOfQuotes(_ string: String) -> Bool { // Swift 3 return string.componentsSeparatedByString("\"").count % 2 == 0 // Swift 2.1 // return string.components(separatedBy: "\"").count % 2 == 0 // Swift 3 } let initial = string.componentsSeparatedByString(separator) // Swift 2.1 // let initial = string.components(separatedBy: separator) // Swift 3 var merged = [String]() for newString in initial { if let record = merged.last { guard oddNumberOfQuotes(record) == true else { merged.append(newString) continue } merged.removeLast() let lastElem = record + separator + newString merged.append(lastElem) } else { merged.append(newString) continue } } return merged } public func csvsplit(string: String, _ rowSeparator: String = "\n", _ colSeparator: String = ",") -> [[String]] { // Swift 2.1 //public func csvsplit(_ string: String, _ rowSeparator: String = "\n", _ colSeparator: String = ",") -> [[String]] { // Swift 3 return split(string.stringByReplacingOccurrencesOfString("\r\n", withString: "\n"), rowSeparator).map{split($0, colSeparator)} // Swift 2.1 // return split(string.replacingOccurrences(of: "\r\n", with: "\n"), rowSeparator).map{split($0, colSeparator)} // Swift 3 } print(csvsplit("aa,\"b,b\",cc\na,b,c")) do { // www.quandl.com api : anonymous user limit of 50 calls per day. let csv = try String(contentsOfURL: NSURL(string: "https://www.quandl.com/api/v3/datasets/FRED/DEXJPUS.csv")!, encoding: NSUTF8StringEncoding) // Swift 2.1 // let csv = try String(contentsOf: Foundation.URL(string: "https://www.quandl.com/api/v3/datasets/FRED/DEXJPUS.csv")!) // Swift 3 // there are over 11 000 rows from this url, so playground will take some times to finish print(split(csv,"\n")[0...2].map{split($0)}) } catch let error { print(error) }



Thursday, September 1, 2016

Struct and Enum used together in Swift 3

Sample code in swift 3 (Xcode 8 beta 6)

This demonstrates
(1) the use of enum initialization method for default value
(2) the use of struct initialization method for default variable value
(3) the use of multiple guard statements in Swift 3
(4) struct and enum used together for data model that has different associated values based on enum type
(5) internal var for mutating associated values
playgroundcode.swift   Select all
//: Playground - noun: a place where people can play import Foundation struct Instrument { enum CurrencyType:String { case USD case EUR case GBP case JPY case EURUSD case USDEUR case GBPUSD case USDGBP case USDJPY case JPYUSD case USDCNY case USDHKD // default initialization methods for currencyType enum init() { self = .USD } } enum InstrumentType { case FloatingRateBond(ccy:String, faceamount: Double?, redemption: Double?, issueDate:String, maturityDate:String, floatingRate:String) case FixedRateBond(ccy:String, faceamount: Double?, redemption: Double?, issueDate:String, maturityDate:String, fixedRate:String) case ZeroCouponBond(ccy:String, faceamount: Double?, redemption: Double?, issueDate:String, maturityDate:String) case Unknown // default initialization methods for different instrumentType enum init() { self = .Unknown } init(ccy: String, issueDate:String, maturityDate:String, floatingRate:String) { self = .FloatingRateBond(ccy: ccy, faceamount: 100.0, redemption: 100.0, issueDate: issueDate, maturityDate: maturityDate, floatingRate: floatingRate) } init(ccy: String, issueDate:String, maturityDate:String, fixedRate:String) { self = .FixedRateBond(ccy: ccy, faceamount: 100.0, redemption: 100.0, issueDate: issueDate, maturityDate: maturityDate, fixedRate: fixedRate) } init(ccy: String, redemption:Double?, issueDate:String, maturityDate:String) { self = .ZeroCouponBond(ccy: ccy, faceamount: 100.0, redemption: redemption, issueDate: issueDate, maturityDate: maturityDate) } } var title:String? = nil var name:String var type:InstrumentType var typeName: String { switch self.type { case .FloatingRateBond : return "FloatingRateBond" case .FixedRateBond : return "FixedRateBond" case .ZeroCouponBond : return "ZeroCouponBond" default : return "Unknown" } } // provide mutating internal var internal var _ccy : String? = nil var ccy : String? { get { guard let ccy: String = { switch self.type { // use case let here case let .FloatingRateBond(tuple) : return self._ccy ?? tuple.ccy case let .FixedRateBond(tuple) : return self._ccy ?? tuple.ccy case let .ZeroCouponBond(tuple) : return self._ccy ?? tuple.ccy default : return nil } }() else { return nil } return ccy } set { // cannot throws error here yet switch self.type { case .FloatingRateBond, .FixedRateBond, .ZeroCouponBond : _ccy = newValue! default : () } } } var currencyType : CurrencyType? { // multiple guard statements Swift 3 guard let ccy = self.ccy, let ccytype:CurrencyType = CurrencyType(rawValue: ccy.uppercased()) else { return nil } return ccytype } // no mutating internal var var faceAmount : Double? { guard let faceAmount: Double = { switch self.type { // use pattern matching here case .FloatingRateBond(_, let faceAmount, _, _, _, _) : return faceAmount case .FixedRateBond(_, let faceAmount, _, _, _, _) : return faceAmount case .ZeroCouponBond(_, let faceAmount, _, _, _) : return faceAmount default : return nil } }() else { return nil } return faceAmount } var redemption : Double? { guard let redemption: Double = { switch self.type { case .FloatingRateBond(_, _, let redemption, _, _, _) : return redemption case .FixedRateBond(_, _, let redemption, _, _, _) : return redemption case .ZeroCouponBond(_, _, let redemption, _, _) : return redemption default : return nil } }() else { return nil } return redemption } var issueDate : String? { guard let issueDate: String = { switch self.type { case .FloatingRateBond(_, _, _, let issueDate, _, _) : return issueDate case .FixedRateBond(_, _, _, let issueDate, _, _) : return issueDate case .ZeroCouponBond(_, _, _, let issueDate, _) : return issueDate default : return nil } }() else { return nil } return issueDate.isEmpty ? nil : issueDate } var maturityDate : String? { guard let maturityDate: String = { switch self.type { case .FloatingRateBond(_, _, _, _, let maturityDate, _) : return maturityDate case .FixedRateBond(_, _, _, _, let maturityDate, _) : return maturityDate case .ZeroCouponBond(_, _, _, _, let maturityDate) : return maturityDate default : return nil } }() else { return nil } return maturityDate.isEmpty ? nil : maturityDate } var description: String { switch self.type { case .FloatingRateBond(let ccy, _, _, let issueDate, let maturityDate, let floatingRate) : return "\(self.name) FloatingRateBond \(ccy) \(issueDate) \(maturityDate) \(floatingRate)" case .FixedRateBond(let ccy, _, _, let issueDate, let maturityDate, let fixedRate) : return "\(self.name) FixedRateBond \(ccy) \(issueDate) \(maturityDate) \(fixedRate)" case .ZeroCouponBond : return "ZeroCouponBond" default : return "Unknown Description" } } var marketData:AnyObject? = nil var pricingEngine:AnyObject? = nil // default initialization methods for Instrument struct init(name: String, type: InstrumentType) { self.name = name self.type = type } init(name: String) { self.name = name self.type = InstrumentType() } func NPV() -> Double? { // multiple guard statements Swift 3 guard let data = self.marketData, let engine = self.pricingEngine else { return nil } // TODO: marketData and pricingEngine print("\(data) \(engine)") return 0.0 } } var portfolio = [ Instrument(name:"B00001USDLIBOR", type: Instrument.InstrumentType(ccy: "USD", issueDate: "20100101", maturityDate: "20101231", floatingRate: "LIBOR+1")), Instrument(name:"B0002JPY0.5%", type: .FixedRateBond(ccy: "JPY", faceamount: 100.0, redemption: 100.0, issueDate: "20110101", maturityDate: "20291231", fixedRate: "0.5%")), Instrument(name:"ZC0001", type: Instrument.InstrumentType(ccy: "USD", redemption: 120.0, issueDate: "20110101", maturityDate: "20291231")), Instrument(name:"U0001")] portfolio.forEach{ ( a : Instrument) -> () in print(a.typeName) print(a) if let b = a.currencyType { print(b) } else { print("missing / invalid currency info \(a.ccy)") } print(a.issueDate ?? "No issueDate") print(a.maturityDate ?? "No maturityDate") print(a.description) print(a.NPV() ?? "No NPV") } print(portfolio[2].ccy) portfolio[2].ccy = "JPY" print(portfolio[2].currencyType) print(portfolio[2].ccy)



Differences between struct Instrument and class Instrument
(1) class is reference type and struct is value type.
(2) open class can be subclassed in other modules, but not for struct.
(3) class func is not allowed, use static func instead in struct.
(4) reference and value types can be modified in the forEach or other iteration methods, as below.
(5) modification inside iteration is local copy only for struct due to value type nature.
playgroundcode.swift   Select all
open class Instrument { .... } .... // cannot set var a here in function parameter for Swift 3 (SE-0003) portfolio.forEach{ ( a : Instrument) -> () in var a = a // using shadow variable switch a.type { case .Unknown : a.type = Instrument.InstrumentType(ccy: "GBP", redemption: 110.0, issueDate: "20010101", maturityDate: "20291231") // modification is local copy only inside iteration for struct a.name = "MODIFIED NAME" default: () // do nothing } print(a.typeName) print(a) if let t = a.currencyType { print(t) } else { print("missing / invalid currency info \(a.ccy)") } print(a.issueDate ?? "No issueDate") print(a.maturityDate ?? "No maturityDate") print(a.description) print(a.NPV() ?? "No NPV") } print(portfolio[3].name) // instance can be modified inside print(portfolio[3].type) // modification is local copy only inside iteration for struct



Tuesday, August 30, 2016

How to parse JSON using JSONSerialization in Swift 3

Sample code in swift 3 (Xcode 8 beta 6) with Swift 2 code shown beneath
samplecode.swift   Select all
import Foundation let str1 = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}" let str2 = "{\"names\": [\"Bob2\", \"Tim2\", \"Tina2\"]};" for str in [str1, str2] { let data = str.data(using: String.Encoding.utf8) // let data = str.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) // Swift 2 do { let json = try JSONSerialization.jsonObject(with: data!) as! [String: AnyObject] // let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) // Swift 2 print(json) if let names = json["names"] as? [String] { print(names) } } catch let error as NSError { print(str) print("Failed to load: \(error.localizedDescription)") } }



Sample Code with json from url in swift 3 (Xcode 8 beta 6) with Swift 2 code shown beneath
samplecode.swift   Select all
import Foundation struct Video { var name: String var url: String } var musicvideo:[Video]=[] typealias JSONDictionary = [String: AnyObject] typealias JSONArray = Array<AnyObject> let url = Foundation.URL(string: "https://itunes.apple.com/us/rss/topmusicvideos/limit=3/json") //let url = NSURL(string: "https://itunes.apple.com/us/rss/topmusicvideos/limit=3/json") // Swift 2 do { let data = try Data(contentsOf: url!) // let data = NSData(contentsOfURL: url!) // Swift 2 let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! JSONDictionary // .allowFragments - top level object is not Array nor Dictionary. // let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) // Swift 2 if let feed = json["feed"] as? JSONDictionary, let entries = feed["entry"] as? JSONArray { // entries = feed["entry"] as? JSONArray { // Swift 2 //print(entries) for (index, entry) in entries.enumerated() { // for (index, entry) in entries.enumerate() { // Swift 2 //print("\(index) is \(entry)") if let name = entry["im:name"] as? JSONDictionary, let vName = name["label"] as? String, // SE-0099 XCode 8 beta 4 // vName = name["label"] as? String, // Swift 2 let video = entry["link"] as? JSONArray, // SE-0099 XCode 8 beta 4 // video = entry["link"] as? JSONArray, // Swift 2 let vUrl = video[1] as? JSONDictionary, // SE-0099 XCode 8 beta 4 // vUrl = video[1] as? JSONDictionary, // Swift 2 let vHref = vUrl["attributes"] as? JSONDictionary, // SE-0099 XCode 8 beta 4 // vHref = vUrl["attributes"] as? JSONDictionary, // Swift 2 let vVideoUrl = vHref["href"] as? String // SE-0099 XCode 8 beta 4 // vVideoUrl = vHref["href"] as? String // Swift 2 { print(vName) print(vVideoUrl) musicvideo.append(Video(name: vName, url:vVideoUrl)) } } } } catch let error as NSError { print("Failed to load: \(error.localizedDescription)") } let jsonDict = musicvideo.map { return ["name":$0.name, "url":$0.url]} print(jsonDict)



Thursday, July 28, 2016

How to write custom XMLParser for Swift 3

There are some general purpose XMLParsers libraries on github e.g. SWXMLHash or XML

Sometimes, it is faster to write your own and can use it in Playgrounds. What you need for a simple XMLParser is to define a class with XMLParserDelegate and write parsing rules in "didStartElement", "foundCharacters" and "didEndElement" methods in the delegated class.

Below is an example code in swift 3 (Xcode 8 beta 6) and with Swift 2.1 code added as comments underneath. And try to parse the xml file from quandl.com online dataset.
// curl "https://www.quandl.com/api/v3/datasets/FRED/DEXJPUS.xml"

These codes do not work on Linux Swift due to incomplete implementation of Foundation library on Linux yet.

testQuandl_main.swift    Select all
// // main.swift // testQuandl // import Foundation func timetest(_ note: String, block: () -> Void) //func timetest(note: String, block: () -> Void) // Swift 2 { let date = Date() // let date = NSDate() // Swift 2 block() let timeInterval = Date().timeIntervalSince(date) // let timeInterval = NSDate().timeIntervalSinceDate(date) // Swift 2 print("Test:", note); print("Elapsed time: \(String(format: "%.2f", timeInterval)) s") } extension String { func trimmed() -> String { return self.trimmingCharacters(in: .whitespacesAndNewlines) //return self.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines()) // Xcode 8 beta 1 //return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) // Swift 2 } } class QuandlCCYParser : NSObject, Foundation.XMLParserDelegate { // class QuandlCCYParser : NSObject, Foundation.NSXMLParserDelegate { // Swift 2 var parser = Foundation.XMLParser() // var parser = Foundation.NSXMLParser() // Swift 2 fileprivate var element:String = String() fileprivate var type:String = String() fileprivate var elements:Dictionary<String,String>? = [String: String]() var dataset = [Dictionary<String,String>]() fileprivate var name:String? = String() fileprivate var newest_available_date:String? = String() var dataPoints:[Dictionary<String,String>] = [[String:String]]() fileprivate var date:String? = String() fileprivate var value:String? = String() func startParsing(_ xmltxt:String) { // func startParsing(xmltxt:String) { // Swift 2 dataset = [] let xmlData = xmltxt.data(using: String.Encoding.utf8)! // let xmlData = xmltxt.dataUsingEncoding(NSUTF8StringEncoding)! // Swift 2 parser = Foundation.XMLParser(data: xmlData) // parser = Foundation.NSXMLParser(data: xmlData) // Swift 2 parser.delegate = self parser.parse() } func startParsing(urlpath:String) { // func startParsing(urlpath urlpath:String) { // Swift 2 dataset = [] parser = Foundation.XMLParser(contentsOf:(Foundation.URL(string:urlpath))! as Foundation.URL)! // parser = Foundation.NSXMLParser(contentsOfURL:(Foundation.NSURL(string:urlpath))! as Foundation.NSURL)! // Swift 2 parser.delegate = self parser.parse() } func parser(_ parser: Foundation.XMLParser, // func parser(parser: Foundation.NSXMLParser, // Swift 2 didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) { element = elementName if let type = attributeDict["type"] { self.type = type } else { self.type = "" } // Step 1 : start element and set nil // <datum type="array"> // <datum type="date">2018-11-23</datum> if (elementName == "datum" && attributeDict["type"] == "date") { date = nil elements = nil } else if (elementName == "datum" && attributeDict["type"] == "float") { value = nil elements = nil } else if (elementName == "name") { elements = nil name = nil } // Step 1 : start element and set nil // <newest-available-date type="date">2018-11-23</newest-available-date> else if (elementName == "newest-available-date" && attributeDict["type"] == "date") { elements = nil newest_available_date = nil } } func parser(_ parser: Foundation.XMLParser, // func parser(parser: Foundation.NSXMLParser, // Swift 2 foundCharacters string: String) { // Step 2 found characters here and set variable to "" and then append string if element == "datum" && type == "date" { if date == nil { date = "" } date!.append(string) // date! += string // Swift 2 } else if element == "datum" && type == "float" { if value == nil { value = "" } value!.append(string) // value! += string // Swift 2 } else if element == "name" { if name == nil { name = "" } name!.append(string) // name! += string // Swift 2 } else if element == "newest-available-date" && type == "date" { if newest_available_date == nil { newest_available_date = "" } newest_available_date!.append(string) // newest_available_date! += string // Swift 2 } } func parser(_ parser: Foundation.XMLParser, // func parser(parser: Foundation.NSXMLParser, // Swift 2 didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { // Step 3 append data points when end element if (elementName == "datum" && type == "float") { if (date != nil && value != nil) { elements = [:] elements!["date"] = date!.trimmed() elements!["value"] = value!.trimmed() } if elements != nil { dataPoints.append(elements!) (date, value, elements) = (nil, nil, nil) } } else if elementName == "dataset" { elements = [:] if name != nil { elements!["name"] = name!.trimmed() } if newest_available_date != nil { elements!["newest-available-date"] = newest_available_date!.trimmed() } if elements != nil { dataset.append(elements!) } (date, value, elements) = (nil, nil, nil) } } func showdataset() { for data in dataset { if let name = data["name"], let newest_available_date = data["newest-available-date"] { // SE-0099 XCode 8 beta 4 // if let name = data["name"], newest_available_date = data["newest-available-date"] { // Swift 2 print("\(name) \(newest_available_date)") } } } } func test1() { let test = QuandlCCYParser() // curl "https://www.quandl.com/api/v3/datasets/FRED/DEXJPUS.xml" test.startParsing(urlpath:"https://www.quandl.com/api/v3/datasets/FRED/DEXJPUS.xml") test.showdataset() for data in test.dataPoints.reversed() where data["date"]! >= "2016-01-01" { // for data in test.dataPoints.reverse() where data["date"] >= "2016-01-01" { // Swift 2 if let date = data["date"], let value = Float(data["value"]!) { // SE-0099 XCode 8 beta 4 // if let date = data["date"], value = Float(data["value"]!) { // Swift 2 print("Date \(date) , USDJPY = \(String(format: "%.2f", value)) JPYUSD = \(1/value)") } } } timetest("DEXJPUS XMLParser", block:test1)

Xcode 8 Beta output




Below is another example XMLParser for Markit Interest Rate Curve Data and to retrieve curvepoints and other field items under Deposits and Swaps tags.
testMarkit_main.swift    Select all
// // main.swift // testMarkit // import Foundation func timetest(_ note: String, block: () -> Void) //func timetest(note: String, block: () -> Void) // Swift 2 { let date = Date() // let date = NSDate() // Swift 2 block() let timeInterval = Date().timeIntervalSince(date) // let timeInterval = NSDate().timeIntervalSinceDate(date) // Swift 2 print("Test:", note); print("Elapsed time: \(String(format: "%.2f", timeInterval)) s") } extension String { func trimmed() -> String { return self.trimmingCharacters(in: .whitespacesAndNewlines) //return self.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines()) // Xcode 8 beta 1 //return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) // Swift 2 } } class ParserBase : NSObject, Foundation.XMLParserDelegate { // class ParserBase : NSObject, Foundation.NSXMLParserDelegate { // Swift 2 var parser = Foundation.XMLParser() // var parser = Foundation.NSXMLParser() // Swift 2 var currentElement:String = "" var foundCharacters = "" weak var parent:ParserBase? = nil func startParsing(_ xmltxt:String) { // func startParsing(xmltxt:String) { // Swift 2 let xmlData = xmltxt.data(using: String.Encoding.utf8)! // let xmlData = xmltxt.dataUsingEncoding(NSUTF8StringEncoding) // Swift 2 parser = Foundation.XMLParser(data: xmlData) // parser = Foundation.NSXMLParser(data: xmlData) // Swift 2 parser.delegate = self parser.parse() } func startParsing(urlpath:String) { // func startParsing(urlpath urlpath:String) { // Swift 2 parser = Foundation.XMLParser(contentsOf:(Foundation.URL(string:urlpath))! as Foundation.URL)! // parser = Foundation.NSXMLParser(contentsOfURL:(Foundation.NSURL(string:urlpath))! as Foundation.NSURL)! // Swift 2 parser.delegate = self parser.parse() } func startParsing(url:URL) { // func startParsing(url url:Foundation.NSURL) { // Swift 2 parser = Foundation.XMLParser(contentsOf:url)! // parser = Foundation.NSXMLParser(contentsOfURL:url)! // Swift 2 parser.delegate = self parser.parse() } func parser(_ parser: Foundation.XMLParser, // func parser(parser: Foundation.NSXMLParser, // Swift 2 didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) { currentElement = elementName } func parser(_ parser: Foundation.XMLParser, foundCharacters string: String) // func parser(parser: Foundation.NSXMLParser, foundCharacters string: String) // Swift 2 { self.foundCharacters += string } } class InterestRateCurve : ParserBase { var currency = "" var effectiveasof = "" lazy var deposits = Deposit() lazy var swaps = Swap() override func parser(_ parser: Foundation.XMLParser, // override func parser(parser: Foundation.NSXMLParser, // Swift 2 didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) { // if we found a tag, delegate further responsibility // to parsing to a new instance of Deposit or Swap if elementName == "deposits" { self.deposits = Deposit() // push responsibility parser.delegate = deposits // let delegate know who is the parent // so that once done XML processing // it can return parsing responsibility back deposits.parent = self } else if elementName == "swaps" { self.swaps = Swap() // push responsibility parser.delegate = swaps // let delegate know who is the parent // so that once done XML processing // it can return parsing responsibility back swaps.parent = self } super.parser(parser, didStartElement: elementName, namespaceURI: namespaceURI, qualifiedName: qName, attributes: attributeDict) } func parser(_ parser: Foundation.XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // func parser(parser: Foundation.NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // Swift 2 { // get other elements for deposits if elementName == "currency" { self.currency = foundCharacters.trimmed() } else if elementName == "effectiveasof" { self.effectiveasof = foundCharacters.trimmed() } // reset found characters foundCharacters = "" } } class Deposit : ParserBase { var curvepoints = [CurvePoint]() var spotdate:String = "" var daycountconvention:String = "" var snaptime:String = "" override func parser(_ parser: Foundation.XMLParser, // override func parser(parser: Foundation.NSXMLParser, // Swift 2 didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) { if elementName == "curvepoint" { let depo = CurvePoint() self.curvepoints.append(depo) // push responsibility parser.delegate = depo // let delegate know who is the parent depo.parent = self } super.parser(parser, didStartElement: elementName, namespaceURI: namespaceURI, qualifiedName: qName, attributes: attributeDict) } func parser(_ parser: Foundation.XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // func parser(parser: Foundation.NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // Swift 2 { // print("processing didEndElement <\(elementName)> tag from Deposit") // if we reached the tag, we do not // have anything further to do, so delegate // parsing responsibility to parent if elementName == "deposits" { parser.delegate = self.parent } // get other field items for deposits else if elementName == "spotdate" { self.spotdate = foundCharacters.trimmed() } else if elementName == "daycountconvention" { self.daycountconvention = foundCharacters.trimmed() } else if elementName == "snaptime" { self.snaptime = foundCharacters.trimmed() } // reset found characters foundCharacters = "" } } class Swap : ParserBase { var curvepoints = [CurvePoint]() var spotdate:String = "" var fixeddaycountconvention:String = "" var floatingdaycountconvention:String = "" var fixedpaymentfrequency:String = "" var floatingpaymentfrequency:String = "" var snaptime:String = "" override func parser(_ parser: Foundation.XMLParser, // override func parser(parser: Foundation.NSXMLParser, // Swift 2 didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String: String]) { if elementName == "curvepoint" { let swap = CurvePoint() self.curvepoints.append(swap) // push responsibility parser.delegate = swap // let delegate know who is the parent // so that it can return parsing responsibility // back after XML processing is done swap.parent = self } super.parser(parser, didStartElement: elementName, namespaceURI: namespaceURI, qualifiedName: qName, attributes: attributeDict) } func parser(_ parser: Foundation.XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // func parser(parser: Foundation.NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // Swift 2 { // print("processing didEndElement <\(elementName)> tag from Swap") // if we reached the </swaps> tag, we do not // have anything further to do, so delegate // parsing responsibility to parent if elementName == "swaps" { parser.delegate = self.parent } // get other field items for swaps else if elementName == "spotdate" { self.spotdate = foundCharacters.trimmed() } else if elementName == "fixeddaycountconvention" { self.fixeddaycountconvention = foundCharacters.trimmed() } else if elementName == "floatingdaycountconvention" { self.floatingdaycountconvention = foundCharacters.trimmed() } else if elementName == "fixedpaymentfrequency" { self.fixedpaymentfrequency = foundCharacters.trimmed() } else if elementName == "floatingpaymentfrequency" { self.floatingpaymentfrequency = foundCharacters.trimmed() } else if elementName == "snaptime" { self.snaptime = foundCharacters.trimmed() } // reset found characters foundCharacters = "" } } class CurvePoint : ParserBase { var tenor = "" var maturitydate = "" var parrate:Float = 0.0 func parser(_ parser: Foundation.XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // func parser(parser: Foundation.NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) // Swift 2 { // print("processing didEndElement <\(elementName)> tag from CurvePoint") // if we finished an tag, the ParserBase parent // would have accumulated the found characters // so just assign that to our variable if elementName == "tenor" { self.tenor = foundCharacters.trimmed() } else if elementName == "maturitydate" { self.maturitydate = foundCharacters.trimmed() } // similarly for other tags else if elementName == "parrate" { if let l = Float(foundCharacters.trimmed()) { self.parrate = l } } // if we reached the </curvepoint> tag, we do not // have anything further to do, so delegate // parsing responsibility to parent else if elementName == "curvepoint" { parser.delegate = self.parent } // reset found characters foundCharacters = "" } } func printcurve(_ xmltxt:String) -> Void { //func printcurve(xmltxt:String) -> Void { // Swift 2 let interestRateCurve = InterestRateCurve() interestRateCurve.startParsing(xmltxt) print("interestRateCurve currency is \(interestRateCurve.currency) and effectiveasof is \(interestRateCurve.effectiveasof)") print(String(repeating: "-", count: 65)) // SE-0130 Xcode 8 beta 6 // print(String(repeating: ("-" as Character), count: 65)) // Xcode 8 beta 1 print("Deposits spotdate is \(interestRateCurve.deposits.spotdate) daycountconvention is \(interestRateCurve.deposits.daycountconvention)") for depo in interestRateCurve.deposits.curvepoints { print("Depo tenor = \(depo.tenor) maturitydate = \(depo.maturitydate) and parrate = \(depo.parrate)") } print("") print("Swaps spotdate is \(interestRateCurve.swaps.spotdate) fixeddaycountconvention is \(interestRateCurve.swaps.fixeddaycountconvention) floatingdaycountconvention is \(interestRateCurve.swaps.floatingdaycountconvention)") for swap in interestRateCurve.swaps.curvepoints { print("Swap tenor = \(swap.tenor) maturitydate = \(swap.maturitydate) and parrate = \(swap.parrate)") } } let xmltxt = "<?xml version=\"1.0\" standalone=\"yes\" ?><interestRateCurve><effectiveasof>2016-07-05</effectiveasof><currency>GBP</currency><baddayconvention>M</baddayconvention><deposits><daycountconvention>ACT/365</daycountconvention><snaptime>2016-07-04T15:00:00.000Z</snaptime><spotdate>2016-07-05</spotdate><calendars><calendar>none</calendar></calendars><curvepoint><tenor>1M</tenor><maturitydate>2016-08-05</maturitydate><parrate>0.004848</parrate></curvepoint><curvepoint><tenor>2M</tenor><maturitydate>2016-09-05</maturitydate><parrate>0.005009</parrate></curvepoint><curvepoint><tenor>3M</tenor><maturitydate>2016-10-05</maturitydate><parrate>0.005163</parrate></curvepoint><curvepoint><tenor>6M</tenor><maturitydate>2017-01-05</maturitydate><parrate>0.006185</parrate></curvepoint><curvepoint><tenor>1Y</tenor><maturitydate>2017-07-05</maturitydate><parrate>0.008459</parrate></curvepoint></deposits><swaps><fixeddaycountconvention>ACT/365</fixeddaycountconvention><floatingdaycountconvention>ACT/365</floatingdaycountconvention><fixedpaymentfrequency>6M</fixedpaymentfrequency><floatingpaymentfrequency>6M</floatingpaymentfrequency><snaptime>2016-07-04T15:00:00.000Z</snaptime><spotdate>2016-07-05</spotdate><calendars><calendar>none</calendar></calendars><curvepoint><tenor>2Y</tenor><maturitydate>2018-07-05</maturitydate><parrate>0.00497</parrate></curvepoint><curvepoint><tenor>3Y</tenor><maturitydate>2019-07-05</maturitydate><parrate>0.00504</parrate></curvepoint><curvepoint><tenor>4Y</tenor><maturitydate>2020-07-05</maturitydate><parrate>0.00539</parrate></curvepoint><curvepoint><tenor>5Y</tenor><maturitydate>2021-07-05</maturitydate><parrate>0.00589</parrate></curvepoint><curvepoint><tenor>6Y</tenor><maturitydate>2022-07-05</maturitydate><parrate>0.00656</parrate></curvepoint><curvepoint><tenor>7Y</tenor><maturitydate>2023-07-05</maturitydate><parrate>0.00732</parrate></curvepoint><curvepoint><tenor>8Y</tenor><maturitydate>2024-07-05</maturitydate><parrate>0.00809</parrate></curvepoint><curvepoint><tenor>9Y</tenor><maturitydate>2025-07-05</maturitydate><parrate>0.00879</parrate></curvepoint><curvepoint><tenor>10Y</tenor><maturitydate>2026-07-05</maturitydate><parrate>0.0094</parrate></curvepoint><curvepoint><tenor>12Y</tenor><maturitydate>2028-07-05</maturitydate><parrate>0.01041</parrate></curvepoint><curvepoint><tenor>15Y</tenor><maturitydate>2031-07-05</maturitydate><parrate>0.01134</parrate></curvepoint><curvepoint><tenor>20Y</tenor><maturitydate>2036-07-05</maturitydate><parrate>0.01186</parrate></curvepoint><curvepoint><tenor>25Y</tenor><maturitydate>2041-07-05</maturitydate><parrate>0.01179</parrate></curvepoint><curvepoint><tenor>30Y</tenor><maturitydate>2046-07-05</maturitydate><parrate>0.01162</parrate></curvepoint></swaps></interestRateCurve>" timetest("Interest Rate Curve XMLParser", block:{printcurve(xmltxt)})

Xcode 8 Beta output




MarKit data are zipped archives. Here is a sample shell script to retrieve and unzip the interest rate curve data. Alternative way is to use other unzip Swift Framework and unzip the url data contents in the code.
getMakit.sh    Select all
#!/bin/bash mkdir -p ~/Downloads/MarKit cd ~/Downloads/MarKit for date in "20160704" "20160705" ;do for ccy in "USD" "GBP" "EUR" "JPY" "CHF" "CAD" "AUD" "NZD" "SGD" "HKD" ;do echo InterestRates_${ccy}_${date}.zip curl -OL https://www.markit.com/news/InterestRates_${ccy}_${date}.zip unzip -o InterestRates_${ccy}_${date}.zip done done


After download and unzip in a folder, it is possible to run a series of XMLParser like this code below

testMarkit2_main.swift    Select all
func test2(url:Foundation.URL) { //func test2(url url:Foundation.NSURL) { // Swift 2 let interestRateCurve = InterestRateCurve() interestRateCurve.startParsing(url:url) print("interestRateCurve currency is \(interestRateCurve.currency) and effectiveasof is \(interestRateCurve.effectiveasof)") print(String(repeating: "-", count: 65)) // SE-0130 Xcode 8 beta 6 // print(String(repeating: ("-" as Character), count: 65)) // Xcode 8 beta 1 print("Deposits spotdate is \(interestRateCurve.deposits.spotdate) daycountconvention is \(interestRateCurve.deposits.daycountconvention)") for depo in interestRateCurve.deposits.curvepoints { print("Depo tenor = \(depo.tenor) maturitydate = \(depo.maturitydate) and parrate = \(depo.parrate)") } print("") print("Swaps spotdate is \(interestRateCurve.swaps.spotdate) fixeddaycountconvention is \(interestRateCurve.swaps.fixeddaycountconvention) floatingdaycountconvention is \(interestRateCurve.swaps.floatingdaycountconvention)") for swap in interestRateCurve.swaps.curvepoints { print("Swap tenor = \(swap.tenor) maturitydate = \(swap.maturitydate) and parrate = \(swap.parrate)") } } for date in ["20160704","20160705"] { for ccy in ["USD","GBP"] { let url = Foundation.URL(fileURLWithPath: NSHomeDirectory() + "/Downloads/MarKit/InterestRates_\(ccy)_\(date).xml") // let url = Foundation.NSURL(fileURLWithPath: NSHomeDirectory() + "/Downloads/MarKit/InterestRates_\(ccy)_\(date).xml") // Swift 2 timetest("InterestRates_\(ccy)_\(date).xml", block:{test2(url:url)}) } }


Below is the playground code (swift 3 Xcode 8 beta 6 and updated to support swift 4 Xcode 9 beta 2) that make use of the compression library (introduced from iOS9 and macOS10.11) to unzip the MarKit Interest Rate Curve url download and then possibly use the InterestRateCurve() XMLParser to print curve points.

unzip_getMarkit.swift    Select all
import Foundation import Compression func timetest(_ note: String, block: () -> Void) //func timetest(note: String, block: () -> Void) // Swift 2 { let date = Date() // let date = NSDate() // Swift 2 block() let timeInterval = Date().timeIntervalSince(date) // let timeInterval = NSDate().timeIntervalSinceDate(date) // Swift 2 print("Test:", note); print("Elapsed time: \(String(format: "%.2f", timeInterval)) s") } func getMarkit(ccy:String, date:String) -> String? { //func getMarkit(ccy ccy:String, date:String) -> String? { // Swift 2 var bytes:[UInt8] = [] var dst:[UInt8] = [] let markitURL = Foundation.URL(string: "https://www.markit.com/news/InterestRates_"+ccy+"_"+date+".zip") // let markitURL = Foundation.NSURL(string: "https://www.markit.com/news/InterestRates_"+ccy+"_"+date+".zip") // Swift 2 guard let markitData = try? Data(contentsOf: markitURL!) , markitData.subdata(in: 0..<4).elementsEqual([0x50,0x4b,0x03,0x04]) // find <504b0304> little-endian <04034b50> // guard let markitData = try? Data(contentsOf: markitURL!) where markitData.subdata(in: 0..<4).elementsEqual([0x50,0x4b,0x03,0x04]) // Xcode 8 beta 1 // guard let markitData = NSData(contentsOfURL: markitURL!) where markitData.subdataWithRange(NSMakeRange(0,4)).isEqualToData(NSData(bytes:[0x50,0x4b,0x03,0x04] as [UInt8], length:4)) // Swift 2 else { return nil } // if let data:NSData = markitData as NSData { // Swift 2 or Xcode 8 beta 1 bytes = Array(UnsafeBufferPointer(start: (markitData as NSData).bytes.bindMemory(to: UInt8.self, capacity: markitData.count), count: markitData.count)) // SE-0107 Xcode 8 beta 6 and convert from markitData:Data to [UInt8] // if convert from data:NSData to [UInt8] // bytes = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes.assumingMemoryBound(to: UInt8.self)), count: data.length)) // Xcode 8 beta 6 // bytes = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)) // Swift 2 or Xcode 8 beta 1 // } // Swift 2 or Xcode 8 beta 1 var firstcentralheader: Int = 0 var offset: Int = 0 var nextoffset: Int = 0 var found:Bool = false let xmlfilenameprefix = "InterestRates" var xmlfilenamelength: Int = 0 var xmlfilename : String = "" for i in 1...bytes.count-4 { // Central directory file header signature = 0x02014b50 if bytes[i..<i+4].elementsEqual([0x50,0x4b,0x01,0x02]) { // find <504b0102> little-endian <02014b50> if firstcentralheader == 0 { firstcentralheader = i } // Central directory : 28 2 File name length (n) let filenamelength = bytes[(i+28)..<(i+28+2)] .enumerated() // .enumerate() // Swift 2 .map { let (index, element) = $0; return Int(Double(element) * pow(256,Double(index))) } // Xcode 9 beta 2 swift 4 and swift 3, SE-0110 which will be back-out in official release // .map { (index, element) in return Int(Double(element) * pow(256,Double(index))) } // Xcode 8 beta 6 // .map { (index, element) in return Int(element) * Int(pow(Double(256),Double(index))) } // Swift 2 .reduce(0, +) // Xcode 8 beta 6 // .reduce(0, combine: +) // Swift 2 or Xcode 8 beta 1 let filename = bytes[(i+46)..<(i+46+filenamelength)].reduce("", { $0 + String(format: "%c", $1)}) // Xcode 8 beta 6 // let filename = bytes[(i+46)..<(i+46+filenamelength)].reduce("", combine: { $0 + String(format: "%c", $1)}) // Swift 2 or Xcode 8 Beta 1 if !found && filename.hasPrefix(xmlfilenameprefix) { // Central directory : 42 4 Relative offset of local file header offset = bytes[(i+42)..<(i+42+4)] .enumerated() // .enumerate() // Swift 2 .map { let (index, element) = $0; return Int(Double(element) * pow(256,Double(index))) } // Xcode 9 beta 2 swift 4 and swift 3, SE-0110 which will be back-out in official release // .map { (index, element) in return Int(Double(element) * pow(256,Double(index))) } // Xcode 8 beta 6 // .map { (index, element) in return Int(element) * Int(pow(Double(256),Double(index))) } // Swift 2 .reduce(0, +) // Xcode 8 beta 6 // .reduce(0, combine: +) // Swift 2 or Xcode 8 beta 1 // Local file header : offset+26 2 File name length (n) xmlfilenamelength = bytes[(offset+26)..<(offset+26+2)] .enumerated() // .enumerate() // Swift 2 .map { let (index, element) = $0; return Int(Double(element) * pow(256,Double(index))) } // Xcode 9 beta 2 swift 4 and swift 3, SE-0110 which will be back-out in official release // .map { (index, element) in return Int(Double(element) * pow(256,Double(index))) } // Xcode 8 beta 6 // .map { (index, element) in return Int(element) * Int(pow(Double(256),Double(index))) } // Swift 2 .reduce(0, +) // Xcode 8 beta 6 // .reduce(0, combine: +) // Swift 2 or Xcode 8 beta 1 xmlfilename = bytes[(i+46)..<(i+46+xmlfilenamelength)].reduce("", { $0 + String(format: "%c", $1)}) // Xcode 8 beta 6 // xmlfilename = bytes[(i+46)..<(i+46+xmlfilenamelength)].reduce("", combine: { $0 + String(format: "%c", $1)}) // Swift 2 or Xcode 8 beta 1 found = true } else { if found && nextoffset == 0 { nextoffset = bytes[(i+42)..<(i+42+4)] .enumerated() // .enumerate() // Swift 2 .map { let (index, element) = $0; return Int(Double(element) * pow(256,Double(index))) } // Xcode 9 beta 2 swift 4 and swift 3, SE-0110 which will be back-out in official release // .map { (index, element) in return Int(Double(element) * pow(256,Double(index))) } // Xcode 8 beta 6 // .map { (index, element) in return Int(element) * Int(pow(Double(256),Double(index))) } // Swift 2 .reduce(0, +) // Xcode 8 beta 6 // .reduce(0, combine: +) // Swift 2 or Xcode 8 beta 1 break } } } } //print(xmlfilename) // Local file header : offset+30 n File name let bytes2 = Array(bytes[(offset+30+xmlfilenamelength)..<(nextoffset > 0 ? nextoffset :firstcentralheader)]) if bytes2.count > 0 { dst = [UInt8](repeating: 0, count: bytes2.count*10) // destination buffer // dst = [UInt8](count: bytes2.count*10, repeatedValue: 0 ) // destination buffer // Swift 2 // use compression library function (iOS9 or macOS 10.11 or above) if #available(OSX 10.11, iOS 9.0, *) { let size = compression_decode_buffer(&dst, dst.count, bytes2, bytes2.count, nil, COMPRESSION_ZLIB) if size > 0 { if let outxml = String(bytes: dst[0..<size], encoding: String.Encoding.ascii) { // if let outxml = String(bytes: dst[0..<size], encoding: NSASCIIStringEncoding) { // Swift 2 return outxml } } } } return nil } timetest("Get MarKit xml", block:{ for date in ["20160808","20160809"] { for ccy in ["USD","GBP"] { if let xml = getMarkit(ccy: ccy, date: date) { print(xml) // printcurve(xml) // if using the InterestRateCurve() XMLParser to print curve points } } } })




Thursday, July 14, 2016

How to use Custom Framework in Xcode Swift Playground

This is a working example

(1) Open Mac Terminal and
cd ~
git clone --depth=1 http://github.com/neonichu/ThisCouldBeUsButYouPlaying.git
cd ThisCouldBeUsButYouPlaying
sudo gem install cocoapods-playgrounds
pod playgrounds Alamofire


(2) In Xcode Build Settings, change the SDKROOT to latest iOS SDK Platform and then select Product -> Destination to iPhone 5s or above (that is simulator destination)


(3) Select Product -> Build (or ⌘B shortcut) to build the framework

(4) In Alamofire.playground, input swift code to play
import Alamofire
print(AlamofireVersionNumber)







Important: The following conditions are required for the custom framework to work in a playground: (ref)
- The framework is in the same workspace as the playground. Use "Save as Workspace" if it is not.
- If it is an iOS framework, it is built for a 64-bit runtime destination (e.g. iPhone 5s simulator).
- The workspace contains at least one active scheme that builds a target. (avoid using legacy build location in project folder)
- The framework has already been built. (⌘B)
- If it is an Objective-C framework, sets the Defines Module build setting to Yes. If it is a Swift framework, sets to No.

The working example above is an iOS Framework for Simulator built and works for iOS Playground in the same workspace. Based on various testings, OS X Custom Framework currently does not work for OS X Playground in Xcode 7.x.