从一个静态库中导出“OBJC_CLASS"作为另一个静态库的一部分 [英] Export an `OBJC_CLASS` from one static lib as part of another

查看:58
本文介绍了从一个静态库中导出“OBJC_CLASS"作为另一个静态库的一部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个静态库(实际上是一个框架,但我知道如何做那部分),其中捆绑了来自另一个静态库的代码.但是,从原始库中导出的 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 the include 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 文件夹中.
    • LibBinclude 目录拖到顶层.
    • 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 the include directory to the top level.
    • Drag LibA from the first project's include 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 作为框架(以防 -lLibAlibLibA.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" (for LibB) instead of adding libLibA as a framework (in case -lLibA is processed differently from libLibA.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 empty libLibB.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.aLibB.o,然后 ranlib 就像 1999 年一样(尽管文档说这行不通,似乎行得通).
    • Require that anyone who wants to use LibB also has to add LibA to their project. And, in particular, the pre-built copy of LibA that we provide.
    • Distribute LibB as source to be included in your project, instead of a static lib and headers.
    • Manually ar libLibA.a and LibB.o, then ranlib 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 to libtool), 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 an ld -r with an empty -exported_symbols_list explicitly to "transform all symbols to private_extern. Otherwise, class objects don't end up that way. However, I'm not 100% sure I understand this one.

    这篇关于从一个静态库中导出“OBJC_CLASS"作为另一个静态库的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