从一个静态库中导出“OBJC_CLASS"作为另一个静态库的一部分 [英] Export an `OBJC_CLASS` from one static lib as part of another
问题描述
我想创建一个静态库(实际上是一个框架,但我知道如何做那部分),其中捆绑了来自另一个静态库的代码.但是,从原始库中导出的 OBJC_CLASS
最终会变成未定义的符号.
I want to create a static library (actually, a framework, but I know how to do that part) that bundles up code from, among other things, another static library. However, the OBJC_CLASS
exports from the original library end up as undefined symbols.
例如,在 Xcode 5.1.1 中(每一步都使用默认设置/选择,除非另有说明):
For example, in Xcode 5.1.1 (using default settings/choices at every step, unless otherwise specified):
- 新建一个名为 LibA 的iOS 框架和库 Cocoa Touch 静态库"项目.
- 构建(无论是模拟器还是真实设备,都没有关系).
- 将
libLibA.a
从 LibA 产品拖到 LibB 项目树中的 Frameworks 文件夹中. - 将
LibA
从静态库旁边的include
目录拖到 LibB 项目树的顶层. - 编辑
LibB.h
,如下所示. - 构建(与之前相同的目标).
- Drag
libLibA.a
from the LibA products to the Frameworks folder in the LibB project tree. - Drag
LibA
from theinclude
directory next to the static lib to the top level of the LibB project tree. - Edit
LibB.h
as shown below. - Build (same target as before).
- 将
libLibB.a
从 LibB 产品拖到 AppC 项目树中的 Frameworks 文件夹中. - 将
LibB
从include
目录拖到顶层. - 将
LibA
从第一个项目的include
目录拖到顶层. - 验证
LibA
是否出现在 Link Binary With Libraries 阶段. - 在向导生成的任何类的任何方法中(例如,
-[MasterViewControllerawakeFromNib]
),添加(void)[[LibB alloc] init]
.立> - 在您刚刚编辑的
.m
文件的顶部,添加#import "LibB.h"
. - 构建.
- Drag
libLibB.a
from the LibB products to the Frameworks folder in the AppC project tree. - Drag
LibB
from theinclude
directory to the top level. - Drag
LibA
from the first project'sinclude
directory to the top level. - Verify that
LibA
appears in the Link Binary With Libraries phase. - In any method of any class the wizard generated (e.g.,
-[MasterViewController awakeFromNib]
), add(void)[[LibB alloc] init]
. - At the top of the
.m
file you just edited, add#import "LibB.h"
. - Build.
这是上面承诺的
LibB.h
:#import <Foundation/Foundation.h> #import "LibA.h" @interface LibB: LibA @end
我收到以下错误:
Undefined symbols for architecture i386: "_OBJC_CLASS_$_LibA", referenced from: _OBJC_CLASS_$_LibB in libLibB.a(LibB.o) "_OBJC_METACLASS_$_LibA", referenced from: _OBJC_METACLASS_$_LibB in libLibB.a(LibB.o) ld: symbol(s) not found for architecture i386 clang: error: linker command failed with exit code 1 (use -v to see invocation)
查看文件,问题很明显:
Looking at the files, the problem is obvious:
$ nm -g libLibB.a U _OBJC_CLASS_$_LibA 0000031c S _OBJC_CLASS_$_LibB U _OBJC_METACLASS_$_LibA 00000308 S _OBJC_METACLASS_$_LibB U _OBJC_METACLASS_$_NSObject U __objc_empty_cache
_OBJC_CLASS_$_LibA
和_OBJC_METACLASS_$_LibA
的符号导出为未定义.The symbols for
_OBJC_CLASS_$_LibA
and_OBJC_METACLASS_$_LibA
are exported as undefined.我可以从 LibA 中引用方法、C 函数和结构、全局变量等.甚至 Foundation 对象上的类别(只要我执行类别虚拟技巧).只有类和元类对象我不知道如何导出.
I can reference methods, C functions and structs, globals, etc. from LibA. Even categories on Foundation objects (as long as I do the category-dummy trick). It's only the class and metaclass objects that I can't figure out how to export.
这是我试图修复它的原因:
Here's what I've tried to fix it:
- 关闭死代码剥离(在所有三个项目中).
- 添加
-ObjC
作为额外的链接器标志(在所有项目中).(这对于静态库没有意义,它所做的只是给你一个警告错误,告诉你确切地说,但每个人都向我建议.) - 创建一个导出的符号文件"(用于
LibB
).(这也只对动态库有意义.) - 将
${PROJECT_DIR}/libLibA.a
作为其他链接器标志"(用于LibB
)而不是添加libLibA
作为框架(以防-lLibA
与libLibA.a
的处理方式不同).
- Turn off Dead Code Stripping (in all three projects).
- Add
-ObjC
as an extra linker flag (in all projects). (This makes no sense for static libs, and all it does is give you a warning error telling you exactly that, but everyone suggests it to me.) - Create an "Exported Symbols File" (for
LibB
). (This also only makes sense for dynamic libs.) - Pass
${PROJECT_DIR}/libLibA.a
as an "Other Linker Flags" (forLibB
) instead of addinglibLibA
as a framework (in case-lLibA
is processed differently fromlibLibA.a
).
我尝试过的我仍然认为可能在正确的道路上,但我不确定:
What I've tried that I still think may be on the right path, but I'm not sure:
- 尝试找出在 Xcode 中没有相应设置的适当
libtool
选项.(如有必要,我可以将其包装在 Makefile 或 Xcode 自定义构建步骤中.) - 启用执行单对象预链接",然后将
${PROJECT_DIR}/libLibA.a
添加到预链接库".我收到有关重复符号的警告,然后成功,但libLibB.a
是空的,所以显然我还需要做一些其他事情.我已经在 OS X 上使用 .dylibs 和动态框架完成了这项工作,而且我不需要在那里做任何其他事情……但从来没有使用静态库.
- Try to figure out appropriate
libtool
options that have no corresponding settings in Xcode. (I can wrap it in a Makefile, or and Xcode custom build step, if necessary.) - Enable "Perform Single-Object Prelink", then add
${PROJECT_DIR}/libLibA.a
to "Prelink libraries". I get warnings about duplicate symbols and then success but with an emptylibLibB.a
, so obviously there's something else I need to do. I've done this with .dylibs and dynamic Frameworks on OS X, and there wasn't anything else I needed to do there… but never with static libs.
我知道的解决方法(如果没有真正的解决方案,我将使用其中之一):
Workarounds that I know about (and I'll use one of these if there's no real solution):
- 要求任何想要使用
LibB
的人还必须将LibA
添加到他们的项目中.尤其是我们提供的LibA
的预构建副本. - 分发
LibB
作为要包含在项目中的源,而不是静态库和标头. - 手动
ar
libLibA.a
和LibB.o
,然后ranlib
就像 1999 年一样(尽管文档说这行不通,似乎行得通).
- Require that anyone who wants to use
LibB
also has to addLibA
to their project. And, in particular, the pre-built copy ofLibA
that we provide. - Distribute
LibB
as source to be included in your project, instead of a static lib and headers. - Manually
ar
libLibA.a
andLibB.o
, thenranlib
like it's 1999 (although the docs say this doesn't work, it seems to).
(对于我的简单测试项目来说,这些都不是太糟糕,但在现实生活中,这不是一个开源项目,LibA 实际上是来自 3 个不同项目的 80 个不同的库,其中一些 LibA 代码构建了胖 armv7/armv7s(这意味着
ar
对它不起作用……),我们计划将模拟器和本机构建一起进行通常的黑客攻击,并利用它们制作一个框架,所有这些都让事情变得更加棘手.(None of these are too terrible for my simple test project, but in real life, this is not an open source project, that LibA is actually 80 different libs from 3 different projects, and some of the LibA code builds fat armv7/armv7s (which means
ar
doesn't work on it…), and we're planning to do the usual hack of lipo'ing together the simulator and native builds and making a framework out of them, all of which makes things more of a problem.推荐答案
我想我可能已经用单对象预链接解决了它(基本上这意味着它做了一个
ld -r
来构建一个巨大的目标文件,然后将其传递给libtool
),尽管我仍然不确定,而且我不喜欢该解决方案.所以,我会发布我得到的答案作为答案,但希望其他人提供更好的答案.I think I may have solved it with single-object prelink (basically this means it does an
ld -r
to build a giant object file, then passes that tolibtool
), although I'm still not sure, and I don't love the solution. So, I will post what I've got as an answer, but hope someone else comes along with a better answer.要使单对象预链接起作用,您需要(在
LibB
中):To get single-object prelink to work, you need to (in
LibB
):- 添加
libLibA.a
作为框架. - 确保它不出现在 Link Binary With Libraries 构建阶段.
- 将死码剥离"设置为否.
- 将Don't Dead-Strip Inits and Terms"设置为Yes.
- 将执行单对象预链接"设置为是.
- 将预链接库"设置为
${PROJECT_DIR}/libLibA.a
- 将保留私有外部符号"设置为是.
- Add
libLibA.a
as a Framework. - Make sure it does not appear in the Link Binary With Libraries build phase.
- Set "Dead Code Stripping" to No.
- Set "Don't Dead-Strip Inits and Terms" to Yes.
- Set `Perform Single-Object Prelink" to Yes.
- Set "Prelink libraries" to
${PROJECT_DIR}/libLibA.a
- Set "Preserve Private External Symbols" to Yes.
(第二步是我之前做错的……)
(The second step is what I was doing wrong earlier…)
不幸的是,这似乎完全打破了依赖规则,因此每个构建都会重新编译作为目标一部分的每个 .m(和 .pch),即使没有任何变化.
Unfortunately, this seems to break the dependency rules completely, so that every build recompiles every .m (and .pch) that's part of the target, even if nothing has changed.
除此之外,这似乎对
AppC
和我的真实项目都适用.Other than that annoyance, this seems to work for both
AppC
and my real project just fine.AppC
不需要保留私有外部符号";我的真实项目确实如此.我相信这是因为其中一个第三方库做了一个ld -r
和一个空的-exported_symbols_list
明确地将所有符号转换为private_extern
>. 否则,类对象不会以这种方式结束.但是,我不是 100% 确定我理解这一点.AppC
does not need "Preserve Private External Symbols"; my real project does. I believe this is because one of the third-party libraries does anld -r
with an empty-exported_symbols_list
explicitly to "transform all symbols toprivate_extern
. Otherwise, class objects don't end up that way. However, I'm not 100% sure I understand this one.这篇关于从一个静态库中导出“OBJC_CLASS"作为另一个静态库的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!