Erreur du compilateur Swift: «en-tête non modulaire à l'intérieur du module de structure»

204

Maintenant, je voudrais migrer mon framework ObjC vers Swift et j'ai eu l'erreur suivante:

include of non-modular header inside framework module 'SOGraphDB'

Les références sont à un fichier d'en-tête qui définit simplement un protocole et j'utilise ce fichier d'en-tête dans certaines classes pour utiliser ce protocole.

Cela semble lié à la fonctionnalité du module mais il n'est pas encore clair comment résoudre ce problème, connaissez-vous une solution?

METTRE À JOUR:

Il s'agit d'une erreur du compilateur Swift.

MISE À JOUR 2:

Une solution rapide (mais ne résolvant pas la cause première) consiste à définir le paramètre suivant sur oui: CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES

Stephan
la source
3
Il semble qu'il y ait un nouveau paramètre de construction pour "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES"
Stephan
1
Quelqu'un at-il vu cela sur des inclusions publiques et modulaires? Je vois cela avec un projet vanilla (cocoapods): github.com/CocoaPods/CocoaPods/issues/3092 et dropbox.com/s/trhe5vwhzoa9bf5/…
Chris Conover
Quelqu'un a-t-il créé un script rapide qui permet cela automatiquement?
fatuhoku
@fatuhoku yeah
funroll
Aucune de ces solutions n'a fonctionné pour moi, il semble que ce soit une collision bolts.framework dans mon cas. Le supprimer a résolu le problème: stackoverflow.com/a/33114309/3324388
Aggressor

Réponses:

316

Votre en-tête est-il public?

Sélectionnez le fichier d'en-tête dans l'explorateur de projet. Ensuite, dans la section à droite dans xcode, vous remarquerez qu'il y a une liste déroulante à côté de la cible. Changez cela de "projet" en "public". Cela a fonctionné pour moi.

en-tête public

kgreenek
la source
J'accepte cette réponse même si c'est la même que je l'ai dit.
Stephan
Vous pouvez également accéder à la phase de création des en-têtes de votre infrastructure et voir rapidement quels en-têtes sont publics, projet et privés.
Jose Ibanez
Je ne pensais pas que cette tâche simple pourrait être la solution car j'avais combattu avec cela pendant plus d'une heure avant de venir ici à SO. Et voilà, c'était EXACTEMENT la solution et a fonctionné immédiatement.
TMc
1
Et si je veux que ces en-têtes soient internes?
Raphael
2
Cela résout également mon problème! Dans mon cas, mon pod qui dépend d'un autre pod ne peut pas l'importer en raison d'un problème modulaire. J'ai donc fait quelques en-têtes inclus comme cible pour un autre pod, en utilisant le mode public. Et cela résout le problème!
Chen Li Yong
135

Il s'agit d'un comportement de compilateur attendu et pour une très bonne raison.

Je pense que la majorité des gens qui courent dans ce problèmes est dû après passer de Application Targetà Framework Targetet commencer à ajouter C et en- têtes Objective C dans de cadre en- tête parapluie attendant qu'il ait un même comportement que Bridging - tête de l' application , qui se comporte différemment. L'en-tête de parapluie est en fait désigné pour le cadre mixte rapide et obj-c et son but est d'exposer les API au monde extérieur que votre cadre a en objectif-c ou c. Cela signifie que les en-têtes que nous y mettons devraient être de portée publique.

Il ne doit pas être utilisé comme un endroit qui expose les en-têtes Objective-C / C qui ne font pas partie de votre framework au code rapide de votre framework. Parce que dans ce cas, ces en-têtes seront également exposés dans le cadre de notre module de cadre au monde extérieur, ce qui n'est souvent pas ce que nous voulons faire car il rompt la modularité. (Et c'est exactement la raison pour laquelle Autorise les modules non modulaires inclus dans le cadre des modules par défaut à NO )

Afin d'exposer la bibliothèque Objective-C / C à votre code Swift de framework, nous devons définir un module Swift distinct pour cette bibliothèque. Ensuite, un swift standard import YourLegacyLibrarypeut être utilisé.

Permettez-moi de le démontrer sur un scénario typique: l'intégration libxml2dans notre cadre.

1. Vous devez d'abord créer un module.modulemapfichier qui ressemblerait à ceci:

Pour le framework OSX:

module SwiftLibXML2 [system] {
  header "/usr/include/libxml2/libxml/xpath.h"
  export *
}

Pour le framework iOS:

module SwiftLibXML2 [system] {
  header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/libxml2/libxml/xpath.h"
  export *
}

Tout ce qu'il fait, c'est qu'il enveloppe l'en-tête et tous les autres en-têtes auxquels il fait référence dans le module swift, afin que swift puisse ensuite générer les liaisons swift pour ces interfaces C.

