问题描述
是否可以弱链接静态库(Obj-C)?
Is it possible to weakly link a static library (Obj-C)?
我确实希望我的自定义静态框架( MyFramework.framework )弱链接我的其他自定义静态库( libMyLibrary.a ).
I do want my custom static framework (MyFramework.framework) to weakly link my other custom static library (libMyLibrary.a).
libMyLibrary.a 后面的功能是可选的,如果任何第三方应用程序链接了 NO libMyLibrary.a ,则可以省略此功能.使用 MyFramework.framework .
The functionality behind libMyLibrary.a is optional and can be omitted if there is NO libMyLibrary.a being linked by any 3rd party application that uses MyFramework.framework.
我正在使用-weak_library
一个>.我的测试应用程序抱怨静态链接器无法在 MyFramework 的ABCTracker.o
符号中找到 MyLibrary 的符号MyClass
:
I am using -weak_library
. My test application complains that static linker is unable to find MyLibrary's symbol MyClass
within MyFramework's ABCTracker.o
symbol:
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)
如何正确设置弱链接?
- Xcode项目构建一个静态的Mach-O二进制文件并将其捆绑到一个静态框架中.结果是 MyFramework.framework 包.
- 其他项目构建了一个静态Mach-O二进制文件,结果是一个静态lib文件 libMyLibrary.a ,其头文件为 MyLib.h 从 MyFramework.framework 目标的 Build Phases > Link Binary With Libraries 中删除
- libMyLibrary.a a href ="https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html" rel ="noreferrer">如此处建议).只有 MyLib.h 可以使用框架类中的库API
- 框架和库中均未使用位码
- MyFramework.framework , libMyLibrary.a 和自定义应用程序都是用Objective-C编写的.
- MyLib.h 定义了一个Objective-C类
MyClass
- MyFramework.framework 使用其自身类
ABCTracker
中的MyClass
有条件地检查运行时的符号可用性,例如NSClassFromString(@"MyClass") == NULL
-
从 MyFramework 目标的 Build Settings 中,我已将
Other Librarian Flags
和Other Linker Flags
设置为相同的值-weak_library MyLibrary
:
- The Xcode project builds a static Mach-O binary and bundles it into a static framework. The result is MyFramework.framework bundle.
- Other project builds a static Mach-O binary and the result is a static lib file libMyLibrary.a with a header MyLib.h
- libMyLibrary.a is removed from MyFramework.framework target's Build Phases > Link Binary With Libraries (as suggested here). Only MyLib.h is available to use library's API from the framework's classes
- NO Bitcode is used neither in the framework, nor in the library
- MyFramework.framework, libMyLibrary.a and custom application are all written in Objective-C
- The MyLib.h defines just one Objective-C class
MyClass
- MyFramework.framework uses
MyClass
from its own classABCTracker
conditionally checking for symbol availability during runtime, e.g.NSClassFromString(@"MyClass") == NULL
From MyFramework target's Build Settings I have set
Other Librarian Flags
andOther Linker Flags
to same value-weak_library MyLibrary
:
OTHER_LDFLAGS = (
"-weak_library",
MyLibrary,
);
OTHER_LIBTOOLFLAGS = "-weak_library MyLibrary";
- MyFramework.framework 构建成功
-
构建后,我检查了生成的二进制文件中的符号,并且输出为emty(静态库中没有任何符号已内置到静态框架二进制文件中):
- MyFramework.framework builds OK
After the build I have checked the symbols in the resulting binary and the output was emty (no symbols from the static library were built into static framework binary):
$ otool -L MyFramework.framework/MyFramework | grep MyClass
尽管如此,我的未与 MyLibrary 链接的测试应用程序都生成了ld
错误:
Despite that, my test application which is not linked with MyLibrary whatsoever, builds with ld
error:
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)
我在这里做什么错了?
在 MyFramework 目标中,将Other Librarian Flags
和Other Linker Flags
设置为相同的值:
In MyFramework target I set Other Librarian Flags
and Other Linker Flags
of to same value:
-
-lMyLibrary
.结果:otool
显示库的符号已内置到框架中(预期). -
-weak-lMyLibrary
.结果与lMyLibrary
相同(是预期的吗?)
-lMyLibrary
. Result:otool
shows the library's symbols are built into the framework (expected).-weak-lMyLibrary
. Result is the same as forlMyLibrary
(is it expected?)
在我的应用目标中,将Other Linker Flags
设置为-force_load MyLibrary
.结果:链接器错误略有变化:
In my application target I set Other Linker Flags
to -force_load MyLibrary
. Result: the linker error slightly changes:
ld: file not found: MyClass
clang: error: linker command failed with exit code 1 (use -v to see invocation)
推荐答案
我也没有成功让XCode适当地弱链接静态库,尽管我遇到了与您相反的问题-对我来说nm
显示了所有静态库中的符号,而不是弱链接框架时看到的"U"(未定义)符号类型.
I have also not been successful at getting XCode to properly weak link a static library, although I have the opposite problem from yours - for me nm
showed all the symbols from the static library, and not with "U" (undefined) symbol type as you see when you weak link a framework.
但是您可以使用以下解决方法:
But a workaround you can use is the following:
- 创建一个名为 MyWrapper.framework 的新Cocoa Touch Framework项目,并向其中添加 libMyLibrary.a
- 将
-ObjC
添加到链接器标志以确保所有符号都被获取已加载(如果需要非Obj-C符号,则为-all_load
) - 将库的标头添加到构建阶段 中框架的公共标头部分
- 构建此框架(您将希望为所有体系结构建立一个聚合目标,但这是一个单独的主题)
- 打开您的 MyFramework.framework 项目,并将其添加到链接较弱的 MyWrapper.framework (即,使用切换开关将其设置为可选或者如果您希望将其从与库链接二进制文件阶段删除,然后通过
-weak_framework
将其添加到 Other Linker Flags (其他链接器标记)) - 现在构建 MyFramework.framework
- 在您的测试应用中,删除对 libMyLibrary.a 的所有引用
- 您应该能够在没有崩溃的情况下运行测试应用,并且您的代码应该不检测到 libMyLibrary.a 中是否存在符号.
- 将 MyWrapper.framework 添加到测试应用程序中,然后您将看到相反的结果-将找到并使用 libMyLibrary.a 中的符号.
- Create a new Cocoa Touch Framework project called MyWrapper.framework and add libMyLibrary.a to it
- Add
-ObjC
to the linker flags to make sure all the symbols getloaded (and-all_load
if you need non Obj-C symbols) - Add your library's headers to the framework's Public Headers section in Build Phases
- Build this framework (you'll want to set up an aggregate target to build for all architectures but that is a whole separate topic)
- Open your MyFramework.framework project and add MyWrapper.framework to it, weakly linked (i.e. use the toggle to set it to Optional or if you prefer remove it from the Link Binary with Libraries phase and add it via
-weak_framework
to Other Linker Flags) - Now build MyFramework.framework
- In your testing app, remove any reference to libMyLibrary.a
- You should be able to run your testing app with no crash and your code should not detect the presence of symbols from libMyLibrary.a
- Add MyWrapper.framework to your testing app and then you should see the opposite result - symbols from libMyLibrary.a will be found and usable.
这篇关于通过-weak_library弱链接静态库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!