web-dev-qa-db-fra.com

Empêcher les symboles en double lors de la construction d'une bibliothèque statique avec Cocoapods

Bien que j'aie rencontré de nombreuses questions concernant les Cocoapods et les bibliothèques statiques, la plupart d'entre elles semblent supposer que vous disposerez éventuellement d'un seul espace de travail avec votre bibliothèque statique et votre application cible finale.

Dans mon scénario, je construis une bibliothèque statique. Plus précisément, je pirate un cadre MyLib.fr pour que les utilisateurs le consomment. Je voudrais {vraiment} _ gérer les dépendances de MyLib.framework avec les Cocoapods, mais cela crée de nombreux problèmes lorsque les utilisateurs de ma bibliothèque aussi utilisent des Cocoapods.

Par exemple, ma bibliothèque a une dépendance AFNetworking que je gère avec Cocoapods. Lorsque je construis ma bibliothèque, cela crée un lien dans libPods.a, qui inclut AFNetworking, ainsi que des fichiers/objets "factices". Si les utilisateurs de mon framework utilisent également Cocoapods pour construire leur app, ils verront quelque chose comme ceci:

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

J'imagine que s'ils ajoutaient une dépendance à AFNetworking, ils obtiendraient également des symboles en double relatifs à AFNetworking.

Je prévois de distribuer éventuellement MyLib avec Cocoapods, mais je souhaite également pouvoir distribuer lui-même un fichier MyLib.framework.

Existe-t-il un moyen d'utiliser Cocoapods avec ma bibliothèque tout en protégeant les Cocoapods pour tout utilisateur potentiel?

21
Erik Kerber

En bref, le seul bon moyen de distribuer des bibliothèques prédéfinies est de not , y compris l’une des dépendances, mais en laissant cela à l’utilisateur. C'est à dire. dans votre exemple, vous indiqueriez à vos utilisateurs comment ajouter également AFNetworking à leur projet. Il en va de même pour les fichiers dummy.

Cela dit, vous pouvez bien sûr opter pour plusieurs variantes préconfigurées:

  • Inclure toutes les dépendances.
  • N'incluez que le code source de votre bibliothèque, laissez les dépendances à l'utilisateur.

Nous avons parlé de créer un plug-in pour produire des bibliothèques statiques autonomes, dans le but que vous souhaitez, mais cela n’a pas encore commencé et prendra probablement un peu plus de temps. (Jusqu'à ce que quelqu'un/quelqu'un ait le temps.)

Pour résoudre ce problème, vous pouvez utiliser le fichier post_install hook de votre Podfile pour supprimer complètement les fichiers factices. (de toute façon, ceux-ci ne sont nécessaires que pour les bibliothèques non-source comme Testflight.) E.g. quelque chose comme ce qui suit:

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

_ {C'est du code non testé.

Le hook post_install renvoie l'objet d'installation de CocoaPods, à partir duquel vous pouvez obtenir les cibles Pods.xcodeproj, pour lesquelles vous pouvez trouver la documentation ici . À partir de là, vous pouvez accéder au projet et y faire ce que vous voulez. Celui-ci est enregistré sur le disque après l'exécution de ce hook.

15
alloy

J'ai eu le même problème. J'ai géré les dépendances de ma bibliothèque avec des cocoapodes en utilisant le format de fichier podfile suivant:

platform :ios, '6.0'
pod 'AFNetworking'

Cela a abouti à un fichier Pods-dummy.o dans mon fichier .a. Si j'inclus ensuite cette bibliothèque dans un autre projet utilisant le même format de fichier podfile, ils créent tous deux un symbole Pods-dummy.o et génèrent une erreur de l'éditeur de liens. La solution consiste à utiliser un autre format de fichier podfile, ce qui donne un symbole Pods-dummy:

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

Il en résulte un fichier Pods-MyProject-dummy.o, qui ne créera pas de symboles en double.

Remarque: si vous basculez votre projet vers le nouveau format de fichier podfile, veillez à dissocier libPods.a de votre projet, car il restera comme un lien brisé car la nouvelle bibliothèque de pods s'appelle Pods-MyProject.

10
eliasbagley

S'ils sont identiques, vous pouvez les fusionner en utilisant:

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

Si cela ne résout pas le problème, voici l'option: http://atnan.com/blog/2012/01/12/avoiding-duplicate-symbol-errors-during-linking-by -removing-classes-from-static-libraries

5
Jeremiah Smith

Avec la référence de http://guides.cocoapods.org/syntax/podfile.html#post_install & http://pdx.esri.com/blog/2013/12/13/namespacing-dependencies/

J'utilise l'approche 'Renommer manuellement tous les symboles'. J'éprouvais le symbole en double _OBJC_METACLASS _ $ _ PodsDummy_Pods et j'ai donc ajouté et modifié le post_install dans le fichier podfile de manière à éviter le symbole en double.

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
3
chinweekoh

Ce problème est survenu lorsque j’ai ajouté manuellement du code externe à mon projet AFNetworking, par exemple, puis que j’ai ajouté plus tard des pods l’incluant également. 

Le simple fait de supprimer AFNetworking de mon propre projet (et non du module) a éliminé le problème.

0
Bill Noto