How do I use a new framework I have built? - objective-c

I have had some issues with the AWS IOS SDK framekit, since it was not built to work with OSX apps. I found a modified version of the SDK that Brad Larson created.
The directory structure looks something like:
AWSiOSSDK.framework/
src/
--Amazon.Runtime/
--Amazon.S3/
..
--AWSCocoa/
----AWSCocoa_Prefix.pch
----AWSCocoa.xcodeproj
----etc
--include/
So if I go into the xcode project, and build AWSCocoa it compiles. But when I look at the timestamp on the AWSiOSSDK.framework, it hasn't changed. So I don't know what compiling this AWSCocoa gets me, or where I can find the files it creates. So assuming that building AWSCocoa.xcodeproj is supposed to build a new version of the framework compatible with OSX development, where do I find and link what I've built?

The AWSiOSSDK.framework bundle is a precompiled framework, probably left over from my earlier experiments in making a Mac version of this (since you can't use frameworks like this with iOS, only static libraries). Ignore that.
If you are using Xcode 4, your built framework will be created somewhere in your ~/Library/Developer/Xcode/DerivedData/ directory. To find where it lies, go to your project navigator in Xcode 4, expand the Products group, right click on AWSCocoa.framework, and select Show in Finder. This is no different from any other third-party framework you would compile.
Nominally, you'll want to add this framework as a target dependency in your application so that it is built alongside that. You'll also have to make sure that the framework is copied into the appropriate location within your application bundle so that it can be used by your application at runtime.

Related

Is there any DSYM file for .framework (besides app)?

I am a new guy in OC programming. Now I am involved in a framework development project.
I know the framework works as a library, which contains a group of methods. It's not an application that can run on devices.
Actually, our framework will work with customer's application. We want to investigate what happened inside our framework when customer's application crashed. So I want the 'DSYM' file of our framework, instead of an application.
As far as I know any iOS application does have corresponded 'DSYM', but I didn't find the 'DSYM' of our framework.
Does iOS framework project have 'DSYM'? If it does have, how can I obtain it?
By the way, I am using Xcode 8.1.
Thanks!
According to my observations, .dSYM files are generated for iOS dynamic framework built with Release configuration only.
After build succeeds, the debug symbols files can be found at these paths, for a device and simulator, respectively:
<Build_Root>/build/Release-iphoneos/<Product_Name>.framework.dSYM
<Build_Root>/build/Release-iphonesimulator/<Product_Name>.framework.dSYM
, where
<Build_Root> is usually a subdirectory within Derived Data directory;
<Product_Name>is the name of your framework.
Yes, you can generate dSYMs for dynamic frameworks. There are a few relevant build settings that control whether and where these files are generated:
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym,
DWARF_DSYM_FOLDER_PATH = "$(CONFIGURATION_BUILD_DIR)",
DWARF_DSYM_FILE_NAME = "$(PRODUCT_NAME).dSYM"
Obviously, you can set these to whatever you want, either in your project's build settings in Xcode (the project.pbxproj file) or as arguments to xcodebuild (depending on how you generate your framework).
DSYM (Debugging SYMbols) files generally store the debugging symbols for your app. And if app crash any where symbols replaced with appropriate method name so that it could help developer in a readable form. And for that you can use the crash log and they can be find in the iPhone where the app is installed. Each app and device have their own crash log.
Also please check this link it might help you.
Read Crash Report
Upload Symbols for iOS Framework
Hopefully these might help you or guide in the right direction.

How do you conditionally include a framework in an Xcode project?

Is it possible to have a single Xcode project (and ideally a single target) that will conditionally include frameworks when built against a certain version of OS X / Xcode but not include those frameworks when built against another version?
I'd like to begin adding support for El Capitan to an application I'm working on but some of the support I have in mind requires linking against frameworks that are not present in Yosemite. Is there a way to configure an Xcode project so that the same project can be built under 10.11 / Xcode 7 with the frameworks but also built under 10.10 / Xcode 6 without the frameworks (and without throwing an error)?
I'm aware of how to check for the existence of a class or method at runtime, but it's not clear to me how I control the framework linking without creating a second Xcode project, a second source control branch or always building against Xcode 7 (none of which I want to do, yet).
The "other version" would essentially be another target — it's setup this way to do precisely what you're asking about. A basic example would be just a matter of right-clicking on your original target and selecting duplicate from the current targets; then make whatever changes to linking frameworks within the Build Phases section.
Targets
In Build Phases you'll notice I've linked three frameworks to my
original target:
After right-clicking on the original target and creating a duplicate
I'm able to link it differently:
The duplicate version of MyApp uses the same classes and headers as the original with the exception of those that require the excluded frameworks. It's also possible to import different frameworks, change things such as the Deployment Target (e.g. build for different versions of OS X), or perhaps which SDK each might use, etc.
Once you're more familiar with the standard build process you can then create custom build scripts to handle specialized tasks like keeping the target names the same or even creating installer packages — anything is possible.

Xcode: How to have shared code (i.e. framework) between main project and plugin bundle

In my project I had two targets, 1) The main application which loads 2) a bundle of plugins. I have started to have objects which need to be available in both targets, so naively tried to compile them separately in each target (producing warnings about having different implementations: Class X is implemented in both Y and Z. One of the two will be used. Which one is undefined.)
To solve this I decided to create a framework, so I added a framework, but I don't know how to make it so that a) both the main app and bundle access the framework (via the compiled framework, and not just through the headers in the project), and so the framework is compiled when I run the project.
If you know how to do this, thanks!
Here are the steps I followed:
Create a new framework in the project , copy all the shared code over.
In the main header of the framework, include the headers of all the shared code.
Build the framework to test it builds (e.g. select the scheme of the framework and click play)
Go to the Build Phases of both the Application and the Plugin Bundle and add the framework to ‘target dependencies’ and ‘Link binary with libraries’
To include the frameworks stuff in code in the app and bundle, just use the main header, and use <> rather than “" e.g if your framework was called Foo use #import
When it comes to deploying, there might have to be some fiddling with where the framework gets installed, currently it gets put alongside the app itself, rather than inside, but I will probably fix that later :)

