什么时候应该在Xcode中使用“嵌入式二进制文件”而不是“链接框架”?


140

关于这两个选项之间的区别,存在一个很好的问题,如使用库VS嵌入式框架的Link Binary中所述。

似乎我们可以选择同时使用它们,只是想知道在哪种情况下我们应该更好地使用嵌入式二进制文件,而不是使用链接框架?

有什么可靠的例子可以解决这个问题吗?谢谢


Answers:


239

您链接的问题引用了“使用库链接二进制文件”功能,该功能与嵌入式二进制文件有些不同。

“使用库链接二进制文件”是指您对链接的期望:无论二进制文件是静态库,动态库还是框架,在编译后的链接时,它将链接到您的目标代码。

当您想到与静态库的链接时,发生的事情很明显:链接器将代码从库(例如)复制libFoo.a到输出二进制文件中。输出文件的大小会增加,但是在运行时不需要解析任何外部依赖项。程序需要运行的所有内容(相对于静态库而言)在构建之后就已经存在。

对于动态库(.dylib或系统提供的框架),可以预期的是,当您运行程序时,要链接的库将出现在系统的动态库加载器路径中。这样,您就无需将所有第三方外部库都复制到二进制文件中,并且还可以找到链接到该库的计算机上的所有不同程序,从而节省了最小的磁盘空间,而且潜在的内存空间,具体取决于系统缓存库的方式和位置。

框架很像动态库,但是可以在其目录结构中包含资源(图像,音频,其他框架等)。在这种情况下,一个简单的静态库文件或.dylib文件将无法剪切,因此您可能不得不链接到框架,以便可以找到正常运行所需的内容。

当您链接到第三方框架(例如您从github下载并自行构建的东西)时,您打算在其上运行的系统上可能不存在该框架。在这种情况下,您不仅要链接到框架,还要使用“复制框架”阶段将其嵌入到应用程序包中。当您的程序运行时,运行时链接程序(又名解析器)将在系统加载程序路径之外的包中查找,找到嵌入式框架并进行链接,以便您的应用程序具有运行所需的代码。

最后,适当的“嵌入式二进制文件”是一个可执行文件,您既可以通过“复制文件”阶段将其嵌入到应用程序捆绑包中,又可以通过调用popen()或类似方法自行执行。嵌入式二进制文件可能由您的程序调用,但未与其链接。它是一个完全外部的实体(例如/bin目录中的程序)。

在实践中,对于系统提供的库和框架,您将链接它们,而这就是您要做的全部。

如果您需要链接构建的不需要任何嵌入式资源的库(即不需要框架存在),则只需链接静态库即可。如果发现程序中有多个模块要使用相同的库代码,则将其转换为框架或动态库并进行链接可以节省空间并且可能很方便(尤其是在考虑内存使用的情况下)。

最后,框架不仅可以包括资源,还可以包括头文件和/或许可证文件。使用框架来传达这些文件实际上是一种方便的分发机制,因此通常您可能希望合并一个框架,以便可以将这些内容与二进制文件一起标记(即,许可证要求可能会强制执行此操作)。

-编辑-

亚当·约翰斯(Adam Johns)发表了以下问题作为评论:

这是一个很好的答案。但是,我仍然有些困惑。自己执行二进制文件意味着什么?您的意思是仅使用嵌入式框架的代码吗?我知道您提到过popen(),但您是说我的应用正在调用popen()吗?我真的不知道那是什么意思。

我是说嵌入式二进制文件只是捆绑软件中的另一个资源文件,例如音频文件或图像,尽管该文件是可执行的命令行工具。该popen()功能(可man popen从终端上阅读以了解更多信息)使您可以从另一个正在运行的程序中执行任意程序。该system()功能是另一种方式。还有其他一些,这里我将给出一个历史示例,这可能会使对嵌入式二进制文件的使用更加清楚:

您可能已经知道,当您在Mac OS X上启动应用程序时,该应用程序将以当前用户的用户ID启动。在大多数常见安装中,默认的台式机admin用户是用户,用户名为501

