如Link Binary with libraries VS Embed Frameworks中所述,关于这两个选项之间的区别有一个很好的问题。
似乎我们可以选择同时使用它们,只是想知道在哪种情况下我们应该更好地使用嵌入式二进制文件,还是使用链接框架?
有什么可靠的例子可以更清楚地解决这个问题吗?谢谢
如Link Binary with libraries VS Embed Frameworks中所述,关于这两个选项之间的区别有一个很好的问题。
似乎我们可以选择同时使用它们,只是想知道在哪种情况下我们应该更好地使用嵌入式二进制文件,还是使用链接框架?
有什么可靠的例子可以更清楚地解决这个问题吗?谢谢
您链接的问题引用了“Link Binary With Libraries”功能,这与嵌入式二进制文件有些不同。
“Link Binary With Libraries”意味着您对链接的期望:无论二进制文件是静态库、动态库还是框架,它都会在编译后的链接时链接到您的目标代码。
当您想到与静态库的链接时,会发生什么很清楚:链接器将代码从库(例如)复制libFoo.a
到您的输出二进制文件中。您的输出文件会变大,但不需要在运行时解析任何外部依赖项。您的程序需要运行的所有内容(相对于静态库)在构建后都存在。
使用动态库(.dylib,或系统提供的框架),期望您链接的库将在您运行程序时出现在系统的动态库加载器路径中的某个位置。这样您就无需将所有第三方外部库复制到您的二进制文件中,并且计算机上所有链接到该库的不同程序都可以找到它,这样可以节省最少的磁盘空间,而且潜在的内存空间,具体取决于系统缓存库的方式和位置。
框架很像动态库,但可以在其目录结构中包含资源(图像、音频、其他框架等)。在这种情况下,一个简单的静态库或 .dylib 文件不会剪切它,因此您可能必须链接到一个框架,以便它可以找到正常运行所需的内容。
当您链接到第三方框架时(比如您从 github 下载并自己构建的框架),它可能不会出现在您打算运行的系统上。在这种情况下,您不仅要链接到框架,还要使用“复制框架”阶段将其嵌入到您的应用程序包中。当您的程序运行时,运行时链接器(也称为解析器)将在您的包中查找系统加载程序路径,找到嵌入式框架并链接它,以便您的应用程序将拥有运行所需的代码。
最后,正确的“嵌入式二进制文件”是一个可执行文件,您可以通过 Copy-Files Phase 将它们嵌入到应用程序包中,并且您自己执行,可能需要调用popen()
或类似的方法。嵌入的二进制文件可能会被您的程序调用,但它没有与之链接。它是一个完全外部的实体(如/bin
目录中的程序)。
在实践中,对于系统提供的库和框架,您将链接到它们,这就是您需要做的所有事情。
如果您需要链接您构建的不需要任何嵌入式资源的库(即不需要存在框架),那么您可以链接到静态库。如果您发现您的程序中有多个模块想要使用相同的库代码,那么将其转换为框架或动态库并对其进行链接可以节省空间并且可能很方便(特别是如果内存使用是一个问题)。
最后,框架不仅可以包含资源,还可以包含头文件和/或许可文件。使用框架来传送这些文件实际上是一种方便的分发机制,因此您可能经常希望合并一个框架,以便这些东西可以与您的二进制文件一起标记(即许可证要求可能使这成为强制性的)。
- - 编辑 - -
Adam Johns 发表了以下问题作为评论:
这是一个很好的答案。然而,有些事情我仍然有点困惑。自己执行二进制文件是什么意思?你的意思是简单地使用嵌入式框架的代码吗?我知道你提到了 popen(),但你是说我的应用正在调用 popen()?我真的不知道那是什么意思。
我是说嵌入式二进制文件只是捆绑包中的另一个资源文件,例如音频文件或图像,尽管该文件是可执行的命令行工具。该popen()
功能(man popen
从您的终端阅读有关它的更多信息)允许您从另一个正在运行的程序执行任意程序。该system()
功能是另一种方式。还有其他的,我将在这里给出一个历史示例,可以更清楚地理解嵌入式二进制文件的使用:
您可能知道,当您在 Mac OS X 上启动应用程序时,它会以当前用户的用户 ID 启动。在最常见的安装中,默认用户是桌面admin
用户,该用户被赋予 user id 501
。
在基于 Unix 的操作系统上,只有root
用户 (user id 0
) 具有对整个文件系统的完全访问权限。有时,桌面用户启动的安装程序需要在特权目录(例如驱动程序)中安装文件。在这种情况下,应用程序需要将其权限提升给root
用户,以便它可以写入这些受限目录。
为了通过 OS X 10.7 在操作系统中实现这一点,Apple 在其授权服务 API中提供了函数AuthorizationExecuteWithPrivileges()(现在已弃用,但仍然是一个有用的示例)。
AuthorizationExecuteWithPrivileges()
将命令行工具的路径作为参数执行为root
. 命令行工具是您为运行安装逻辑而编写的可执行 shell 脚本或编译后的二进制文件。就像任何其他资源文件一样,此工具安装在您的应用程序包中。
当被调用时,操作系统会弹出一个授权对话框,询问用户的密码(你以前见过这个!),当输入时,它将root
代表你的应用程序执行程序。这个过程类似于popen()
自己执行一个程序,尽管popen()
单独执行并不能为您带来特权提升的好处。
简而言之,
- 系统库,链接它们;
- 3rd 方库,嵌入它们。
为什么?
- 如果您尝试嵌入系统库,您将不会在弹出列表中找到它们;
- 如果您链接 3rd 方库,您可能会崩溃。
Xcode v11 之前的版本。嵌入式二进制文件与链接框架和库
历史
Embedded Binaries vs Linked Frameworks and Libraries -> Frameworks, Libraries, and Embedded Content
[Xcode v11。Frameworks, Libraries, and Embedded Content]将其从General
选项卡中的 Xcode v11 部分替换
embedded binaries
并且Linked Frameworks
是Dependency
管理的一部分[关于]
General -> Linked Frameworks and Libraries
是 的镜子Build Phases -> Link Binary With Libraries
。
静态库和框架
如果您Static Library or Static Framework
向此部分添加 a,它将出现在Frameworks
组[About] ( Project Navigator -> <workspace/project> -> Frameworks
) 中,并且将为您的项目添加一个参考。然后它将被Static Linker
. Static Linker
在编译时会将库中的所有代码包含/复制到可执行目标文件中。Static linker
与Build Settings -> <Library/Framework> Search Paths
Static Library
Build Settings -> Library Search Paths
[找不到库]如果您不static library
向此部分添加 a,您将收到链接器错误[ld: symbol(s) not found]Static Framework
Build Settings -> Framework Search Paths
. 如果你不添加static framework
到这个部分,你会得到一个编译错误[No such module]静态库和静态框架
嵌入对 a 没有任何意义Static Library
,Static Framework
因为它们的符号被编译成可执行的二进制文件。Xcode 不会让你static library
在 Embed 部分下放置一个。
动态框架
General -> Embedded Binaries
是 的镜子Build Phases -> Embed Frameworks
。
嵌入实际上将框架的副本添加到您的应用程序包中(不将框架和应用程序的代码合并到单个可执行二进制文件中)
默认情况下,捆绑包的文件夹是Frameworks
,但您可以使用Destination
字段更改它。此外,您可以指定一个Subpath
.
Dynamic linker :dyld
在加载或运行时将尝试使用[关于]查找嵌入式框架,如果未找到则会发生错误[dyld: Library not loaded]@rpath
结果:
Static Library
-Link
Static Framework
-Link
Dynamic Framework
-Embed