通过-weak_library弱链接静态库

Yev*_*nin 9 xcode linker objective-c static-libraries ios

题:

是否可以弱连接静态库(Obj-C)?

简短细节

我确实希望我的自定义静态框架(MyFramework.framework)弱链接我的其他自定义静态库(libMyLibrary.a).

libMyLibrary.a背后的功能是可选的,如果没有 libMyLibrary.a被任何使用MyFramework.framework的第三方应用程序链接,则可以省略.

我在用-weak_library.我的测试应用抱怨说,静态链接无法找到在MyLibrary的符号MyClassMyFramework S' ABCTracker.o符号:

Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_MyClass", referenced from:
      objc-class-ref in MyFramework(ABCTracker.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)

如何正确设置弱链接?

全部细节

建立

  • Xcode项目构建一个静态Mach-O二进制文件并将其捆绑到一个静态框架中.结果是MyFramework.framework包.
  • 其他项目构建一个静态的Mach-O二进制文件,结果是一个静态的lib文件libMyLibrary.a,带有一个标题MyLib.h
  • libMyLibrary.a将从MyFramework.framework目标的Build Phases > Link Binary With Libraries中删除(如此处所示).只有MyLib.h可以从框架的类中使用库的API
  • NO Bitcode既不用于框架,也不用于库中
  • MyFramework.framework,libMyLibrary.a和自定义应用程序都是用Objective-C编写的
  • MyLib.h只定义了一个Objective-C类MyClass
  • MyFramework.framework使用MyClass其自己的类ABCTracker有条件检查符号可用性运行时,如NSClassFromString(@"MyClass") == NULL
  • MyFramework目标的生成设置我已设置Other Librarian FlagsOther Linker Flags以相同的价值-weak_library MyLibrary:

    OTHER_LDFLAGS = (
        "-weak_library",
        MyLibrary,
    );
    OTHER_LIBTOOLFLAGS = "-weak_library MyLibrary";
    
    Run Code Online (Sandbox Code Playgroud)

结果

  • MyFramework.framework构建正常
  • 在构建之后,我检查了生成的二进制文件中的符号,输出是emty(静态库中没有符号构建到静态框架二进制文件中):

    $ otool -L MyFramework.framework/MyFramework | grep MyClass
    
    Run Code Online (Sandbox Code Playgroud)
  • 尽管如此,我的测试应用程序没有与MyLibrary链接,构建ld错误:

    Undefined symbols for architecture arm64:
      "_OBJC_CLASS_$_MyClass", referenced from:
          objc-class-ref in MyFramework(ABCTracker.o)
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    
    Run Code Online (Sandbox Code Playgroud)

我在这做错了什么?

其他观察

MyFramework目标我设置Other Librarian FlagsOther Linker Flags以相同的价值:

  • -lMyLibrary.结果:otool显示库的符号已构建到框架中(预期).
  • -weak-lMyLibrary.结果与lMyLibrary(预期?)相同

我的应用程序目标中,我设置Other Linker Flags-force_load MyLibrary.结果:链接器错误略有变化:

ld: file not found: MyClass
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Run Code Online (Sandbox Code Playgroud)

Dan*_*nny 1

我也没有成功地让 XCode 正确地弱链接静态库,尽管我遇到了与你相反的问题 - 对我来说nm显示了静态库中的所有符号,而不是像你一样使用“U”(未定义)符号类型看看你什么时候弱链接一个框架。

但您可以使用的解决方法如下:

  1. 创建一个名为MyWrapper.framework的新 Cocoa Touch Framework 项目并将libMyLibrary.a添加到其中
  2. 添加-ObjC到链接器标志以确保加载所有符号(-all_load如果您需要非 Obj-C 符号)
  3. 将库的标头添加到构建阶段中框架的公共标头部分
  4. 构建这个框架(您需要设置一个聚合目标来构建所有架构,但这是一个完全独立的主题)
  5. 打开您的MyFramework.framework项目并将MyWrapper.framework添加到其中,弱链接(即使用切换将其设置为可选,或者如果您希望将其从Link Binary with Libraries-weak_framework阶段中删除并通过Other Linker Flags添加)
  6. 现在构建MyFramework.framework
  7. 在您的测试应用程序中,删除对libMyLibrary.a的任何引用
  8. 您应该能够运行测试应用程序而不会崩溃,并且您的代码不应检测到libMyLibrary.a中符号的存在
  9. 将MyWrapper.framework添加到您的测试应用程序中,然后您应该看到相反的结果 -将找到并使用libMyLibrary.a中的符号。