我正在尝试创建一个用 Objective-C 编写的静态库。我想对这个库的消费者隐藏所有实现细节。在这个例子中,“OneThing”对象使用了库内部的其他功能,包括“SecretThing”,它可以被库中的许多东西使用(并且不能隐藏在 OneThing 中)。但是,我不希望库的用户看到 OneThing 使用 SecretThing,或者 SecretThing 甚至存在,即使他们在 .a 文件中四处寻找。
@interface OneThing
+ (void) do;
@end
@interface SecretThing
+ (void) undo;
@end
@implementation OneThing
+ (void) do
{
[SecretThing undo];
}
@end
@implementation SecretThing
+ (void) undo { }
@end
如果我们编译它,并检查符号表:
% cc -c onething.m
% nm onething.o | grep Thing
0000000000000000 t +[OneThing do]
00000000000002f8 s +[OneThing do].eh
0000000000000040 t +[SecretThing undo]
0000000000000320 s +[SecretThing undo].eh
0000000000000078 S _OBJC_CLASS_$_OneThing
0000000000000050 S _OBJC_CLASS_$_SecretThing
00000000000000a0 S _OBJC_METACLASS_$_OneThing
00000000000000c8 S _OBJC_METACLASS_$_SecretThing
0000000000000128 s l_OBJC_$_CLASS_METHODS_OneThing
00000000000001d8 s l_OBJC_$_CLASS_METHODS_SecretThing
0000000000000190 s l_OBJC_CLASS_RO_$_OneThing
0000000000000240 s l_OBJC_CLASS_RO_$_SecretThing
0000000000000148 s l_OBJC_METACLASS_RO_$_OneThing
00000000000001f8 s l_OBJC_METACLASS_RO_$_SecretThing
%
正如我们所料,我们看到 OneThing 和 SecretThing 同样暴露在外。现在,如果能以某种方式解决 SecretThing 的内部对库的使用,并且只将 OneThing 暴露给外部世界,那就太好了。我想要做的是这个(只选择一种方法来尝试和管理):
% ld -r onething.o -exported_symbol "+[OneThing do]" -o onlyonething.o
我希望这会将“+ [OneThing do]”标记为“T”类型(全局文本),然后它将在“条带”中存活下来。它不是。这让我很烦恼,因为我认为这在某个时间点有效,也许当我更新工具链时,我得到了一个新版本的 ld(“ld -v”==ld64-133.3),它的工作方式不同。
除了获取链接器的源代码并编写自己的新标志来做我想做的事情之外,我没有其他想法。我希望我只是愚蠢,有一些我不明白的东西使这更容易。
在答案中建议这从根本上是不可能的,因为您需要在运行时可用的所有链接信息来进行方法分派。我相信这个实验证明这不是真的。
# Move OneThing and SecertThing into their own files, with their own .h
% cat c_api.m
#include "OneThing.h"
void one_thing_do()
{
[OneThing do];
}
% cc -c c_api.c
% cat main.m
int main(int argc, char**argv)
{
extern void one_thing_do();
one_thing_do();
}
% cc main.m c_api.o onething.o secretthing.o -framework Foundation
% ./a.out
% ( runs to completion, no errors )
现在我们尝试隐藏我们不想让世界看到的部分:
% ld -r c_api.o onething.o secretthing.o -o strip_c_api.o -exported_symbol "_one_thing_do"
% strip -x c_strip_c_api.o
% nm strip_c_api.o
0000000000000118 s EH_Frame1
0000000000000098 s EH_Frame1
00000000000000d8 s EH_Frame1
U __objc_empty_cache
U __objc_empty_vtable
U _objc_msgSend
0000000000000000 T _one_thing_do
0000000000000130 s func.eh
00000000000000f0 s func.eh
00000000000000b0 s func.eh
0000000000000020 t l001
0000000000000060 t l002
0000000000000170 s l003
0000000000000190 s l004
00000000000001d8 s l005
0000000000000220 s l006
0000000000000240 s l007
0000000000000288 s l008
00000000000002f0 s l009
0000000000000318 s l010
0000000000000340 s l011
0000000000000368 s l012
% clang main.m strip_c_api.o -framework Foundation
% ./a.out
% nm a.out
0000000100001280 S _NXArgc
0000000100001288 S _NXArgv
0000000100001298 S ___progname
0000000100000000 T __mh_execute_header
U __objc_empty_cache
U __objc_empty_vtable
0000000100001290 S _environ
U _exit
0000000100000db0 T _main
U _objc_msgSend
0000000100000de0 T _one_thing_do
0000000100001000 s _pvars
U dyld_stub_binder
0000000100000d70 T start