简体   繁体   English

如何处理可加载的 NSBundle/插件中的重复符号?

[英]How do I handle duplicated symbols in a loadable NSBundle/plug-in?

Consider the following Cocoa project structure:考虑以下 Cocoa 项目结构:

Host
|-- LoadablePlugIn
|   |-- Main.storyboard
|   |-- Info.plist
|   |-- TDWLPIClassOne.h
|   |-- TDWLPIClassOne.m
|   |-- TDWLPIClassTwo.h
|   |-- TDWLPIClassTwo.m
|-- TDWAppDelegate.h
|-- TDWAppDelegate.h
|-- TDWClassOne.h
|-- TDWClassOne.m
|-- TDWUtils.h
|-- TDWUtils.mm
|-- Base.lproj
|   `-- Main.storyboard
|-- Info.plist
`-- main.m

Here the root folder refers to sources of the Host target (the main executable target), while LoadablePlugIn refers to resources of an embedded plug-in target with corresponding name.这里的根文件夹是指Host目标(主要可执行目标)的资源,而LoadablePlugIn是指具有相应名称的嵌入式插件目标的资源。 Both targets at the same time want to use TDWUtils symbols for their own purposes, so I add TDWUtils.mm to compile sources of both Host and LoadablePlugIn targets.两个目标同时希望将TDWUtils符号用于它们自己的目的,因此我添加TDWUtils.mm来编译HostLoadablePlugIn目标的源代码。 It compiles and works without issues, however since the LoadablePlugIn is supposed to load during run-time the linker is not able to locate duplicated symbols of TDWUtils.mm in the binaries and I'm not sure if that is a robust scenario:它编译和工作没有问题,但是由于LoadablePlugIn应该在运行时加载 linker 无法在二进制文件中找到TDWUtils.mm的重复符号,我不确定这是否是一个可靠的场景:

...
Class plugInPrincipalClass = [NSBundle bundleWithURL:loadablePlugInURL].principalClass;
NSWindowController *windowController = [plugInPC instantiateInitialController];
...

Should I compile LoadablePlugIn with hidden symbols compiler flag (like -fvisibility=hidden ) or use any other technique to prevent the name collision or can I just leave it as is because in both binaries the symbols of TDWUtils have exactly the same implementation?我应该用隐藏符号编译器标志(如-fvisibility=hidden )编译LoadablePlugIn还是使用任何其他技术来防止名称冲突,或者我可以保持原样,因为在两个二进制文件中, TDWUtils的符号具有完全相同的实现?

Ideally, you could factor out the duplicate code into a framework that is linked against by each module that requires it.理想情况下,您可以将重复代码提取到一个框架中,该框架由需要它的每个模块链接。

So, in the final app, you'd have a structure like the following:因此,在最终的应用程序中,您将拥有如下结构:

AppName.app/Contents/MacOS/AppName

AppName.app/Contents/Frameworks/TDWUtils.framework

AppName.app/Contents/PlugIns/Loadable.plugin/Contents/MacOS/Loadable

The Dynamic Library Install Name Base ( DYLIB_INSTALL_NAME_BASE ) for the TDWUtils.framework should be @rpath (ie avoid using @executable_path or @loader_path in the install name). @rpath的动态库安装名称库 ( DYLIB_INSTALL_NAME_BASE ) 应该是TDWUtils.framework (即避免在安装名称中使用@executable_path@loader_path )。 Using @rpath makes it easy to share the same library among code that's located at various locations within an app bundle.使用@rpath可以轻松地在位于应用程序包内不同位置的代码之间共享相同的库。 With @rpath , it becomes the responsibility of module that's doing the loading to specify where the library is in relation to itself.使用@rpath ,进行加载的模块有责任指定库相对于自身的位置。 You do this by adding a Runpath Search Path ( LD_RUNPATH_SEARCH_PATHS ) entry for each library the loading module needs.为此,您可以为加载模块需要的每个库添加一个运行路径搜索路径 ( LD_RUNPATH_SEARCH_PATHS ) 条目。

For the main app executable, it could be either @executable_path/../Frameworks or @loader_path/../Frameworks .对于主应用程序可执行文件,它可以是@executable_path/../Frameworks@loader_path/../Frameworks

For the plugin, it becomes @loader_path/../../../../Frameworks .对于插件,它变为@loader_path/../../../../Frameworks (Using @executable_path would not work, since a plugin isn't executed, it's just loaded). (使用@executable_path是行不通的,因为插件没有被执行,它只是被加载)。 At runtime, @loader_path in this case becomes AppName.app/Contents/PlugIns/Loadable.plugin/Contents/MacOS/Loadable , so to get to the Frameworks directory, you have to go up 4 levels to get to the Contents, folder, then back down into the Frameworks folder.在运行时, @loader_path在这种情况下变为AppName.app/Contents/PlugIns/Loadable.plugin/Contents/MacOS/Loadable ,因此要进入 Frameworks 目录,您必须 go 向上 4 个级别才能到达 Contents 文件夹,然后返回到 Frameworks 文件夹。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM