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

链接二进制与库VSembedded框架中描述的这两个选项之间的区别是一个很好的问题。

好像我们可以select使用它们,只是想知道哪种情况下我们应该更好地使用embedded式二进制文件,而不是链接框架?

任何可靠的例子来解决这个更清楚? 谢谢

链接的问题引用了“链接库与库”function,这与embedded式二进制文件有所不同。

“链接二进制与库”意味着你期望它在连接方面:无论是二进制文件是静态库,dynamic库还是框架,在编译之后链接时都会链接到目标代码。

当你想到与静态库的链接时,会发生什么非常明显的事情:链接器将库中的代码(例如libFoo.alibFoo.a到输出二进制文件中。 您的输出文件的大小会增大,但不需要在运行时解决任何外部依赖性。 你的程序需要运行的所有东西(关于静态库)在构build完成后都会出现。

使用dynamic库(.dylib或系统提供的框架),期望在运行程序时,链接的库将存在于系统的dynamic库加载器path中的某处。 这样你就没有把所有的第三方外部库复制到你的二进制文件的开销,而且连接到这个库的计算机上的所有不同的程序都能够find它,这样可以节省最less的磁盘空间,而且可能的内存空间,这取决于系统caching库的方式和位置。

框架非常像dynamic库,但是可以在其目录结构(图像,audio,其他框架等)中包含资源。 在这种情况下,一个简单的静态库或者.dylib文件不会被剪切掉,所以你可能不得不链接到一个框架,以便能够find它需要正确运行的东西。

当你链接到第三方框架(比如你从github下载并自己构build的东西)时,它可能不会出现在你打算运行的系统上。 在这种情况下,您不仅可以链接到框架,还可以使用“复制框架”阶段将其embedded到应用程序包中。 当你的程序运行时,runtime-linker(也就是parsing器)除了系统加载器path以外,还会查看你的bundle,findembedded式框架,并将它链接起来,这样你的应用就会拥有它所需要的代码来运行。

最后,正确的“embedded式二进制文件”是一个可执行文件,它们都通过复制文件阶段embedded到应用程序包中,并且可以通过调用popen()或类似方法来执行。 embedded式二进制文件可能会被你的程序调用,但是它并没有被链接。 它是一个完全外部的实体(像/bin目录中的程序)。

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

如果你需要链接一个你不需要任何embedded式资源(即不需要框架)的库,那么你可以直接连接一个静态库。 如果你发现你的程序中有多个模块需要使用相同的库代码,那么将其转换为一个框架或dynamic库,然后进行链接可以节省空间,并且可能很方便(特别是在内存使用率较高的情况下)。

最后,框架不仅可以包含资源,还可以包含头文件和/或许可证文件。 使用框架来传递这些文件实际上是一个方便的分发机制,所以你可能想要合并一个框架,以便这些东西可以与你的二进制文件一起标记(即许可证的要求可能使这是必须的)。

—编辑—

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

这是一个很好的答案。 但是,我还是有点困惑。 这是什么意思自己执行二进制文件? 你的意思是简单地使用embedded式框架的代码? 我知道你提到了popen(),但是你说我的应用程序正在调用popen()? 我真的不知道这意味着什么。

我在说一个embedded式二进制文件只是你的包中的另一个资源文件,就像audio文件或图像一样,尽pipe这个文件是一个可执行的命令行工具。 popen()函数(从您的terminalman popen读取更多关于它)让您从另一个正在运行的程序执行任意程序。 system()函数是另一种方法。 还有其他的,我会在这里给出一个历史的例子,这可能使得理解embedded式二进制的使用更加清晰:

正如您可能已经知道的那样,当您在Mac OS X上启动应用程序时,它将以当前用户的用户标识启动。 在最常见的安装下,默认的用户在桌面admin用户,谁被给予用户ID 501

在基于Unix的操作系统上,只有root用户(用户ID为0 )才能完全访问整个文件系统。 有时,桌面用户启动的安装程序需要将文件安装在特权目录(例如驱动程序)中。 在这种情况下,应用程序需要将其权限升级到root用户,以便可以写入这些受限制的目录。

为了在操作系统中通过OS X 10.7实现这个function,Apple在其Authorization Services API中提供了AuthorizationExecuteWithPrivileges()函数(现在不推荐使用,但仍然是一个有用的例子)。

AuthorizationExecuteWithPrivileges()将一个命令行工具的path作为参数,以root身份执行。 命令行工具是一个可执行的shell脚本或编译的二进制文件,您可以使用它来运行安装逻辑。 这个工具就像任何其他资源文件一样安装在应用程序包内。

被调用的时候,操作系统会popup一个授权对话框询问用户的密码(以前你已经看到了!),input密码就会代表你的应用程序以root身份执行程序。 这个过程与使用popen()自己执行程序相似,尽pipepopen()本身并不能为您提供权限提升的好处。

简而言之,

  • 系统库,链接它们;
  • 第三方库,embedded它们。

为什么?

  • 如果您尝试embedded系统库,则不会在popup列表中find它们;
  • 如果你链接第三方库,你可能会崩溃。