Bitcode and dylib - ios

I am trying to compile a C library to use it in my iOS project, and I want to embed bitcode.
I can successfully build static libraries targeting each arch. And those static library do contain bitcode (checked using otool), but the dynamic library doesn't contain bitcode. Why? Is bitcode not supported in dylib?
The library I am trying to build is xz. Here is the script
build_iOS()
{
ARCH=$1
if [ $ARCH == "i386" ] || [ $ARCH == "x86_64" ];
then
SDKROOT="$(xcodebuild -version -sdk iphonesimulator | grep -E '^Path' | sed 's/Path: //')"
else
SDKROOT="$(xcodebuild -version -sdk iphoneos | grep -E '^Path' | sed 's/Path: //')"
fi
export CC="$(xcrun -sdk iphoneos -find clang)"
export CFLAGS="-fembed-bitcode -isysroot $SDKROOT -arch ${ARCH} -miphoneos-version-min=9.0"
export LDFLAGS="-arch ${ARCH} -isysroot $SDKROOT"
if [ $ARCH == "i386" ] || [ $ARCH == "x86_64" ];
then
./configure --prefix=$XZPATH/build/iOS/$ARCH --host=i686-apple-darwin11 --disable-static --enable-shared
else
./configure --prefix=$XZPATH/build/iOS/$ARCH --host=arm-apple-darwin --disable-static --enable-shared
fi
make && make install && make clean
}
build_iOS i386
build_iOS x86_64
build_iOS armv7
build_iOS armv7s
build_iOS arm64
Thanks!

It looks like I cannot add bitcode to dylibs. I tried building several dylibs, then use otool -l path_to_dylib | grep bitcode to test if they contain any bitcode, all got nothing.
More evidence:
in Xcode(7.3.1), macOS (previously called OS X) targets don't have enable bitcode option in build settings
in the bitcode section of App Thinning, Apple didn't mentioned bitcode on macOS. Plus, App Thinning is only available on iOS, watchOS and tvOS.
I currently don't know why macOS apps don't have enable bitcode option in build setting. Maybe it's because Mac App store is not the only way for distributing mac apps? And people might copy one mac app from one mac app to another using USB sticks?

I was not able to verify bitcode in my bitcode enabled dynamic library via cmd line tools (otool, file or clang). Also comparing the diff between bitcode and non-bitcode build showed no difference, except the filesize.
Interestingly when using the dynamic library withouth bitcode enabled in an actual app and archiving xcode will fail to archive when I use the non-bitcode build:
ld: bitcode bundle could not be generated because '...' was built without full bitcode. All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build for architecture armv7
When building the dylib with bitcode enabled the filesize increases a lot and also xcode does not fail on archiving a sample project with bitcode enabled. So I am pretty sure that bitcode must be included in the dynamic lib, although we haven't found a way to verify that via cmd line tools yet...

Related

Build C Library from makefile for ios and not macos

I have a makefile that builds some C files and if I run it on an M1 mac the resulting library has the architecture arm64 which I thought it what is necessary for them to compile with an Xcode project for iOS. I discovered I can run the command otool -l libf2c.a | grep platform which should tell me what it was compiled for and in my case it returns platform1 which indicates macOS. Based on this, I think I need a value of platform2 for iOS.
The reason this is an issue is because in Xcode I get the error ld: building for iOS, but linking in object file built for macOS, file '/Users/e.../close.o' for architecture arm64.
Based on what I have been researching it seems iOS and macOS have the same architecture (arm64) but are a different 'platform'? But, I am not sure how the platform is determined. Is there some setting in my makefile I need to specify the platform? I am assuming that if I am able to get the platform to be iOS then Xcode will cooperate and be able to build the library I have generated.
The preferred way to compile for iOS via command line would probably be to use the xcrun command. This will allow you to specify the correct SDK for the platform you actually want to run on. For example:
prompt$ xcrun --sdk iphoneos --toolchain iphoneos clang -c test.c -o test.o -arch arm64
prompt$ otool -v -l test.o | grep platform
platform IOS
TL;DR: change your compiler invocation from plain clang to xcrun --sdk iphoneos --toolchain iphoneos clang.

How to build a Fat Framework that includes Mac Catalyst?

