Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 332
Forrest Avatar asked Oct 09 '22 05:10

Forrest


People also ask

What is embedded binaries in Xcode?

3 Answers. Show activity on this post. Embedded binaries are binary files that are copied to your application bundle when you build the project. Use embedded binaries when your application relies on third-party frameworks so people can use your application without needing those frameworks installed on their machine.

What is embedded framework iOS?

A framework is a hierarchical directory that encapsulates a dynamic library, header files, and resources, such as storyboards, image files, and localized strings, into a single package. Apps using frameworks need to embed the framework in the app's bundle.

What does embed mean in Xcode?

1. 1. I guess "embed" means "copy into app bundle".

Where is linked frameworks and libraries in Xcode?

If you're building for iOS, tvOS, or watchOS: On your application targets' “General” settings tab, in the “Linked Frameworks and Libraries” section, drag and drop each framework you want to use from the Carthage/Build folder on disk.


1 Answers

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.

like image 258
par Avatar answered Oct 13 '22 22:10

par