背景
我正在构建一个 iOS 应用程序(从这里我将其称为 MyApp
),它将依赖于由几个单独的静态库(我将其称为 Lib1
、 Lib2
、 Lib3
、。 ...)。每个库都构建在自己的项目中,然后导入到单个工作区(因此工作区将包含 MyApp
、 Lib1
、 Lib2
、...)。有关如何设置的更多详细信息 here .这些库由独立于 MyApp
的其他产品使用。 ,所以我想尽量减少库中的任何更改。库也写在(普通)C
,所以没有头文件。
某些函数名被多个库使用(所以 Lib1
和 Lib2
可能都有一个 DoStuff
方法)。具有相同名称的函数通常做同样的事情,但有一些关于如何做的细节在库之间可能有所不同,因此 DoStuff
中的实际代码在 Lib1
可能与 DoStuff
中的代码完全不同在 Lib2
.编写一个通用的 DoStuff
将是非常困难的。这在每个库中都完全相同。
问题
当应用程序运行时,它没有调用正确的 DoStuff
来自正确的库。我发现这是因为在调试 session 期间调用了错误的函数(最终导致应用程序崩溃,因为 DoStuff
函数中的细微差别)。
我在找什么
每个库只有一个来自 MyApp
的入口点,并且每个入口点都有唯一的名称。如 DoStuff
从 Lib1
的入口点方法调用(或任何其他方法 Lib1
,就此而言),然后我希望它调用 DoStuff
方法在 Lib1
.实现这一目标的最佳方法是什么?
有什么办法(也许通过 XCode 中某处的设置)我可以让每个库都是它自己的命名空间?这将是我解决问题的首选方法。我想我可以遍历并重命名重复的函数,以便它们都是唯一的(因此 DoStuff
上的 Lib1
方法可以重命名为 Lib1DoStuff
或类似的东西),但是有数百个函数可以具有重复的名称,我们将在项目中添加数百个库,因此必须手动重命名所有函数并修复对它们的所有调用将花费大量时间,而我的老板不会认为这是一个可行的选择。
更新
在查看了 Josh Caswell 的评论和他提供的一些链接后,似乎可以在编译库时自动重命名所有函数,这将是尝试修复 的最佳方法。 THE ISSUE
以上。据我所知,objcopy
iOS 不支持评论中的几个链接中提到的内容。我最终遇到了 this博客条目,其中讨论了为 Xcode 目标创建自定义构建规则,以及 this讨论自定义build设置和构建阶段的博客。
我是否正确假设我可以在构建过程中的某个时刻使用脚本来自动附加到我的每个库中的所有函数的名称,而不是像我在 WHAT I'M LOOKING FOR
的最后一段中描述的那样手动执行此操作?上面的部分? 如果是这样,进行这些更改的构建过程的正确部分是什么?最后,做这样的事情的语法是什么样的? 在构建过程的不同部分中使用的“脚本”当然不像 Obj-C。我以前从未使用过这些“脚本”,所以我对如何使用它们完全一无所知,这就是我正在寻求帮助的原因。
我试图尽可能清楚,但如果对我的要求有任何疑问,请告诉我。
最佳答案
为什么 xcode 不调用正确的库函数?
假设我有你提到的 3 个 C 库。假设它有以下代码。
库 1 - test1lib.a,代码:
#include <stdio.h>
void doStuff()
{
printf("\nDoing stuff for lib1\n");
}
void uniqueEntryPoint1()
{
printf("\nUnique entry point for lib1\n");
doStuff();
}
库 2 - test2lib.a 代码:
#include <stdio.h>
void doStuff()
{
printf("\nDoing stuff for lib2\n");
}
void uniqueEntryPoint2()
{
printf("\nUnique entry point for lib2\n");
doStuff();
}
库 3 - test3lib.a 代码:
#include <stdio.h>
void doStuff()
{
printf("\nDoing stuff for lib3\n");
}
void uniqueEntryPoint3()
{
printf("\nUnique entry point for lib3\n");
doStuff();
}
这里每个库都有一个独特的功能和一个通用功能
doStuff()
当我们将这 3 个库添加到 xcode 并链接它们时。 xcode 链接但不加载所有对象文件。假设 Objective-C 代码是这样的:
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
uniqueEntryPoint1();
}
输出是
Unique entry point for lib1
Doing stuff for lib1
在这种情况下,xcode 将仅加载在这种情况下引用的符号(库 1 对象)。
如果您了解链接器标志/选项,例如
-all_load
, -force_load
和 -objC
,你会有更好的理解。如果我们添加
-all_load
链接器选项,它将强制链接器加载库的所有对象,因此我们将在 xcode 中收到以下错误ld: 2 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
失败的原因是链接器检测到
doStuff()
被多次重新定义。解决此问题的唯一方法是更改链接器输入,即这 3 个库中存在的符号。 Josh 在评论中已经提到了这一点。我会添加我的 0.02 美元。
可能的解决方案
解决方案1:
最好的解决方案(不言自明)是更改源代码,如果您有权访问它。
解决方案2:
使用 objcopy 重命名该函数或为其添加前缀,如此 How to deal with symbol collisions between statically linked libraries? 的答案中提供的那样
现在您对如何找到 objcopy 有疑问。
选项1:
您可以使用这个项目https://github.com/RodAtDISA/llvm-objcopy .这将很难编译,因为它与 llvm 一起构建。您必须按照 http://llvm.org/docs/GettingStarted.html 中的说明进行操作。和 http://llvm.org/docs/CMake.html .
如果重写https://github.com/RodAtDISA/llvm-objcopy/blob/master/llvm-objcopy.cpp ,您可能可以在不依赖 llvm 的情况下重用解析和对象重写逻辑。
选项 2:
编译并重用来自 https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=binutils/objcopy.c;h=2636ab4bcb34cf1e1e54db9933018a805b366727;hb=HEAD 的 binutils objcopy
解决方案 3:
您可以按照 Richard 在此链接中提供的答案Rewriting symbols in static iOS libraries .这更像是一种黑客攻击,但如果它们的长度保持不变,您可以使用十六进制编辑器重写符号。如果你有更多的符号并且它的库很大,你可以考虑使用 https://sourceforge.net/projects/bbe-/和 nm 编写脚本。
所有这些都是相当大的努力,但显然没有捷径。
关于ios - 在构建时更改子程序名称以避免 Xcode 中的冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40366419/