How does one build a fat framework that includes the architectures necessary to build to Mac Catalyst apps?
Apple has introduced a (undocumented?) new target: x86_64-apple-ios13.0-macabi
How to build for this target depends on your frameworks build environment.
1) XCFramework
In case your framework is an Xcode project:
Select the target in Xcode
Select the "General" tab
Under "Deployment Info", tick the "Mac" checkbox:
build
2) External Build
In case you are building your framework outside Xcode, e.g. a C lib, instead of building for x86_64 & iphonesimulator, build for the new target x86_64-apple-ios13.0-macabi & macosx.
Example for C Lib using make:
MIN_IOS_VERSION="10.0"
LIB_NAME= "theNameOfYourLib"
# The build function
build()
{
ARCH=$1
TARGET=$2
HOST=$3
SDK=$4
SDK_PATH=`xcrun -sdk ${SDK} --show-sdk-path`
export PREFIX=build/${ARCH}
export CFLAGS="-arch ${ARCH} -isysroot ${SDK_PATH} -miphoneos-version-min=${MIN_IOS_VERSION} -std=c99 -target ${TARGET}"
export LDFLAGS="-arch ${ARCH}"
export CC="$(xcrun --sdk ${SDK} -f clang) -arch ${ARCH} -isysroot ${SDK_PATH}"
PKG_CONFIG_ALLOW_CROSS=1 PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig ./configure --host=${HOST} --prefix=$PREFIX
make
make install
}
# Build for all required architectures
build "armv7" "armv7-apple-ios" "arm-apple-darwin" "iphoneos" # MIN_IOS_VERSION must be one of arm7 supported ones to. Else remove this line.
build "arm64" "aarch64-apple-ios" "arm-apple-darwin" "iphoneos"
# build "x86_64" "x86_64-apple-ios" "x86_64-apple-darwin" "iphonesimulator" #obsolete due to x86_64-apple-ios13.0-macabi
build "x86_64" "x86_64-apple-ios13.0-macabi" "x86_64-apple-darwin" "macosx"
build "i386" "i386-apple-ios" "i386-apple-darwin" "iphonesimulator" # same as arm7: MIN_IOS_VERSION must be one of arm7 supported ones.
# Now find all the artefacts created above (e.g. build/arm64/lib/${LIB_NAME}.a, build/x86_64/lib/${LIB_NAME}.a ...) and merge them together to a fat lib using lipo
OUTPUT_DIR="fatLib"
lipo -create -output $OUTPUT_DIR/lib/${LIB_NAME}.a build/x86_64/lib/${LIB_NAME}.a build/arm64/lib/${LIB_NAME}.a build/armv7/lib/${LIB_NAME}.a build/i386/lib/${LIB_NAME}.a
# You may also need the header files
cp -R build/armv7/include/* $OUTPUT_DIR/include/
Note: You must/can not add slices for x86_64-apple-ios and x86_64-apple-ios13.0-macabito the fat lib. Both are x86_64. Use only the one for x86_64-apple-ios13.0-macabi.

Could not find module 'MyCustomFramework' for target 'x86_64-apple-ios-simulator'; found: arm64, armv7-apple-ios, arm64-apple-ios, arm, armv7

I have a custom framework that I am archiving for use in another project. After updating to Xcode11 I get the following error in my project utilizing the framework.
Could not find module 'MyCustomFramework' for target 'x86_64-apple-ios-simulator'; found: arm64, armv7-apple-ios, arm64-apple-ios, arm, armv7
My framework works fine on Xcode10 but does not on 11. My target is set to NO for build active architectures only. I have the following for Valid Architectures; arm64e, armv7s, armv7, arm64.
My build script
exec > ${PROJECT_DIR}/${PROJECT_NAME}_archive.log 2>&1
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: Detected, stopping"
else
export ALREADYINVOKED="true"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
echo "Building for iPhoneSimulator"
xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11 Pro Max' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build
# Step 1. Copy the framework structure (from iphoneos build) to the universal folder
echo "Copying to output folder"
cp -R "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule"
fi
# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory
echo "Combining executables"
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${EXECUTABLE_PATH}"
# Step 4. Create universal binaries for embedded frameworks
#for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do
#BINARY_NAME="${SUB_FRAMEWORK%.*}"
#lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}"
#done
# Step 5. Convenience step to copy the framework to the project's directory
ARCHIVE_PATH="${PROJECT_DIR}/Products"
rm -rf "${ARCHIVE_PATH}"
mkdir "${ARCHIVE_PATH}"
echo "Copying to project dir"
yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${ARCHIVE_PATH}"
open "${ARCHIVE_PATH}"
fi
This line is incorrect
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule"
Should be
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/"
You'll need to check in the target folder
"${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/"
If there are files like
x86_64-apple-ios-simulator.swiftdoc
x86_64-apple-ios-simulator.swiftmodule
x86_64.swiftdoc
x86_64.swiftmodule
Before Xcode 11, Apple seems neglect those files so your script works well.
From Xcode 11 those files are seem to be checked rigorously.
Swift 5.0-5.1, Xcode 11 Open Xcode, <your project>, Build Settings, Build Active Architecture Only and change to <NO> for Debug and Release. Architectures set/leave in Standard Architecture -$(ARCHS_STANDART), important is next step:Valid Architecture: armv7, armv7s, amr64, amr64e, ADD here x86_64 and if you need add i386 for Debug and Release. (String: armv7, armv7s, amr64, amr64e, x86_64)
Choose any simulator in your simulator list and BUILT IT. DONE.
I hope it is works for you.
Description of Architecture:
armv64: iPhoneX, iPhone 5s-8, iPad Air — iPad Pro
armv7 : iPhone3Gs-5c, iPad WIFI(4th gen)
armv6 : iPhone — iPhone3G
-the above if for real devices
i386 : 32-bit simulator
x86_64 : 64-bit simulator

Creating iOS universal framework with Xcode 9

I am creating universal framework for iOS. I am trying to create one through lipo and it does create a universal one
I check the architecture with lipo after creation it returns me correct:
Architectures in the fat file: i386 x86_64 armv7 arm64
I run the application on phone and simulator that works fine as well.. But when I try to export the .ipa from xcarchive I get the following error:
Failed to verify bitcode in Myframework.framework/Myframework:\nerror: Platform iPhoneSimulator is not supported\n\n
Also I can the bitcode symbols in my universal framework running
otool -l /Path/To/Framework | grep __LLVM
segname __LLVM
segname __LLVM
If I choose only iphoneos framework that works fine
You need to strip i386 and x86_64 from the framework before exporting the archive.
e.g.
$ lipo -remove i386 ./path/to/binary_name -o ./path/to/binary_name
$ lipo -remove x86_64 ./path/to/binary_name -o ./path/to/binary_name
You need to do this, since i386 and x86_64 are not supported for export -- "Platform iPhoneSimulator is not supported"

How to build Boost-Libraries for iPhone

Can someone tell me, where to find a detailed guide, how to build the Boost-Libraries for using it on the iPhone-Device.
I've allready build the libs for Mac and can use them in my project (only on iPhone-Simulator). While building the project for iPhone-Device, XCode haunts me a warning: "file is not of required architecture" ond some other errors.
Please Help
Start a new project in Xcode using the iPhone Static Library project template.
Then import the source and headers, and compile it that way. The result should be an iPhone compatible static library
I started here:
http://lists.boost.org/boost-build/2009/02/21326.php
With most of Boost you probably don't need to actually compile it, just include the useful headers. In my case, I just did the compiler define in my own Xcode project.
Hey I have updated Pete Goodliffes script in my openFrameworks addon:
It currently has arm64, armv7, i386, x86_64
Boost 1.59.0 or previous
libc++ / std=c++11 -- Now optional release for libstdc++
Precompiled and Script to build yourself (so if you need libstdc++ quite easy to change)
Supports Xcode 7
[https://github.com/danoli3/ofxiOSBoost][1]
For boost libraries which have only headers files (.hpp) you can just set header search path from your project to them.
For boost libraries with sources you can build static libraries for both ios phone/simulator with next simple steps:
Download and unpack a boost release archive (from https://www.boost.org/users/download/) e.g.: https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.bz2
Run bootstrap.sh with needed libraries to build for instance 'context' (format =library1,library2,...):
./bootstrap.sh --with-libraries=context
Add toolsets with correct paths to installed SDKs to project-config.jam:
# IOS ARM64
using clang : iphoneos
: xcrun clang -arch arm64 -stdlib=libc++ -std=c++11 -miphoneos-version-min=12.0 -fvisibility-inlines-hidden -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
;
# IOS x86_64
using clang : iphonesimulator
: xcrun clang -arch x86_64 -stdlib=libc++ -std=c++11 -miphoneos-version-min=12.0 -fvisibility-inlines-hidden -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk
;
Create and run build.sh script (where lib name is libboost_<name>.a):
lib=libboost_context.a
dir='stage/lib'
# Build arm64
./b2 -a -j4 toolset=clang-iphoneos binary-format=mach-o abi=aapcs link=static stage
mv $dir/$lib $dir/arm64_$lib
# Build x86_64
./b2 -a -j4 toolset=clang-iphonesimulator binary-format=mach-o abi=sysv link=static stage
mv $dir/$lib $dir/x86_64_$lib
# Make fat
lipo -create $dir/arm64_$lib $dir/x86_64_$lib -output $dir/$lib
Now you have next compiled static libraries in "/stage/lib" dir for boost context: arm64_libboost_context.a, x86_64_libboost_context.a and fat one libboost_context.a.
We use boost too. To simplify its inclusion into new applications I have created a Xcode project you can drop into your workspace to include boost. It is based on a Makefile so you need the Xcode commandline tools installed.
The project is here https://github.com/Cogosense/iOSBoostFramework.
Clone the project into your workspace, then click on Menu File->"Add Files to workspace". Select iOSBoostFramework/iOSBoostFramework.xcodeproj in the file finder and click add.
The Makefile in the iOSBoostFramework directory controls what is built and how it is built. There is support for Xcode workspace dependencies, bitcode generation, and only the target architectures selected by Xcode are built.
The following libraries are built test, thread, atomic, signals, filesystem, regex, program_options, system date_time, serialization, exception, locale, and random.
All the separate libraries and architectures are combined, the final build output is a FAT boost.framework Framework bundle which can be linked into the application.
The version of boost is specified in the Makefile (currently 1.64.0), it is downloaded, built for all active architectures and installed in the BUILT_PRODUCTS_DIR specified by xcode.
The previous answer helped me when I wanted to build boost for the arm simulator. When you have a Mac with M1 processor and want to use the simulator, you cannot use the arm64 build for the iPhone.
I added this to the project-config.jam:
# IOS Arm Simulator
using clang : iphonesimulatorarm64
: xcrun clang -arch arm64 -stdlib=libc++ -std=c++11 -miphoneos-version-min=10.0 -fvisibility-inlines-hidden -target arm64-apple-ios10.0-simulator -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ;
Then pass toolset=clang-iphonesimulatorarm64 to the b2 command.

Resources