When should we use "embedded binaries" rather than "Linked Frameworks" in Xcode?
Asked Answered
L

3

151

There is a good question about the difference between those two options as described in Link Binary with libraries VS Embed Frameworks.

Seems like we have options to use them both, just wonder which case we should use embedded binaries better, or rather than linked framework ?

Any solid examples to address this more clear? Thanks

Loony answered 20/9, 2015 at 2:51 Comment(1)
Possible duplicate of Link Binary with libraries VS Embed FrameworksPatchwork
M
262

The question you linked references the "Link Binary With Libraries" functionality, which is somewhat different than an embedded binary.

"Link Binary With Libraries" means what you'd expect it to with respect to linkage: Regardless of whether the binary is a static library, dynamic library, or framework it will be linked to your object code at link time after compilation.

When you think of linkage with a static library, what happens is pretty clear: the linker copies the code from the library (e.g. libFoo.a) into your output binary. Your output file grows in size but doesn't need to resolve any external dependencies at runtime. Everything your program needs to run (with respect to the static library) is present after it is built.

With a dynamic library (.dylib, or system-supplied framework), the expectation is that the library you are linking against will be present somewhere in the system's dynamic-library loader path when you run your program. This way you don't have the overhead of copying all the third party external libraries into your binary, and all the different programs on a computer that also link to that library will be able to find it, which saves minimally disk space, but also potentially memory space, depending on how and where the system caches libraries.

A framework is much like a dynamic library, but can contain resources in its directory structure (images, audio, other frameworks, etc.). In this case a simple static-library or .dylib file won't cut it so you might have to link to a framework just so it can find what it needs to run properly.

When you link to a third-party framework (say something you downloaded from github and built yourself), it might not be present on the system you intend to run on. In this case, you'd not only link to the framework, but embed it inside your application bundle as well using the "Copy Frameworks" phase. When your program runs, the runtime-linker (aka the resolver) will look inside your bundle in addition to the system loader path, find the embedded framework, and link it so your app will have the code it needs in order to run.

Finally, what is properly an "embedded binary" is an executable you both embed in your application bundle via a Copy-Files Phase, and that you execute yourself, perhaps with a call to popen() or similar. The embedded binary may be called by your program, but it isn't linked with it. It is a fully external entity (like programs in the /bin directory).

In practice, for system-supplied libraries and frameworks you will link against them and that's all you need to do.

If you need to link a library you built that doesn't need any embedded resources (i.e. doesn't require a framework to exist), then you can just link against a static library. If you find you have multiple modules in your program that want to use the same library code, then converting it to a framework or dynamic library and linking against that can save space and may be convenient (particularly if memory usage is a concern).

Finally, frameworks can include not only resources, but header and/or license files. Using a framework to convey these files is actually a convenient distribution mechanism so often you may want to incorporate a framework just so these things can tag along with your binary (i.e. license requirements may make this mandatory).

--- EDIT ---

Adam Johns posted the following question as a comment:

This is a great answer. There is something I'm still a little confused on, however. What does it mean to execute the binary yourself? Do you mean simply using the embedded framework's code? I know you mentioned popen(), but you're saying my app is calling popen()? I don't really know what that means.

I'm saying an embedded binary is just another resource file in your bundle, like an audio file or image, although the file is instead an executable command-line tool. The popen() function (man popen from your terminal to read more about it) lets you execute arbitrary programs from another running program. The system() function is another way. There are others, and I'll give a historical example here that may make understanding use of an embedded binary a bit more clear:

As you're probably aware, when you launch an app on Mac OS X it is launched with a user id of the current user. Under most common installations that's the default user-at-the-Desktop admin user, who is given user id 501.

On Unix-based operating systems only the root user (user id 0) has full access to the entire filesystem. Sometimes it happens that an installer program launched by the Desktop user needs to install files in a privileged directory (drivers for example). In this case, the application program needs to escalate its privileges to the root user so it can write in these restricted directories.

To facilitate this in operating systems through OS X 10.7, Apple provided in its Authorization Services API the function AuthorizationExecuteWithPrivileges() (this is now deprecated, but is still a useful example).

AuthorizationExecuteWithPrivileges() took as an argument a path to a command-line tool to execute as root. The command line tool was an executable shell script or compiled binary that you wrote to run your install logic. This tool was installed inside your application bundle just like any other resource file.

When called, the OS put up an authorization dialog asking for the user's password (you've seen this before!) and when entered would execute the program as root on your app's behalf. This process is similar to just executing a program with popen() yourself, although popen() alone doesn't give you the benefit of privilege escalation.

