使用Cocoapods构建静态库时防止出现重复符号

时间:2014-01-21 04:37:07

标签: ios objective-c static-libraries cocoapods

虽然我已经看到很多关于Cocoapods和静态库的问题,但大多数人似乎都认为你最终会拥有一个带有静态库和最终目标应用程序的工作区。

在我的场景中,我正在构建一个静态库。更具体地说,我正在攻击MyLib.framework供用户使用。我真的喜欢用Cocoapods来管理MyLib.framework的依赖关系,但是当我的库的消费者使用Cocoapods时,它会产生很多痛点。

例如,我的库有一个AFNetworking依赖项,我用Cocoapods管理它。当我构建我的库时,它链接在libPods.a中,其中包括AFNetworking,以及一些“虚拟”文件/对象。如果我的框架的用户也使用Cocoapods来构建他们的应用程序,他们会看到类似这样的内容:

duplicate symbol _OBJC_METACLASS_$_PodsDummy_Pods in:
    /Users/erikkerber/Dropbox/Projects/MillMain/MyLib.framework/BuddySDK(Pods-dummy.o)
    /Users/erikkerber/Library/Developer/Xcode/DerivedData/MillMain-fngfqhlslygksgcfuciznkpqfrbr/Build/Products/Debug-iphonesimulator/libPods.a(Pods-dummy.o)
duplicate symbol _OBJC_CLASS_$_PodsDummy_Pods in:
    /Users/erikkerber/Dropbox/Projects/MillMain/MyLib.framework/BuddySDK(Pods-dummy.o)
    /Users/erikkerber/Library/Developer/Xcode/DerivedData/MillMain-fngfqhlslygksgcfuciznkpqfrbr/Build/Products/Debug-iphonesimulator/libPods.a(Pods-dummy.o)
ld: 2 duplicate symbols for architecture i386

我想如果他们要添加一个AFNetworking依赖项,他们也会得到与AFNetworking相关的重复符号。

我计划最终用Cocoapods分发MyLib,但我也希望能够自己分发MyLib.framework。

有没有办法在我的库中使用Cocoapods,同时让Cocoapods对任何潜在用户都安全?

6 个答案:

答案 0 :(得分:16)

简而言之,分发预构建库的唯一好方法是,包括任何依赖项,但将其留给用户。即在您的示例中,您将指示您的用户如何将AFNetworking添加到他们的项目中。这同样适用于dummy文件。

话虽如此,您当然可以选择多种预建变体:

  • 包括所有依赖项。
  • 仅包含您的lib的源,将依赖项留给用户。

我们一直在讨论创建一个插件来生成独立的静态库,这是为了你想要的目的,但是还没有开始,可能需要更长的时间。 (直到有人/任何人有时间。)

作为一种解决方法,您可以使用Podfile的post_install hook来完全删除虚拟文件。 (这些仅适用于像Testflight这样的非源库。)例如。如下所示:

post_install do |installer|
  installer.project.targets.each do |target|
    source_files = target.source_build_phase.files
    dummy = source_files.find do |file|
      # TODO Fix this to the actual filename
      # puts "File: #{file.file_ref.name}"
      file.file_ref.name == 'TheDummyFile.m'
    end
    puts "Deleting source file #{dummy.inspect} from target #{target.inspect}."
    source_files.delete(dummy)
  end
end

这是未经测试的代码。

post_install挂钩生成CocoaPods安装程序对象,您可以从中获取Pods.xcodeproj目标,您可以从中找到文档here。从那里,您可以向下钻取并对项目执行任何操作,在运行此挂钩后将其保存到磁盘。

答案 1 :(得分:10)

我有同样的问题。我使用以下podfile格式管理我的库与cocoapods的依赖关系:

platform :ios, '6.0'
pod 'AFNetworking'

这导致我的.a文件中有一个Pods-dummy.o文件。如果我然后使用相同的podfile格式将此库包含在另一个项目中,则它们都会创建一个Pods-dummy.o符号并导致链接器错误。解决方案是使用不同的podfile格式,这将导致命名空间的Pods-dummy符号:

platform :ios, '6.0'
target "MyProject" do
    pod 'AFNetworking'
end

这会产生一个Pods-MyProject-dummy.o文件,该文件不会导致重复的符号。

注意:如果您将项目切换为使用新的podfile格式,请确保从项目中取消链接libPods.a,因为它会作为断开链接而挂起,因为新的pods库名为Pods-MyProject

答案 2 :(得分:5)

如果它们相同,您可以使用以下方法合并它们:

libtool (libtool -o merged.a file1.a file2.a)

如果这不能解决错误,则有以下选项: http://atnan.com/blog/2012/01/12/avoiding-duplicate-symbol-errors-during-linking-by-removing-classes-from-static-libraries

答案 3 :(得分:3)

参考http://guides.cocoapods.org/syntax/podfile.html#post_install& http://pdx.esri.com/blog/2013/12/13/namespacing-dependencies/

我使用'手动重命名所有符号'做法。我遇到了重复的符号_OBJC_METACLASS _ $ _ PodsDummy_Pods,所以我添加并编辑了Podfile中的post_install,以避免重复的符号

post_install do |installer_representation|
    installer_representation.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited), PodsDummy_Pods=SomeOtherNamePodsDummy_Pods'
        end
    end
end

答案 4 :(得分:0)

当我手动将一些外部代码添加到我的项目AFNetworking中时,我遇到了这个问题,例如,之后又添加了一些包含它的pod。

简单地从我自己的项目(而不是pod)中删除AFNetworking消除了这个问题。

答案 5 :(得分:-1)

将每个冲突符号的条目添加到您的其他C标志,例如" -DAFHTTPClient = AF2HTTPClient" Xcode Multiple Static Libraries and Duplicate Symbols