14

I've created a framework in which is inserted the second framework, the so-called "umbrella framework". When I insert the framework in the test application(embedded binaries and linked frameworks and libraries, both) can not build app, I get the following error:

ld: framework not found 'embeddedInMyFramework' for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

Than add that framework(embeddedInMyFramework) also in embedded binaries and linked frameworks and libraries and try to build than works ok. Later remove that framework from both, embedded binaries and linked frameworks and libraries and still works fine. Can someone help me with this, not sure what happens when I add framework to embedded binaries for the first time, and how to fix that (could it work somehow without adding to embedded binaries at all)

Vladimir Zivanov
  • 381
  • 1
  • 2
  • 10

3 Answers3

23

I was able to set up a working Umbrella Framework and wrote down my approach.

Step 5 should remove your linker error ld: framework not found ..


Setup:

  • A Swift based "client" project that has the Umbrella Framework as dependency

  • A dynamic Framework (mainly C++ and ObjC) that is a dependency of the Umbrella Framework


Steps:

  1. Link the Umbrella Framework with its dependent (sub-)Framework and make sure that it is copied into the product upon building.

Setting of Project -> Build Phases


2. Add the location of the dependent (sub-)framework to the Framework Search Paths of the Umbrella Framework project.

Setting of Project -> Build Settings


3. In the "client" project make sure to link and embed the Umbrella Framework

General Setting Client


4. Make sure the Umbrella Framework is copied into the (client-) app bundle to avoid dyld: Library not loaded: @rpath/... errors. The (client-) app, usually under ...Build/Products/Debug-iphoneos/YOUR_CLIENT_APP.app should now contain your Umbrella Framework in a folder called Frameworks.

Project Setting Embed Framework


5. In the "client" project Make sure to add the path to the Umbrella Framework to Framework Search Paths.
If the ld: framework not found '[Framework_Name]' for architecture ... error persists you can also add the path to the (sub-) Framework here.

Project setting framework search path

DeltaCap019
  • 6,532
  • 3
  • 48
  • 70
ehrpaulhardt
  • 1,607
  • 12
  • 19
  • Client project step #1 sub framework path is required. This is tricky because on your own machine, framework search paths embedded in the binary will be searching for a hard coded directory specified in Umbrella Framework step #2. If you create a sample client project on your own machine, temporarily remove the sub framework from the location in step #2 and you'll get the 'framework not found' error. – Vinnie Jan 25 '17 at 10:13
  • 6
    This approach has no difference from sending 2 frameworks separately, the sub framework is still exposed and user need to point the search path manually – vk.edward.li Feb 04 '18 at 08:03
4

HERE IS AN DEMO PROJECT:

Umbrella Framework Demo

All answers under this line are wrong, cause they just do the thing that manually copy sub frameworks into "umbrella framework"

Embedding a framework within a framework (iOS 8+)

How to create an umbrella framework in iOS SDK?

How to add a framework inside another framework (Umbrella Framework)

Umbrella framework

First thing we should know that "umbrella framework" is a conception in Mac OS not in iOS, the official document is here

https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/CreationGuidelines.html#//apple_ref/doc/uid/20002254-BAJHGGGA

if you want to create an un-recommend "UmbrellaFramework", you must do these process step by step, and know details during the compile and link periods

  1. Change all sub frameworks Mach-O to Static Library, it means compile this target as Static Library(.a)
  2. Manually copy all sub-Framework into UmbrellaFramework during the build phase(Like other answers did)
  3. Add "FakeBundleShellScript" to Target "UmbrellaFramework", it makes all sub frameworks package itself resources as bundle to join "UmbrellaFramework"
  4. Change the framework load function, you must load the sub-framework resources via path or url, cause it became an bundle, this step means you should have the supreme control of all codes both sub-frameworks & umbrella

!!Here is an example of "FakeBundleShellScript" you can refer

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
BUNDLE_IN_ROOT="$APP_PATH/${FRAMEWORK_EXECUTABLE_NAME}.bundle"
if [[ -e "$FRAMEWORK_EXECUTABLE_PATH" ]]; then
  FRAMEWORK_MACH_O="$(otool -a "$FRAMEWORK_EXECUTABLE_PATH" | head -n 1)"
  FRAMEWORK_FAT_ARCH="$(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")"
else
  FRAMEWORK_MACH_O="NO EXIST"
  FRAMEWORK_FAT_ARCH="NO EXIST"