2. Ensuite, dans votre répertoire de projet xcode, créez un dossier SwiftLibXML2et placez-y ce module.modulemap

3. Dans Build Settings , ajoutez $(SDKROOT)/usr/include/libxml2aux en- têtes des chemins de recherche

4. Dans Build Settings , ajoutez $(SRCROOT)/SwiftLibXML2à Import Paths

5. Sous l' onglet Général du projet , ajoutez-le libxml2.tbdaux cadres et bibliothèques liés .

Maintenant, vous importez ce module si nécessaire avec:

import SwiftLibXML2

(si vous voulez regarder un exemple de module.map plus complet, je suggérerais de référencer le module.modulemap de Darwin à /usr/include/module.modulemap, vous auriez besoin d'avoir des outils de ligne de commande Xcode installés pour y aller, référence Missing / usr / include dans OS X El Capitan )

lumière ambiante
la source
1
Le nom du fichier module.mapest obsolète, il doit être renommé module.modulemap clang.llvm.org/docs/Modules.html#attributes
Hyperbole
Comment import SwiftLibXML2dans Objective-C? Merci!
Itachi
de la même manière que pour toute autre importation obj-c: #import <libxml / xpath.h> mais assurez-vous d'avoir fait les étapes 3 à 5.
ambientlight
Nous l'avons fait, mais l'artefact de génération ne peut pas être déplacé entre les machines: le module (sous) Objective-C est apparemment lié à l'aide de chemins absolus, ce qui provoque des erreurs lors de la compilation, par exemple, d'une application qui utilise le framework que vous avez fourni.
Raphael
l'erreur est probablement propre à votre processus de construction, il s'agit simplement d'une définition de module afin que les langages llvm qui prennent en charge les modules puissent interagir avec d'autres, je ne pense pas que cela puisse affecter en soi vos artefacts de construction, que la communauté me corrige si je me trompe
ambientlight
55

Voici comment appliquer automatiquement le correctif rapide afin que vous n'ayez pas à modifier Pods.xcodeprojmanuellement après chaque pod install.

Ajoutez cet extrait à la fin de votre Podfile:

post_install do |installer|
  installer.pods_project.build_configuration_list.build_configurations.each do |configuration|
    configuration.build_settings['CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'] = 'YES'
  end
end
funroll
la source
29

La solution pour moi était d'aller sur la cible -> les paramètres de construction -> Autoriser les inclusions non modulaires dans le commutateur des modules de structure sur OUI!

Vlad Burlaciuc
la source
A également travaillé avec Cocoapods ici. Pas besoin de faire la magie de l'autre réponse après l'installation du pod
brainray
3
J'ai fait cette étape .. cela a fonctionné pendant un certain temps .. et maintenant cela ne fonctionne pas ... J'ai également inclus l'étape d'installation des pods. Mais il échoue à nouveau. Autre chose que je devrais vérifier? Je ne vois pas GoogleMobileAds.Framework comme une option pour changer les en-têtes en Public.
Michael Rowe
Ça n'a pas marché pour moi. Toujours l'erreur avec Parse. Xcode 7.3.1
C0D3
J'ai dû redémarrer XCode après avoir effectué cette modification pour que cela fonctionne.
John Fowler
1
Quel est l'impact de la modification de ce paramètre?
nr5
15

Je pense que j'ai contourné cela. J'ai du code modèle qui utilise sqlite3 dans un framework. Dans mon cas, le coupable était <sqlite3.h>.

Le problème était que dans mon en-tête Module / Module.h, j'avais importé un en-tête public qui importait <sqlite3.h>. La solution consistait à masquer tous les types sqlite3_xxx et à s'assurer qu'ils n'étaient visibles dans aucun .h public. Toutes les références directes à sqlite3 ont été rendues privées ou visibles par le projet. Par exemple, j'avais un singleton public avec des pointeurs sqlite3_stmt accrochés. J'ai déplacé ceux-ci dans une classe distincte qui n'est maintenant qu'une déclaration directe dans cet en-tête public. Maintenant je peux construire.

Par ailleurs, le paramètre CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES n'a pas fonctionné. J'ai essayé de le placer à la fois dans le cadre et le projet dépendant. Cette solution de contournement était nécessaire, mais je ne sais pas pourquoi.

Jimmy Dee
la source
Cela a totalement aidé! Dans mon cas, c'était l'accessibilité.
Daniel Brim
4
Je suis presque sûr que c'est la solution à mon problème lorsque j'essaie d'inclure SSZipArchive dans mon module de framework. L'en-tête public est en train d'importer <zlib.h> et donne la même erreur. Pouvez-vous publier votre code source quelque part parce que j'ai du mal à le faire fonctionner car je ne comprends qu'une partie de votre réponse .. merci!
Bruce
15

Dans Swift :

1. Modifiez les paramètres de construction de votre projet Xcode et de vos cibles comme indiqué ci-dessous:

Autoriser les modules non modulaires inclus dans le cadre: Non

Activer le Bitcode: Oui

2. Utilisez la dernière version actuelle disponible pour le SDK iOS GoogleMaps (utilisez CocoaPods pour l'obtenir):

GoogleMaps (1.10.4)

3. Commentez l'importation problématique:

//import GoogleMaps

4. Créez ou modifiez votre fichier d'en-tête de pontage, en ajoutant l'importation problématique:

[Nom de votre projet Xcode] -Bridging-Header.h

// Use this file to import your target's public headers 
// that you would like to expose to Swift.
#import <GoogleMaps/GoogleMaps.h>

5. Nettoyez et reconstruisez votre projet Xcode.

Roi-sorcier
la source
1
Cela aide beaucoup! Fonctionne également très bien avec le cadre GoogleMobilAds (avec Cocoapods)
bluenowhere
pour plus d'informations sur la création du fichier d'en-tête, voir: stackoverflow.com/a/51227304/529663
lenooh
6

Cette réponse est dépassée.

Lors de l'importation de frameworks, vous devez importer tous les fichiers d'en-tête qui partagent des dépendances avec l'en-tête racine. Le moyen le plus simple de vous assurer que cela fonctionne toujours consiste à importer tous les en-têtes du dossier "En-têtes" du framework dans votre chemin d'en-tête public.

entrez la description de l'image ici

Le compilateur Swift utilise ces informations pour générer une carte de symboles non modifiés avec leurs informations de type associées.

seo
la source
Cela semble aller à l'encontre du but d'avoir les fichiers Framework, mais cela a fonctionné pour moi. Chartboost et RevMob ont récemment commencé à utiliser des fichiers Framework au lieu de seulement des bibliothèques. Tout copier de leurs en-têtes vers les en-têtes de mon application résout le problème.
Jason Short
Est-ce la seule solution? J'ai 6 cadres et chaque cadre a environ 20 en-têtes. Cela crée un gâchis. Un suppléant?
vivin
1
Plus que probable. Ce n'est probablement plus pertinent car il s'agissait d'une solution de contournement dans un bogue Xcode.
seo
6

Ne le fais pas

#import "MyOtherFramework.h"

Faire

#import <MyOtherFramework/MyOtherFramework.h>
hfossli
la source
3

Le fichier d'en-tête a été alloué à la cible mais n'a été marqué que comme projet visible, un simple changement de public a permis de résoudre cette erreur.

Stephan
la source
Comment puis-je faire exactement cela? J'ai des problèmes avec mes fichiers d'en-tête TwitterKit
Vinod Sobale
2

Je sais que c'est une vieille question, mais j'ai eu le même problème et rien d'en haut ne m'a aidé. J'espère donc que ma réponse sera utile à quelqu'un. Dans mon cas, le problème était dans le paramètre ALWAYS_SEARCH_USER_PATHS. Quand il a été défini sur NO, le projet a été construit et a fonctionné correctement. Mais dans la mesure où l'un des pods exigeait qu'il soit réglé sur OUI, je recevais une erreur

Inclure un en-tête non modulaire à l'intérieur du module de structure

Après quelques tasses de café et des recherches toute la journée, j'ai découvert que, selon les problèmes connus des notes de version de Xcode 7.1 Beta 2 :

• Si vous obtenez une erreur indiquant «Inclure l'en-tête non modulaire à l'intérieur du module de cadre» pour un cadre qui a été compilé précédemment, assurez-vous que le paramètre de génération «Toujours rechercher les chemins utilisateur» est défini sur «Non». La valeur par défaut est "Oui" uniquement pour des raisons héritées. (22784786)

J'utilisais cependant XCode 7.3, mais il semble que ce bogue n'ait pas encore été corrigé.

iyuna
la source
C'est ça qui m'a aidé! J'ai dû changer certaines importations après être passé à NO mais maintenant j'ai pu importer mon framework nécessaire!
Pavel Gurov
2

Basculer les paramètres de build> Autoriser les inclusions non modulaires dans les modules Framework à YES! résolu le même problème pour moi.

Mohamed TAIEB
la source
2

Je voudrais également ajouter mon expérience avec le problème.

Juste pour résumer:

  • La réponse de @ ambientlight est excellente et elle résout la plupart des problèmes.
  • autoriser les en-têtes non modulaires est une autre solution (voir certaines des réponses ci-dessus).
  • marquer les en-têtes du framework comme publics (uniquement ceux que vous souhaitez exposer) et les importer dans l'en-tête parapluie.

Voici mes 2 ajouts aux réponses ci-dessus:

  • vérifiez soigneusement les importations dans votre projet pour les en-têtes qui importent vos cadres directement dedans (au lieu d'utiliser la déclaration directe, si possible) - ce n'est pas une bonne pratique d'inclure un fichier d'en-tête dans un autre fichier d'en-tête; Parfois, cela pose problème, car s'il n'est pas fait correctement, cela peut entraîner plusieurs inclusions d'un en-tête et créer des problèmes de l'éditeur de liens.
  • MISE À JOUR: assurez-vous que les architectures de la bibliothèque et celle de la cible que vous souhaitez lier correspondent.
  • et enfin, après avoir fait tout ce qui précède, j'ai continué à me cogner sur cette erreur. J'ai donc creusé un peu plus et trouvé (dans les forums de développeurs Apple, mais j'ai perdu le lien :() que si vous incluez les en-têtes dans l'en-tête du parapluie pas comme ça <framework/headerName.h>, mais seulement comme ça "headerName.h", le problème disparaît.

J'ai essayé cette dernière, et jusqu'à présent, je n'ai plus rencontré ce problème, mais je soupçonne que cette solution n'est valide que si vous avez appliqué certaines des meilleures réponses (remarque: elles ne sont pas toutes compatibles les unes avec les autres, par exemple , l'approche du module et l'autorisation de l'en-tête non modulaire incluent).

Georgi Boyadzhiev
la source
1

J'ai eu ce problème exact lors de l'inclusion de mon propre cadre dans un projet. Le problème a été résolu en plaçant toutes les importations de sqlite3.h dans des fichiers .m et non dans des fichiers publics .h. Je suppose que d'autres bibliothèques peuvent signaler des problèmes similaires avec Xcode.

Rob Sanders
la source
1

J'ai eu le problème spécifique avec Facebook 4.02 sdk et FBSDKCoreKit.

J'ai fait toutes les étapes mais toujours une erreur sur l'en-tête non modulaire. J'ai fait glisser et déposé uniquement l'en-tête spécifique du cadre pour créer des phases-> section d'en-tête.

Puis créé automatiquement une copie de l'en-tête sur le navigateur de projet en haut.

Je l'ai supprimé des phases de construction -> en-tête et supprimé le nouveau fichier et a bien fonctionné.

Comme si c'était réinitialisé ou quelque chose.

Haris
la source
1

Dans mon cas (Xcode 9 beta 6 - Swift 4 - utilisant des Cocoapods), cela a été résolu lorsque j'ai supprimé Podfile.lock et le répertoire Pods et que j'ai exécuté de pod installnouveau

m_katsifarakis
la source
1

J'ai eu ce problème après avoir mis à jour un projet de swift2 vers swift3. J'utilisais XCode 8.3.2 pour mettre à jour le code et je n'ai pas pu me débarrasser de l'erreur «en-tête non modulaire à l'intérieur du module de framework». Lorsque j'ai ouvert le même projet dans une autre version de XCode (version 9.0.1), l'erreur ne s'est pas produite.

DevB2F
la source
0

Le plus souvent, cette erreur est due à la réponse choisie, mais cette erreur s'est produite une fois par accident lors du glissement des fichiers de framework dans mon nouveau dossier de projet. J'ai cliqué pour supprimer les frameworks, mais j'ai accidentellement appuyé pour ne supprimer que les références aux frameworks plutôt que de supprimer complètement les fichiers. À ce stade, si j'ouvrais mon dossier de projet dans le Finder, j'y voyais des fichiers comme «CoreLocation» et «AudioToolbox». La suppression de ces fichiers du dossier du projet et le nettoyage du projet ont résolu le problème.

ColossalChris
la source
0

Après avoir autorisé l'importation d'importations non modulaires, vous pouvez essayer d'importer ce module à l'aide de l'en-tête de pontage Objective-C:

#import <YandexMobileMetrica/YandexMobileMetrica.h>
Yuri Korshev
la source
0

Je l'ai résolu en supprimant le Modulesdossier du cadre.

  • Accédez à l'emplacement de votre framework qui est présent dans le projet d'application à l'aide du Finder

  • Allez dans le Test.frameworkdossier (dans le cas ci-dessus, ce sera le cas SOGraphDB.framework) et supprimez le Modulesdossier.

  • Nettoyez et reconstruisez l'application, cela résoudra le problème.

Vittal Pai
la source
-1

J'ai eu ce problème lors de l'importation du framework Parse. La seule façon de le corriger était de supprimer toutes mes modifications depuis mon dernier commit (simplement supprimer le framework et nettoyer le projet n'a pas fonctionné) et ajouter à nouveau Parse (après un nouveau téléchargement du SDK) avec ses autres frameworks requis.

amurray4
la source