Mapes answered 20/9, 2015 at 3:10 Comment(15)
How do you know these things?Beata
@IanWarburton I've been programming Apple operating systems for 20+ years and have picked up a few tidbits here and there. :)Mapes
You said: A framework is much like a dynamic library, but can contain resources in its directory structure ... so you might have to link to a framework just so it can find what it needs to run properly. - didn't you mean embed instead of link? And is this embedding the same thing which can be found in "Embedded binaries" on XCode 8 and is it essentially the same as Copy Files build phase in older XCode versions?Riparian
@Riparian I mean link, but you are correct that you have to also embed it via a copy-files phase (otherwise how would you use it?). The goal of using either a third party framework or an embedded binary is to execute the code that entity provides. With an embedded binary no linking is involved. At runtime you construct a path to the binary then manually execute it. With a framework the compile-time linker will link it when you build your app, then (if it's a 3rd-party framework) you embed it via a copy-files phase, and finally the runtime linker links it again when you run your app.Mapes
The things are bit unclear as to what you answered to @JustAMartin. The goal of using either a third party framework or an embedded binary is to execute the code that entity provides. Nowadays Embedded binaries can also be third party framework. I am trying to understand what you mean here... AFA I understood, embedded binaries means, separate binary of the framework embedded will be introduced into the App bundle, And If you just link the same framework it would put that into same binary as that of app. Please correct me If I am wrong...Donal
@Donal Newer Xcode versions (at least 8+, possibly earlier) now refer to 3rd party frameworks as embedded binaries on a target's General settings tab. This has muddied the water a bit because 3rd party frameworks are more precisely embedded frameworks. This is why the Build Phases tab still has an "Embed Frameworks" phase separate from the "Copy Bundle Resources" phase where traditional embedded binaries are added. This is an old answer... It still provides a relevant overview but I suspect it will become more out of date as Apple continues to update and change Xcode.Mapes
For future commenters: please open a new question if you'd like to continue the discussion.Mapes
Great answer of course, but why doesn't anyone ever mention that dynamic libs (.dylib) are not supported on iOS unless they are wrapped in a framework or unless they are Swift dylib files? developer.apple.com/library/content/technotes/tn2435/…. In this doc it says: Dynamic libraries outside of a framework bundle, which typically have the file extension .dylib, are not supported on iOS, watchOS, or tvOS, except for the system Swift libraries provided by Xcode. Nobody ever mentions this :(Quad
@Mapes I made a new question related to this here. If you have a moment, you might be able to help out with your knowledge on the subject.Lepp
How can you specify a framework in "embedded binaries" but NOT in "linked frameworks and binaries" and still use it? I have a vendor-provided demo project that does just this.Ellanellard
@Ellanellard Use the NSBundle API to manually load the embedded framework.Mapes
Thanks! But I wasn't asking because I want to do that; I'm asking because I have a project that compiles and runs, but doesn't specify the library in "linked frameworks and binaries." It only lists it as embedded. And I don't think it manually loads the framework either.Ellanellard
Maybe there's new Xcode magic that will load an embedded framework. It's been a while since I've needed that functionality. If you want to explore what's going on more please post a new question here on SO.Mapes
@Ellanellard maybe it compiles because the "Link Frameworks Automatically" build setting is set to "Yes" (which is the default). "This setting allows the compiler to automatically link to the frameworks corresponding to any modules you import without having to explicitly link them in your link library's build phase." - WWDC 2018 Video: Behind the Scenes of the Xcode Build Process However, this auto-link feature doesn't establish an implicit target dependency at the build-system level. So, explicitly linking embedded frameworks is suggested.Johnathan
Is there any difference in the final executable (app) file size, when I choose "embeded binaries" or not?Castellany
R
38

In short,

  • system libraries, link them;
  • 3rd party libraries, embed them.

why?

  • if you try to embed system libraries, you won't find them in the popup list;
  • if you link 3rd party libraries, you'll probably get a crash.
Rechaba answered 9/10, 2017 at 11:1 Comment(0)
S
12

Xcode pre-v11. Embedded Binaries vs Linked Frameworks and Libraries

History

Embedded Binaries vs Linked Frameworks and Libraries -> Frameworks, Libraries, and Embedded Content

[Xcode v11. Frameworks, Libraries, and Embedded Content] replaced it from Xcode v11 section in General tab

embedded binaries and Linked Frameworks are a part of Dependency management [About]

[Xcode v11]

Link Binary

General -> Linked Frameworks and Libraries is a mirror of Build Phases -> Link Binary With Libraries.

Static Library and Framework

If you add a Static Library or Static Framework to this section it will appear at Frameworks group[About](Project Navigator -> <workspace/project> -> Frameworks) and there will be a reference added to your project for it. Then it will be used by Static Linker. Static Linker at compile time will include/copy all code from the library into the executable object file. Static linker works in pair with Build Settings -> <Library/Framework> Search Paths

Static Library

Static Framework

  • Build Settings -> Framework Search Paths. If you do not add a static framework to this section you will get a compile error[No such module]

Embed binary

Static Library and Static Framework

Embedding wouldn’t make any sense for a Static Library and Static Framework because the symbols from them are compiled into the executable binary. Xcode won’t let you drop a static library under the Embed section.

Dynamic Framework

General -> Embedded Binaries is a mirror of Build Phases -> Embed Frameworks.

Embedding actually adds a copy of the framework into your application bundle(not merging framework's and application's code into single executable binary)

By default the bundle's folder is Frameworks but you can change it using Destination field. Moreover you can specify a Subpath.

Dynamic linker :dyld at load or run time will try to find the embedded framework using @rpath[About] If it is not found the error will occur [dyld: Library not loaded]

Result:

  • Static Library - Link
  • Static Framework - Link
  • Dynamic Framework - Embed

[Static vs Dynamic linker]
[When use Link and Embed]
[Vocabulary]

Slurry answered 6/12, 2019 at 16:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.