fi
echo "FRAMEWORK_EXECUTABLE_NAME is $FRAMEWORK_EXECUTABLE_NAME"
echo "FRAMEWORK_EXECUTABLE_PATH is $FRAMEWORK_EXECUTABLE_PATH"
echo "FRAMEWORK_MACH_O is $FRAMEWORK_MACH_O"
echo "FRAMEWORK_FAT_ARCH is $FRAMEWORK_FAT_ARCH"
echo "BUNDLE_IN_ROOT is $BUNDLE_IN_ROOT"
if [[ "$FRAMEWORK_MACH_O" =~ "Archive :" ]]; then
  echo "Rmove Static-Mach-O is $FRAMEWORK_EXECUTABLE_PATH"
  rm "$FRAMEWORK_EXECUTABLE_PATH"
  defaults write "$FRAMEWORK/Info.plist" CFBundlePackageType "BNDL"
  defaults delete "$FRAMEWORK/Info.plist" CFBundleExecutable
  if [[ -d "$BUNDLE_IN_ROOT" ]]; then
    rm -rf "$BUNDLE_IN_ROOT"
  fi
  mv -f "$FRAMEWORK" "$BUNDLE_IN_ROOT"
elif [[ "$FRAMEWORK_FAT_ARCH" =~ "Architectures in the fat file" ]]; then
  #statements
  EXTRACTED_ARCHS=()
  for ARCH in $ARCHS
  do
    echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
    lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
    EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
  done
  echo "Merging extracted architectures: ${ARCHS}"
  lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
  rm "${EXTRACTED_ARCHS[@]}"
  echo "Replacing original executable with thinned version"
  rm "$FRAMEWORK_EXECUTABLE_PATH"
  mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
fi
done

http://alanli7991.github.io/2017/07/17/%E6%A8%A1%E5%9D%97%E5%8C%9617Framework%E4%B8%8EStaticFramework%E4%BC%AA%E8%A3%85Bundle/

As all I said, the key point of to make an un-recommend "UmbrellaFramework" is !!!! [Compile the sub-frameworks as Static, process the resources via fake a bundle], REMEMBER!! Apple always said DONT'T CREATE AN UmbrellaFramework

if you can understand Chinese, more details to make an "UmbrellaFramework" can be obtained from my blog

Alan.li 2017年的文章

MinamiTouma
  • 409
  • 3
  • 10
  • 1
    How do you change sub frameworks's Mach-O to static library? My sub-frameworks are opencv2.framework and firebasecore.framework – Rurouni Jun 24 '19 at 05:56
  • @MinamiTouma will that work for Swift static libs? Thanks – Paul Nadolinskyi Dec 23 '19 at 00:35
  • @MinamiTouma could you pls share sample with swift frameworks? BTW if I embed Umbrella framework to 3rd party app, it doesn't see UmbrellaObj and its properties, what I am missing? thanks – Paul Nadolinskyi Dec 24 '19 at 12:01
2

Adding to embedded libraries also sets certain Build Settings, which are not removed when removing the library from embedded libraries.

Most probably the Framework Search Paths contain the path to the previously missing library.

It will not work without somehow adding the embedded library. You might want to use some dependency management tool (like CocoaPods or Carthage) to do the more or less of the work for you.

shallowThought
  • 19,212
  • 9
  • 65
  • 112
  • I don't want to use any dependency management tool. Can i somehow automatic include that missing library? – Vladimir Zivanov Dec 30 '16 at 20:52
  • I found this answer but i don't know how to use this script http://stackoverflow.com/questions/27868259/embedding-a-framework-within-a-framework-ios-8 – Vladimir Zivanov Dec 30 '16 at 20:57
  • Afaics the script does _create_the framework, not use it as a client. – shallowThought Dec 30 '16 at 21:05
  • I need to find a way to do that. Thank you anyway. – Vladimir Zivanov Dec 30 '16 at 21:09
  • You can certainly write a script that does this for you. But I do not see the advantage. Maybe describe your use case more detailed (update question) to understand the need. – shallowThought Dec 30 '16 at 21:12
  • I need to create framework which contains another framework, and i want to include just "umbrella framework" in app, i don't want that app developer know anything about embed framework. – Vladimir Zivanov Dec 30 '16 at 21:19
  • An umbrella framework is technically nothing but a directory containing your sub-frameworks, so so every 3rd party developer using your framework will know about them anyway. The question is only about how your frameworks are supposed to integrated. – shallowThought Jan 02 '17 at 14:03