在基于Unix的操作系统上,只有root用户(user id 0)具有对整个文件系统的完全访问权限。有时会发生由桌面用户启动的安装程序需要在特权目录(例如驱动程序)中安装文件的情况。在这种情况下,应用程序需要将其特权提升给root用户,以便它可以在这些受限制的目录中写入。

为了通过OS X 10.7在操作系统中简化此操作,Apple在其Authorization Services API中提供了功能AuthorizationExecuteWithPrivileges()(现已弃用,但仍是一个有用的示例)。

AuthorizationExecuteWithPrivileges()将以as身份执行的命令行工具的路径作为参数root。命令行工具是您编写的用于运行安装逻辑的可执行Shell脚本或编译的二进制文件。就像任何其他资源文件一样,此工具已安装在应用程序捆绑包中。

调用时,操作系统会显示一个授权对话框,询问用户密码(您之前已经看到过!),输入后将root代表您的应用程序执行该程序。此过程类似于仅popen()自己执行一个程序,尽管popen()单独执行并不能给您带来特权升级的好处。


62
你怎么知道这些事?
伊恩·沃伯顿

56
@IanWarburton我已经对Apple操作系统进行了20多年的编程,并且在这里和那里都收获了一些窍门。:)
标准杆

1
@JustAMartin我的意思是link,但您是正确的,您还必须通过复制文件阶段将其嵌入(否则您将如何使用它?)。使用第三方框架或嵌入式二进制文件的目的是执行实体提供的代码。对于嵌入式二进制文件,不涉及链接。在运行时,您可以构建二进制文件的路径,然后手动执行它。使用框架时,编译时链接程序将在构建应用程序时将其链接,然后(如果它是第三方框架)则通过复制文件阶段将其嵌入,最后,运行时链接程序将在运行应用程序时再次链接它。
票面

1
关于您对@JustAMartin的回答,事情还不清楚。使用第三方框架或嵌入式二进制文件的目的是执行实体提供的代码。如今,嵌入式二进制文件也可以是第三方框架。我想了解您的意思... AFA,我理解嵌入式二进制文件的意思是,嵌入式框架的单独二进制文件将被引入App捆绑包中,如果您链​​接相同的框架,它将被放入与应用程序的。请纠正我,如果我错了……
hariszaman

1
也许有新的Xcode魔术可以加载嵌入式框架。自从我需要该功能已经有一段时间了。如果您想了解发生了什么,请在此处发布一个新问题。

35

简而言之,

  • 系统库,将它们链接;
  • 第三方库,将其嵌入。

为什么?

  • 如果尝试嵌入系统库,则不会在弹出列表中找到它们。
  • 如果您链接第三方库,则可能会崩溃。

6

它是Dependency管理的一部分[关于]

请注意,标签Xcode 11中仅包含Frameworks, Libraries, and Embedded Content部分General

链接二进制

Build Phases -> Link Binary With Libraries是的一面镜子General -> Linked Frameworks and Libraries

静态库和框架

如果添加Static Library or Static Framework到本节将出现在Frameworks [关于]Project Navigator -> <workspace/project> -> Frameworks),而且将被添加到您的项目为它的参考。然后它将由Static LinkerStatic Linker在编译时,会将所有代码从库中包含/复制到可执行目标文件中。Static linker与...配对Build Settings -> <Library/Framework> Search Paths

Static Library

Static Framework

  • Build Settings -> Framework Search Paths。如果您未static framework在此部分添加,则会出现编译错误[无此类模块]

嵌入二进制

静态库和静态框架

嵌入对a毫无意义Static LibraryStatic Framework因为它们中的符号已编译为可执行二进制文件。Xcode不允许您static library在“嵌入”部分下放置一个。

动态框架

Build Phases -> Embed Frameworks是的一面镜子General -> Embedded Binaries。嵌入实际上会将框架的副本添加到您的应用程序包中。因此,将框架添加/删除到该Embed部分时,它将自动添加/删除到该Linked部分。默认情况下,捆绑软件的文件夹为,Frameworks但您可以使用Destination字段进行更改。此外,您可以指定一个Subpath

Dynamic linker :dyld加载或运行时将尝试使用[关于]查找嵌入式框架。如果未找到,则会发生错误[dyld:未加载库]@rpath

[使用链接和嵌入时]

[词汇]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.