Xcode: how to build a static library project correctly?

This question will be easy for Xcode pros but for a MonoTouch developer it seems to be impossible to resolve. :-)
I'm using Xcode 4.5 and I want to target iOS 5.1 and above and iOS Simulator 5.1 and above.
I have a a library project here and it is coming with a prebuilt binary named "DemoLib" (no extension and it is 11MB in size). The library is a fat lib for Simulator and iOS 5.1+.
I can use that library without any problem.
However if I try to build the library myself, I end up with a "DemoLib.a" file (notice the extension and the size of 30MB). How can I get the same build result? What is a .a file compared to the file without extension?
I tried to build the project "for running", and "for archiving" in Xcode. Both results in the same 30MB .a file.
I was expecting some dropdown in Xcode where one could select "DEBUG" or "RELEASE" build and the latter one would create the smaller lib.
Of course I could never tell without seeing the framework's project file. Having said that, there is an excellent guide to creating and compiling iOS frameworks here: https://github.com/jverkoey/iOS-Framework
Using the above guide, you should be able to recreate your framework's project from scratch, add the files you have to it, and properly compile it.
Hope this helps! :)
Did it come with a Makefile? Create a new target, set the build settings of the target to what's in the Makefile, then set your project to depend on that new target.
A file with the .a is a static library, which means it depends on nothing external and all the code it needs is compiled inside it. I think no extension generally implies dynamic library, which means it'll depend on some dependencies being present on your system to link against. Maybe that's why the .a is so much bigger. I think Xcode will build static by default because iOS does not allow the use of dynamic libraries.
The dropdown for what to build is in your scheme. Command+shift+< to view your scheme. Within the scheme you can edit which environment each method of building will use.

XCode 4.4.1 ignores LD_RUNPATH_SEARCH_PATHS

