12

After building a Cocoa Touch framework (Swift or Object-C) and adding it to another project as "Embedded Binaries" I get the following error message when I try to build

missing required architecture i386
...
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Following various existing answers and extended research I already added i386 to the Architectures build settings …

enter image description here

However this doesn't seem to have an effect. When I check using

lipo -info TesterFrameworkObjC

I only get

Architectures in the fat file: TesterFrameworkObjC are: armv7 arm64

… shouldn't i386 (and x86_64) appear here as well? What am I missing?

(I am using Xcode 6.2 + building for iOS 8.2)


Some new insights

Using a version of this build script I am able to build the missing architectures for the Swift version of the framework.

enter image description here

However when I add this framework to my app and build I still get errors

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$__TtC20TesterFrameworkSwift18TestFrameworkSwift", referenced from:
  objc-class-ref in ViewController.o
ld: symbol(s) not found for architecture x86_64

Looking at the final build folder building for the simulator

Build/Products/Debug-iphoneos/TesterFrameworkSwift.framework/

I can see that the architectures are still missing although they were part of the framework (as shown). How can I ensure all the right architecture builds of my framework are included when building the app?


Update

Looking at all the error messages to me it looks like the issue isn't actually to have the wrong products/archictures being built but one step later there the Linker isn't using the correct paths to them. Not sure how correct this.

Bernd
  • 11,133
  • 11
  • 65
  • 98
  • No, I only use Foundation. And I have only one function in it for testing. – Bernd Feb 22 '15 at 00:00
  • Did you build your framework using Simulator or iDevice. When you build with iDevice, it creates framework for device architecture: armv7, armv7s, arm64. When you build for simulator, XCode creates framework included i386 & x86_86 (simulator 64bits). You have to group these 2 libraries in to a universal library to get a full architecture library. – Duyen-Hoa Feb 22 '15 at 00:03
  • Take a look at this article, you will find the way to create universal framework: http://www.raywenderlich.com/41377/creating-a-static-library-in-ios-tutorial – Duyen-Hoa Feb 22 '15 at 00:05
  • @HoaParis I tried both building with a selected Simulator or the device. The built framework never contains i386/x86 … therefore I am not even at the point where I could create a universal binary. – Bernd Feb 22 '15 at 00:36
  • also I tried the article and the script you linked. It didn't work … not sure if it's because it is about Static frameworks which is not what I am building. – Bernd Feb 22 '15 at 00:37
  • In fact, framework is just a special folder that contains a static library. Try first to build your framework for Simulator then verify if the framework architecture is i386 & x86_64. Then, you can find another article about creating universal framework. For example: http://spin.atomicobject.com/2011/12/13/building-a-universal-framework-for-ios/ – Duyen-Hoa Feb 22 '15 at 00:50
  • In fact when I first "clean the build folder" (name.framework becomes red) building for the Simulator does not create the Product (name.framework stays red). Only building for the device creates the name.framework (not including the i386 and x86_64 versions). – Bernd Feb 22 '15 at 00:56
  • I used this link to make an universal framework: https://gist.github.com/cromandini/1a9c4aeab27ca84f5d79 – Javier Flores Font Feb 22 '15 at 22:39
  • Maybe you have a problem with building for simulator target. Take a look at XCode build log to verify that everything is ok. – Duyen-Hoa Feb 23 '15 at 09:27
  • @JavierFloresFont Thanks, that's a good one. Using the script I am able to build the missing architectures of the framework. However when I build the app I still get errors like "Undefined symbols for architecture x86_64:" – Looking at the "Build/Products/Debug-iphoneos/TesterFrameworkSwift.framework/" I can see that the x86_64 build architecture is not included in this final stage. – Bernd Feb 23 '15 at 11:06
  • This seems like a rather serious bug in XCode. I still have this problem with XCode 6.3 and just can't build a framework for both the simulator and devices. @Bernd, did you actually solve the issue somehow? – AlBirdie May 07 '15 at 07:59

4 Answers4

38

This is the same problem that I had.

Seems this is a Xcode bug, I workaround it by adding a build script. It will just compile your library with all architectures, and lipo it to fat binary image.

Also note

Looking at the final build folder building for the simulator

Build/Products/Debug-iphoneos/TesterFrameworkSwift.framework/

you are looking x86_64 and i386 images in iphone build folder, they should be in Debug-iphonesimulator/TesterFrameworkSwift.framework/

Also there is a recursion issue in your script, I've corrected it.

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: Detected, stopping"
else
export ALREADYINVOKED="true"

# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"

# Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"

# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"

# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"

# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

fi

6) Hit "cmd + B" (Build Project)

7) Open Product in Finder

enter image description here

8) Navigate 1 directory up ("cmd + ↑"), and you will see "Release-universal" directory. enter image description here

There will be your "fat/universal" library, You are ready to go!

You can check it via

file test.dylib 
test.dylib: Mach-O universal binary with 4 architectures
test.dylib (for architecture i386): Mach-O dynamically linked shared library i386
test.dylib (for architecture x86_64):   Mach-O 64-bit dynamically linked shared library x86_64
test.dylib (for architecture armv7):    Mach-O dynamically linked shared library arm
test.dylib (for architecture arm64):    Mach-O 64-bit dynamically linked shared library
Community
  • 1
  • 1
l0gg3r
  • 8,864
  • 3
  • 26
  • 46
1

I encounter the same problem and fortunately I solved it.

When you create a framework with Xcode and build it with the iPhone 5 simulator or the simulator before iPhone 5(such as iPhone 4s or iPhone 4),you will get a framework with i386 architecture.And if you build it with iPhone 5s simulator or the simulatro after iPhone 5s,you will get a framework with x86_64 architecture. But if you use the framework in your project and you want to run the app on a simulator,the framework must contain both i386 and x86_64 architecture,otherwise you will get a linker error. So you need to use lipo -create command to merge two framework,at this point your framework is ready for use.

DaiPei
  • 31
  • 2
1

Go to Build Settings -> Set Build Active Architecture Only to NO

Build your Framework in iPhone 5 and iPhone 6 or above Simulators.

Add the run script in post actions to generate the universal framework.

Go to terminal and type cd (path of your framework, or drag and drop your framework) which will take you to the frameworks directory

type file YOUR_FRAMEWORK_NAME which lists all the architectures your framework is supporting

you can see that your framework supports all four architectures i386, x86_64, armv7 arm64.

-3

Active Architecture => NO Valid Architecture => "armv7 armv7s arm64 i386 x86_64"

Use Above Build Setting when in are aggregating !!! I worked for me for all Architecture Framework creation