Bitcode disabled on Carthage dependencies - ios

Scenario
My project (codebase shared for iOS/watchOS/tvOS ) has build settings with ENABLE_BITCODE = YES and takes advantage of fundamental libraries which are not yet supporting bitcode, although quoting Apple documentation in App Thinning
Bitcode is the default, but optional. For watchOS and tvOS apps,
bitcode is required. If you provide bitcode, all apps and frameworks
in the app bundle (all targets in the project) need to include bitcode
I am currently integrating those fundamental libraries with Carthage.
Problem
In order to have a clean build process, I tried to submit some pull requests to the respective owners for enabling the bitcode but, due to the complexity of their codebases, which are working for multiple operating systems/architectures, my pull requests are still in pending: so, to be able to build my own project, I still have to change manually their build settings.
Question
How can I short-circuit the Carthage process for injecting specific build settings (in this case ENABLE_BITCODE = YES) into the relevant libraries?

I found a solution by making a shell script able to erase the disabling of bitcode, in case someone is facing or curious to solve a similar problem, the script is this:
carthage update --platform ios
for D in ./Carthage/Checkouts/*; do
if [ -d "${D}" ]; then
find $D -type d -name \*.xcodeproj -print0 |
while IFS= read -r -d $'\0' folder; do
sed -i '' 's/ENABLE_BITCODE = NO;//g' $folder/project.pbxproj
done
fi
done
carthage build --platform ios
so basically the script's mechanism is:
downloading all the dependencies
for each dependency, find thepbxproj living inside xcodeproj and cut off the string ENABLE_BITCODE = NO
finally building the dependencies to make the .framework

To add to Andrea's answer, make sure you carthage build with --no-use-binaries as the dependency may have a bitcode disabled in its released framework which will be used without --no-use-binaries.

Related

How does one build a OpenSSL library for Project Catalyst?

I have to support OpenSSL in my project in building my iPad app for UIKitForMac. Currently, I get these errors.
Building for UIKit for Mac, but the linked library 'libssl.a' was built for freestanding. You may need to restrict the platforms for which this library should be linked in the target editor.
Building for UIKit for Mac, but the linked library 'libcrypto.a' was built for freestanding. You may need to restrict the platforms for which this library should be linked in the target editor.
I was reading about XCFrameworks, but Apple really hasn't put out much information here. Has anyone figured out build scenarios?
The solution in the comments doesn't work for me. However, I just build to different libs: iOS as I used to and another one for Catalyst by adding the build parameters: -target x86_64-apple-ios13.0-macabi and defining Mac SDK in -isysroot. After that, I just conditionally add each of the libraries for each build version and it works.
Amid mounting frustration following many failed attempts and Google searches, I successfully built openSSL 1.1.1g for Catalyst, compiled my project, linked openSSL and launched the app on my Mac by doing the following:
I used the same directory in to which I had previously extracted and built openSSL for IOS.
Following instructions here, I edited <openSSL directory>/Configurations/10-main.conf. Scrolling down to the "darwin64-x86_64-cc" section, I added a second CFLAGS line:
CFLAGS => add("-target x86_64-apple-ios13.0-macabi"),
In the openSSL directory, execute ./Configure darwin64-x86_64-cc -shared Note that I've seen several other versions of this Configure statement, some with many more options. This command worked for me, but I'm not sure what all the other variations do. You may want to research this further.
Execute make clean to clear all the objects from the prior IOS build
Execute make This successfully built openSSL.
In Xcode, under -> General -> "Frameworks, Libraries and Embedded Content" I removed both libcrypto.a and libssl.a this was a critical step
Switching tabs to Build Phases -> Link Binary With Libraries, verify both archives are removed from this section as well. (It appeared that removing them in step 5 also cleared them in step 6, but I'm not certain).
Back on General -> Frameworks, click the + to add new entries, select "add other" in the lower left corner of the popup window, then provide the path to the newly built libcrypto.a. Repeat for libssl.a
Delete the derived data in a terminal window (I'm not certain this was necessary, but did it out of an abundance of caution):
cd ~/Library/Developer/Xcode
mv DerivedData DerivedData.old
Build the project in Xcode. This successfully completed.
Steps 5-7 turned out to be critical. Even though I moved and/or completely replaced the prior libraries, when I tried to build in Xcode I would get linker errors that I was building for MacOS Catalina but trying to link something built for MacOS x86.

Using CMake to copy .frameworks to iOS app bundle

A library I'm using recently switched to distribution as a .framework.
In my existing CMake file, I've been successful at getting it to link with my iOS app, but am getting:
dyld: Library not loaded: #rpath/Pizza.framework/Pizza
Referenced from: /var/mobile/Containers/Bundle/Application/D71ED298-C287-4B2F-8AFA-710A14C06D75/pizzashop.app/pizza
Reason: image not found
when I install it from Xcode. If I manually add it to my xcode project, in the "embedded binaries" section then I'm good (see image below)
So I've concluded that the problem is getting the .framework into my app bundle. I've come across this question and looked at the linked QT example, but I'm still trying to orient myself here as I'm finding the syntax a bit opaque.
Is CMake's BundleUtilities what I want to use here? In looking at the BundleUtilities example I'm a bit lost:
set(APPS ...) # paths to executables
set(DIRS ...) # directories to search for prerequisites
INSTALL(CODE "
include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
" COMPONENT Runtime)
Is this OSX-specific or can I apply it similarly to iOS?
We didn't end up finding an ideal solution, and ended up doing things a bit more manually than preferred:
We added a custom command we run after the build is complete, but before it is packaged (see CMake's add_custom_command).
The custom command does the following:
creates a Frameworks directory under our app bundle folder (make sure it's somewhere where it will get copied in your packaging process).
we use cp -aH to copy all frameworks into this Frameworks directory
we then re-sign each framework in this directory using:
codesign --force --verbose Computers.framework --sign "$2"
Add the Frameworks directory to your search paths:
set_target_properties(${EXE_NAME} PROPERTIES
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "#executable_path/Frameworks")

how to build DLIB for iOS

I'm trying to build DLIB for an iOS project. Running the cmake results in a libdlib.a and a load of .o files.
When I add the library to an Xcode project I get warning that the library hasn't been built for arm64.
My question is two-part:
How can I build DLIB for iOS (I tried cmake **path_to_source** -DCMAKE_OSX_ARCHITECTURE="arm64" but it caused loads of errors e.g. unknown type name '__uint32_t'; did you mean '__uint128_t')?
What is the purpose of all the .o files that get built when you run cmake? Do I need to include them in an Xcode project?
I finally figured out how to do this:
Requirements
X11 (on a mac you can just open the X11 app and if X11 isn't installed it'll take you to the download).
Xcode
cmake (you can use home-brew for that)
Steps
In terminal make the lib-xx.xx/examples your root
Run:
mkdir build
cd build
cmake -G Xcode ..
cmake --build . --config Release
This will create a folder called dlib_build in which you can find an Xcode project that compiles the library. In the build settings of that Xcode project you can set the build architecture and SDK for any Xcode supported OS you like!
EDIT:
You have to include a lot of custom compiler flags and 3rd party libraries to get dlib to work in a project. Check out the examples.xcproject build settings.
To compliment RASS's answer, I am attaching screenshots showing how to change this to and from an iOS and OSX lib
After opening the project,
Select the project file from the project navigator
Select the dlib target all the way down the bottom
Select 'Build Settings'
Expand 'Base SDK' drop down
Select either iOS or macOS (OSX)
I hope this helps some people out! gl
Rob Sanders and mylogon already show how to build dlib for ios, here is how to use it:
add libdlib.a to project, and add path to library search paths
add all source to include directory(do not add to project), and add path to header search paths.
add accelerate framework, which contains blas symbols.
add preprocessor macros, from building settings, "custom compiler flag"/"other c flags". these macros make sure the header files match the lib.
-DDLIB_JPEG_SUPPORT
-DDLIB_NO_GUI_SUPPORT
-DNDEBUG
-DDLIB_USE_BLAS
-DDLIB_USE_LAPACK

How to compile OpenCV iOS with ENABLE_BITCODE

When I tried to compile my XCode project with OpenCV 2.4 iOS using XCode 7 + iOS SDK 9, XCode complained that
ld:
'opencv2.framework/opencv2(alloc.o)'
does not contain bitcode. You must rebuild it with bitcode enabled
(Xcode setting ENABLE_BITCODE), obtain an updated library from the
vendor, or disable bitcode for this target. for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see
invocation)
and refused to link. After some googling, it turns out to be because Apple added a new feature named Bitcode for app optimization within App Store. While OpenCV iOS binary hasn't been updated to include Bitcode, it cannot pass the link stage.
Some reference pointed out a temporary solution to disable ENABLE_BITCODE so the linking could be done without Bitcode. This will prevent the app being compiled for Apple Watches because Bitcode is mandatory for Watch Apps. Therefore my question is, are there some (best easy) ways to compile iOS OpenCV with Bitcode enabled? (better with a download link for compiled framework)
After some search and trial, I figured out a way to compile OpenCV iOS from the source with Bitcode. A compiled binary is also provided here: [v3.0] [v2.4]. [Disclaimer: I am not responsible for the integrity of the compiled binary. Use at your own risk.]
The steps of compilation is basically the same as the official document, with only one extra step.
Download the code with git:
cd ~/<my_working_directory>
git clone https://github.com/Itseez/opencv.git
Make symbolic link for Xcode to let OpenCV build scripts find the compiler, header files etc.
cd /
sudo ln -s /Applications/Xcode.app/Contents/Developer Developer
[Key Step] Change the compilation script to add the extra option for Bitcode: edit ~/<my_working_directory>/opencv/platform/ios/build_framework.py, and locate the line containing -DCMAKE_C_FLAGS. Add a flag of -fembed-bitcode. For example, in the source I got, it's line 55, and will look like
"-DCMAKE_C_FLAGS=\"-Wno-implicit-function-declaration -fembed-bitcode\" " +
after the change. [ref]
Build OpenCV framework:
cd ~/<my_working_directory>
python opencv/platforms/ios/build_framework.py ios
If everything’s fine, a few minutes later you will get ~/<my_working_directory>/ios/opencv2.framework. You can add this framework to your Xcode projects.
P.S. Ask a question, even when you already know the answer is encouraged according to this post on Meta Stackchange.
OpenCV is precisely the kind of software (along with audio and video Codecs) that is likely to have hand-rolled ARM NEON optimisations. The documentation suggests that ~40 functions have had this treatment in OpenCV3.0.
If compiling for LLVM bit-code you'll get the generic (less optimised, implemented in C or C++) versions instead.
Use of Bitcode is optional - except when compiling for Apple watch, where it's hard to imagine you'd run computationally complex image processing anyway. If you're bundling a watch app, override the build setting for bitcode on it only.

Cocoa Touch Framework fails to debug on simulator in embedding project

I've got a Cocoa Touch framework built with XCode 6 targetted towards iOS >= iOS8.
This framework's target architecture settings are default, meaning that I haven't changed anything.
The architectures are set to standard (which doesn't include x86_64, more on that later).
The framework itself contains both Swift and Objective-C code, so building it using the static library workaround from Ray Wenderlich won't work.
Now, if I create a new project and add the framework project to it, the project builds for both the device and simulator, which is fine.
However, if I take the .framework file and add it to a different project just like you'd add any other framework, the project won't build for the simulator. Well, it does build, but it crashes because it can't find the relevant classes. It works fine on the device and archiving works just as expected as well.
The framework project itself already gives me a warning;
"Apple Mach-O Linker Warning - Directory not found for option ....(Debug-ophoneos)".
Any help would be highly appreciated!
I have finally found the solution to this issue.
As it turns out, XCode no longer creates fat binaries out of the box. No idea what Apple's reasoning behind this might be, too me it just seems like sometimes the guys responsible for XCode like to make fun of the developers using their product...
Anyways, you can find the definitive guide as to how to create a fat binary for simulator and all iOS devices (yes, you even have to lipo different architectures in order to get a framework that works on newer and older devices): https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/
In short;
Create a Cocoa Touch Framework
Set the Architectures to arm64, armv7, and armv7s
Set "Build Active Architecture" to "NO"
Set "Valid Architectures" to arm64, armv1, and armv7s
Add the following script to the framework's build Scheme as an Archive Post-action;
set -e
DEVICE_BIN="${OBJROOT}/UninstalledProducts/${TARGET_NAME}.framework"
SIMULATOR_BIN="${SYMROOT}/../../../../Products/Debug- iphonesimulator/${TARGET_NAME}.framework"
ARCHIVE_PATH="${SRCROOT}/_Archive"
rm -rf "${ARCHIVE_PATH}"
mkdir "${ARCHIVE_PATH}"
if [ "${CONFIGURATION}" = "Release" ]; then
if [ -d "${DEVICE_BIN}" ]; then
DEVICE_PATH="${ARCHIVE_PATH}/Release"
mkdir "${DEVICE_PATH}"
cp -r "${DEVICE_BIN}" "${DEVICE_PATH}"
fi
if [ -d "${SIMULATOR_BIN}" ]; then
SIMULATOR_PATH="${ARCHIVE_PATH}/Debug"
mkdir "${SIMULATOR_PATH}"
cp -r "${DEVICE_BIN}" "${SIMULATOR_PATH}"
lipo -create "${DEVICE_BIN}/${TARGET_NAME}" "${SIMULATOR_BIN}/${TARGET_NAME}" -output "${SIMULATOR_PATH}/${TARGET_NAME}.framework/${TARGET_NAME}"
fi
fi
exit 0;
This will create an _Archive directory in your project's directory where you can find the frameworks for both debug and release.
Important: As of today (May 22nd 2015) you'll have to build the project with the simulator first, and then archive with a device. Otherwise you won't get a universal binary!
This post has been created in order to avoid dead link errors, for updates regarding the packaging process, please ALWAYS try the steps posted on the kodmunki website I've linked above first as the steps in this post might have been outdated already!

Resources