I am dealing with a weird behavior of XCode:
dyld: Library not loaded: /Library/Frameworks/SBJson.framework/Versions/A/SBJson
Basically it ignores my Runpath Search Path (LD_RUNPATH_SEARCH_PATHS) configuration that is actually #loader_path/../Frameworks.
I am not able to load any embedded framework in this moment :/
otool says
otool -L /Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r
/Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r:
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
/Library/Frameworks/SBJson.framework/Versions/A/SBJson (compatibility version 1.0.0, current version 37.0.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.0.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1186.0.0)
P.S. If you're wondering if I added the copy to framework build phase, the answer is yes.
The short version
The problem is that when you built SBJSON.framework, the install name wasn't configured to use #rpath. As a result, when your app goes to load the dynamic library, it's looking in /Library/Frameworks instead of where your app's runpath tells it to look.
To fix it, you need to change a build setting on the SBJSON.framework target. Change the the Dynamic Library Install Name setting to #rpath/${EXECUTABLE_PATH}. Then just build again, linking against the newly-built framework, and you're good to go.
The long version
Frameworks are, at the core, just dynamic libraries. This means that the code contained in the library is not embedded into your app, but rather pulled in from the SBJSON.framework bundle at runtime. In order to do this, your app needs to know where to look for the dynamic library.
The way this works is that when you link against a framework, the linker doesn't actually embed the whole library into your app. Instead, it just adds a small section that tells the app where to find the library when it runs. Of course, that means that the compiler has to know where the library will be at runtime. It finds that information by looking at the "Install Name" of the dynamic library.
A dynamic library's "Install Name" is essentially just the path where the library is expected to be. Historically, most dynamic libraries and frameworks have been shared system-wide. Things like Foundation.framework and CoreData.framework, for example, live in /System/Library/Frameworks, and all apps can reasonably expect to find them there. Thus, when CoreData.framework is built, its install name is set to /System/Library/Frameworks/.... When Xcode links your app against Core Data, it looks at the framework's install name and tells it to load in the framework at that path when the app is launched.
That's all fine and well, but it doesn't help you when you need to embed a framework inside your app. You don't know where the app will be located on the system at runtime. The user may run it from /Applications, but they might also run it from ~/Downloads. There's no single path you could provide as the install name that would always correctly point to the framework at runtime.
To deal with this, you can set the framework's install name to #loader_path/../Frameworks. When the dynamic loader sees #loader_path, it replaces it with the path of the currently-loading app. Using this install name would allow the framework to be installed inside the Frameworks folder of any app.
However, things still aren't perfect. The framework is still dictating where it should be placed. If another app wanted to place the framework inside a Libraries folder instead, for example, it's out of luck. The framework is in charge of where it can be placed, instead of the app. This is an inversion of the dependency tree, and is not ideal. The app should be able to load the framework from wherever it wants to stash it, regardless of what other frameworks do.
Thus, in OS X 10.5, #rpath was introduced. If the install name of a dylib or framework begins with #rpath, then the loader will turn around and ask the app what it's "Runpath search paths" are, and substitute those in. This allows the app to specify where its frameworks will live. By using #rpath, the framework delegates the decision back to the app. The app can use #loader_path if it wants, or can specify an absolute path if it wants. It could even specify a shared folder that a whole suite of apps will use.
Your problem
So, on to your problem. You're correctly setting the app's runpath search path to #loader_path/../Frameworks. However, the framework's install name isn't using #rpath; in fact, it's still using a hard-coded path to /Library/Frameworks/.... Since the framework's install name doesn't use #rpath, the app's runpaths aren't even consulted. It's simply trying to link in SBJSON from the /Library folder. Since it's not there, your app crashes before it even launches.
You need to change the install name of the SBJSON framework to use #rpath. Set the Dynamic Library Install Name setting to #rpath/${EXECUTABLE_PATH}. (${EXECUTABLE_PATH} is the relative path to the internal dynamic library, from the folder containing the framework.)
Once you've built the framework with the new install name, you should be able to link against the new framework, make sure it's copied into the app bundle's Frameworks/ folder, and you're good to go!
P.S. If this isn't all clear, Mike Ash did a pretty nice review of #rpath and friends. You can find it here.