web-dev-qa-db-fra.com

Xcode 4 ne peut pas localiser les fichiers d'en-tête publics à partir d'une dépendance de bibliothèque statique

Autres titres pour faciliter la recherche

  • Xcode ne trouve pas l'en-tête
  • Manquant .h dans Xcode
  • Xcode .h fichier non trouvé
  • fichier de problème lexical ou du préprocesseur introuvable

Je travaille sur un projet d'application iOS issu de Xcode 3. Je suis maintenant passé à Xcode 4 et mon projet génère un certain nombre de bibliothèques statiques.

Ces bibliothèques statiques déclarent également des en-têtes publics et ces en-têtes sont utilisés par le code de l'application. Dans Xcode 3.x, les en-têtes étaient copiés (en tant que phase de construction) dans le public headers directory, puis dans le projet d’application, le public headers directory a été ajouté au headers search list.

Sous Xcode 4, le répertoire de construction est déplacé vers ~/Library/Developer/Xcode/DerivedData/my-project.

Le problème est de savoir comment référencer ce nouvel emplacement dans les paramètres de recherche des en-têtes. Il paraît que:

  • public headers directory est relatif au répertoire DerivedData, mais
  • headers search répertoire est relatif à quelque chose d'autre (éventuellement l'emplacement du projet)

Comment dois-je configurer une cible de bibliothèque statique pour le développement iOS dans Xcode 4 afin de garantir que les fichiers d'en-tête sont mis à la disposition des clients qui utilisent la bibliothèque statique lors d'une tentative de compilation en tant que dépendance?

91
rjstelling

Projet Xcode 4 ne réussit pas à compiler une bibliothèque statique

Question associée: "fichier de problème lexical ou de préprocesseur introuvable" dans Xcode 4

Les erreurs peuvent inclure: fichiers d'en-tête manquants, "problème lexical ou pré-processeur"

Solutions:

  1. Vérifiez que les "chemins d'en-tête de l'utilisateur" sont corrects
  2. Définissez "Toujours rechercher les chemins d'utilisateur" sur OUI
  3. Créez un appel de groupe "Indexation des en-têtes" dans votre projet et faites glisser les en-têtes vers ce groupe, NE PAS ajouter à toutes les cibles lorsque vous y êtes invité.
16
rjstelling

Chacune des solutions que j'ai trouvées à ce problème a semblé soit inélégante (copier les en-têtes dans le projet de l'application), soit trop simplifiée au point qu'elles ne fonctionnent que dans des situations triviales.

La réponse courte

Ajoutez le chemin suivant à votre chemins de recherche d'en-tête d'utilisateur

"$ (BUILD_ROOT) /../ IntermediateBuildFilesPath/UninstalledProducts"

Pourquoi ça marche?

Premièrement, nous devons comprendre le problème. Dans des circonstances normales, c'est-à-dire lorsque vous exécutez, testez, profilez ou analysez, Xcode construit votre projet et place la sortie dans la configuration Construire/Produits//Répertoire des produits, disponible via la macro $ BUILT_PRODUCTS_DIR.

La plupart des guides concernant les bibliothèques statiques recommandent de définir le paramètre chemin du dossier des en-têtes publics sur $ TARGET_NAME, ce qui signifie que votre fichier lib devient $ BUILT_PRODUCTS_DIR/libTargetName.a et vos en-têtes sont placés dans $ BUILT_PRODUCTS_DIR/TargetName. Tant que votre application inclut $ BUILT_PRODUCTS_DIR dans ses chemins de recherche, les importations fonctionneront dans les 4 situations indiquées ci-dessus. Toutefois, cela ne fonctionnera pas lorsque vous essayez d’archiver.

L'archivage fonctionne un peu différemment

Lorsque vous archivez un projet, Xcode utilise un autre dossier appelé ArchiveIntermediates. Dans ce dossier, vous trouverez/YourAppName/BuildProductsPath/Release-iphoneos /. Il s’agit du dossier $ BUILT_PRODUCTS_DIR lorsque vous créez une archive. Si vous regardez à l'intérieur, vous verrez qu'il existe un lien symbolique vers votre fichier de bibliothèque statique construit, mais le dossier avec les en-têtes est manquant.

Pour trouver les en-têtes (et le fichier lib), vous devez accéder à IntermediateBuildFilesPath/UninstalledProducts /. Rappelez-vous quand on vous a dit de configurer Ignorer l'installation sur OUI pour les bibliothèques statiques? Eh bien, c’est l’effet que ce paramètre produit lorsque vous créez une archive.

Note latérale: Si vous ne le configurez pas pour ignorer l'installation, vos en-têtes seront placés dans un autre emplacement et le fichier lib sera copié dans votre archive, vous empêchant ainsi d'exporter un fichier .ipa que vous pourrez soumettre à l'App Store. .

Après de nombreuses recherches, je n'ai trouvé aucune macro correspondant exactement au dossier UninstalledProducts, d'où la nécessité de construire le chemin avec "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath/UninstalledProducts"

Sommaire

Pour votre bibliothèque statique, veillez à ignorer l'installation et à placer vos en-têtes publics dans $ TARGET_NAME.

Pour votre application, définissez les chemins de recherche de votre en-tête d'utilisateur sur "$ (BUILT_PRODUCTS_DIR)", ce qui fonctionne bien pour les versions standard, et "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath/UninstalledProducts", qui fonctionne pour les versions d'archive.

125
Colin

Je rencontrais le même problème lorsque je développais ma propre bibliothèque statique et bien que la réponse de Colin fût très utile, je devais la modifier un peu pour fonctionner de manière cohérente et simple lors de l’exécution et de l’archivage de projets sous Xcode 4 avec un espace de travail.

Ce qui est différent avec ma méthode est que vous pouvez utiliser un chemin d’en-tête utilisateur unique pour toutes vos configurations de construction.

Ma méthode est la suivante:

Créer un espace de travail

  1. Sous Xcode 4, allez dans Fichier, Nouveau, Espace de travail.
  2. À partir du Finder, vous pouvez faire glisser les projets .xcodeproj à la fois pour la bibliothèque statique que vous souhaitez utiliser et pour la nouvelle application que vous créez, qui utilise cette bibliothèque. Voir Apple pour plus d'informations sur la configuration des espaces de travail: https://developer.Apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html )

Paramètres du projet de bibliothèque statique

  1. Assurez-vous que tous les en-têtes de la bibliothèque statique sont configurés pour être copiés sur "Public". Cette opération est effectuée dans les paramètres de la cible de la bibliothèque statique> Phases de construction. Dans la phase "Copier les en-têtes", assurez-vous que tous vos en-têtes figurent dans la section "Public".
  2. Ensuite, allez dans Paramètres de construction, trouvez "Chemin du dossier des en-têtes publics" et entrez le chemin de votre bibliothèque. Je choisis d'utiliser ceci:

include/Nom de la bibliothèque

J'ai adopté cette utilisation avec RestKit et je trouve que cela fonctionne mieux avec toutes mes bibliothèques statiques. Cela indique à Xcode de copier tous les en-têtes que nous avons déplacés vers la section "En-têtes" publics à l'étape 1 dans le dossier spécifié ici, qui réside dans le dossier Derived Data lors de la création. Comme avec RestKit, j'aime utiliser un seul dossier "include" pour contenir chaque bibliothèque statique que j'utilise dans un projet.

De plus, je n'aime pas utiliser les macros ici, car cela nous permettra d'utiliser un chemin de recherche d'en-tête à utilisateur unique ultérieurement, lorsque nous configurerons le projet à l'aide de la bibliothèque statique.

  1. Recherchez "Ignorer l’installation" et assurez-vous que cette option est définie sur OUI.

Paramètres du projet à l'aide de la bibliothèque statique

  1. Ajoutez la bibliothèque statique en tant que cadre sous Build Phases> Lier les fichiers binaires avec des bibliothèques et ajoutez le fichier libLibraryName.a à la bibliothèque statique que vous souhaitez utiliser.
  2. Assurez-vous ensuite que le projet est configuré pour rechercher des chemins de recherche d'utilisateurs. Cette opération est effectuée sous Paramètres de construction> Toujours rechercher les chemins d’utilisateur et assurez-vous qu’il est défini sur OUI.
  3. Dans la même zone, recherchez les chemins de recherche d’en-têtes d’utilisateur et ajoutez:

    "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts/include"

Cela indique à Xcode de rechercher des bibliothèques statiques dans le dossier de construction intermédiaire créé par Xcode au cours du processus de construction. Ici, nous avons le dossier "include" que nous utilisons pour nos emplacements de bibliothèque statiques que nous avons configurés à l'étape 2 pour les paramètres du projet de bibliothèque statique. Il s'agit de l'étape la plus importante pour que Xcode trouve correctement vos bibliothèques statiques.

Configurer l'espace de travail

Ici, nous voulons configurer l’espace de travail pour qu’il construise la bibliothèque statique lors de la création de notre application. Cela se fait en modifiant le schéma utilisé pour notre application.

  1. Assurez-vous que vous avez sélectionné le schéma qui créera votre application.
  2. Dans la liste déroulante Schéma, choisissez Edit Scheme.
  3. Sélectionnez Construire en haut de la liste à gauche. Ajoutez une nouvelle cible en appuyant sur le signe + du volet central.
  4. Vous devriez voir la bibliothèque statique apparaître pour la bibliothèque que vous essayez de lier. Choisissez la bibliothèque statique iOS.
  5. Cliquez sur Exécuter et archiver. Cela indique au système de compiler les bibliothèques pour la bibliothèque statique chaque fois que vous créez votre application.
  6. Faites glisser la bibliothèque statique au-dessus de votre cible d'application. Cela rend les bibliothèques statiques compilées avant la cible de votre application.

Commencer à utiliser la bibliothèque

Maintenant, vous devriez pouvoir importer votre bibliothèque statique en utilisant

import <LibraryName/LibraryName.h>

Cette méthode évite d'avoir à utiliser des chemins d'en-tête d'utilisateur différents pour des configurations différentes. Vous ne devriez donc pas rencontrer de problèmes de compilation pour les archives.

Pourquoi ça marche?

Tout dépend de ce chemin:

"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"

Dans la mesure où nous configurons notre bibliothèque statique pour utiliser "Ignorer l'installation", les fichiers compilés sont déplacés vers le dossier "UninstalledProjects" dans le répertoire de construction temporaire. Notre chemin d'accès ici résout également le dossier "include" que nous avons configuré pour notre bibliothèque statique et que nous utilisons pour notre chemin de recherche d'en-tête d'utilisateur. La collaboration des deux permet à Xcode de savoir où trouver notre bibliothèque pendant le processus de compilation. Comme ce répertoire de construction temporaire existe pour les configurations Debug et Release, vous n'avez besoin que d'un seul chemin pour Xcode afin de rechercher des bibliothèques statiques.

85
gdavis

C'était un fil très utile. En recherchant ma propre situation, j'ai constaté que Apple contient un document de 12 pages daté de septembre 2012 intitulé "Utilisation de bibliothèques statiques sous iOS." Voici le lien pdf: http://developer.Apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf

C'est beaucoup plus simple que la plupart des discussions sur Internet, et avec quelques petits mods pour expliquer la configuration des bibliothèques externes que j'utilise, cela fonctionne bien pour moi. La partie la plus importante est probablement:

Si votre cible de bibliothèque a une phase de construction "Copier les en-têtes", vous devez la supprimer. Les phases de construction des en-têtes de copie ne fonctionnent pas correctement avec les cibles de bibliothèque statiques lors de l'exécution de l'action "Archiver" dans Xcode.

Les nouvelles cibles de bibliothèques statiques créées avec Xcode 4.4 ou version ultérieure comportent une phase de copie des fichiers configurée de manière appropriée pour les en-têtes. Vous devez donc vérifier si vous en avez déjà un avant d'en créer un. Si vous ne le faites pas, appuyez sur "Ajouter la phase de construction" au bas de l'éditeur cible et choisissez "Ajouter les fichiers de copie". Indiquez la nouvelle phase de construction des fichiers de copie et définissez la destination sur "Répertoire de produits". Définissez le sous-chemin à inclure/$ {PRODUCT_NAME}. Cela copiera les fichiers dans un dossier nommé d'après votre bibliothèque (issu du paramètre de génération de PRODUCT_NAME), dans un dossier nommé include, dans votre répertoire de produits construits. Le dossier d'inclusion dans un répertoire de produits de construction se trouve dans le chemin de recherche par en-tête par défaut pour les applications. Il s'agit donc d'un emplacement approprié pour placer des fichiers d'en-tête.

Je suis sûr que dans de nombreuses situations existantes, l'approche d'Apple pourrait ne pas suffire. Je publie ce message ici pour tous ceux qui commencent tout juste leur périple sur le sentier du jardin de la bibliothèque statique - c’est peut-être le meilleur point de départ pour des cas simples.

15
Michael J.

http://developer.Apple.com/library/ios/#technotes/iOSStaticLibraries/Articles/creating.html

Per Apple documentation:

Votre bibliothèque aura un ou plusieurs fichiers d'en-tête que les clients de cette bibliothèque doivent importer. Pour configurer les en-têtes exportés vers les clients, sélectionnez votre projet de bibliothèque pour ouvrir l'éditeur de projet, sélectionnez la cible de la bibliothèque pour ouvrir l'éditeur de cible et sélectionnez l'onglet des phases de construction. Si votre cible de bibliothèque a une phase de construction "Copier les en-têtes", vous devez la supprimer. Les phases de construction des en-têtes de copie ne fonctionnent pas correctement avec les cibles de bibliothèque statiques lors de l'exécution de l'action "Archiver" dans Xcode.

4
dmarnel

Jetez un oeil à la solution de Jonah Wlliam (à mi-chemin) et au modèle GitHub (dans les commentaires) pour un aperçu. http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

3
d1bru

Dans mon cas, mon espace de travail comportait quelques projets de bibliothèque statiques et l’un d’eux dépendait de la dépendance, y compris des fichiers d’en-tête. Le problème était avec l'ordre de construction. Dans la page d'édition Scheme, dans la section Build, j'ai désélectionné l'option de parallélisation et organisé l'ordre des cibles en fonction des dépendances. Le problème a été résolu.

2
Vamshi

Ajoutez ($ (OBJROOT)/UninstalledProducts/exactPathToHeaders au chemins de recherche d'en-tête.

Pour une raison quelconque, la case à cocher récursive ne fonctionnait pas pour moi et j'ai dû ajouter le reste du chemin d'accès à l'emplacement des en-têtes.

Sous le Navigateur de journaux dans Xcode (l'onglet à droite du navigateur de points d'arrêt), vous pouvez voir l'historique de construction. Si vous sélectionnez l’échec de construction réel, vous pouvez développer ses détails pour afficher setenv PATH et vérifier que le chemin de vos fichiers d’en-tête est présent.

2
Collin

Au risque de montrer quel idiot je suis ... Je souffre du fait que XCode refuse de retrouver mes fichiers .h tout l’après-midi.

Puis j'ai réalisé.

Parce que j'utilisais "XCode 4", j'avais "intelligemment" décidé de placer tous mes projets dans un sous-dossier d'un dossier nommé "projets XCode 4".

Ces espaces dans le nom du dossier ont tout gâché XCode!

Renommer ce dossier en "XCode_4_Projects" a ramené la joie (et moins de jurons) dans ma vie.

Rappelez-moi à nouveau, quelle année est-ce?

Peut-être que quelqu'un pourrait dire aux Apple développeurs ...

1
Mike Gledhill

Aucune des réponses ci-dessus n'a fonctionné pour moi sur Xcode 7, mais ils m'ont cependant donné une bonne idée. Pour les gars qui luttent sur Xcode 7, j'ai résolu ce problème en ajoutant ce qui suit aux chemins de recherche de l'en-tête de l'utilisateur (y compris les guillemets)

"$(BUILT_PRODUCTS_DIR)/usr/local/include"

Changer la partie d'URL relative usr/local/include selon ce qu'il y a dans le paramètre 'Public Header Folder Path' de la bibliothèque statique

1
Evol Gate

Aucune de ces réponses n'a fonctionné pour moi. Voici ce qui a fait. Ajoutez exactement les éléments suivants (copier/coller, y compris les guillemets) à votre paramètre de construction Chemins de recherche d'en-tête d'utilisateur:

"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/"

Notez l'ajout du sous-répertoire "/ include /" par rapport aux autres réponses. Comme d'autres utilisateurs l'ont souligné, l'option "récursive" ne semble rien faire, vous pouvez donc l'ignorer.

Mon projet était désormais capable d'archiver avec succès lors de l'importation de fichiers d'en-tête de bibliothèque statiques sous la forme suivante:

#import "LibraryName/HeaderFile.h"

Vous faites pas devez activer le paramètre Toujours rechercher les chemins utilisateur sauf si vous incluez vos en-têtes de bibliothèque statiques avec des crochets angulaires (#import <LibraryName/HeaderFile.h>), mais vous ne devriez vraiment pas le faire de cette façon si ce n’est pas un en-tête système/framework.

1
devios1

Ajoutez le chemin suivant à vos chemins de recherche d'en-tête d'utilisateur:

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

Ceci est vérifié!

1
yirenjun

Voici ce qui a résolu le même problème pour moi.

J'ai une cible d'application et une cible d'extension iMessage. Ensuite, j'ai eu 2 SDK (le mien), contre lesquels l'App Target fait référence.

Le problème était le suivant: ma cible iMessage utilisait également les 2 SDK du mien (projets distincts), mais elle ne faisait pas le lien entre eux dans Build Phases -> Link Binary With Libraries. Je devais ajouter mes 2 SDK à la cible iMessage pour correspondre à la cible de mon application, et maintenant, il archive.

La morale de l'histoire est donc la suivante: Si vous avez plusieurs cibles, telles que des extensions, assurez-vous que toutes vos cibles sont liées aux bibliothèques dont elles ont besoin. Il était capable de construire et de déployer sur le simulateur et le périphérique, mais pas d'archiver.

0
FranticRock

Il existe différentes manières complexes de le faire, et certaines solutions très intelligentes sont proposées dans ce fil.

Le principal problème de toutes ces solutions est qu’elles réduisent considérablement la portabilité de votre bibliothèque.

  • Chaque fois que vous devez démarrer un nouveau projet à l'aide de votre bibliothèque et l'archiver pour iTunes, c'est un enfer de configuration.
  • Chaque fois que vous souhaitez partager votre projet avec votre équipe ou vos clients, celui-ci peut échouer pour quelque raison que ce soit (contexte, version de Xcode, etc.).

Mon choix a finalement été d’utiliser simplement des cadres - toujours - comme recommandé par Apple (vidéos WWDC)).

C'est tellement plus facile et fait le même travail à la fin!

Une autre solution assez élégante qui semble fonctionner est l’utilisation de Private Cocoapods. Cocoapods effectue tout le travail de configuration, copie d'en-tête, etc.

Les cadres rock!

0
Moose

C’est un problème connexe qui m’a amené à cette question; j’ajoute donc ma solution strictement pour la documentation/cela permettrait d’économiser une âme supplémentaire en transpirant

Fichier DropboxSDK.h introuvable

Après des jours d’essai de compilation de VES pour iOS, j’ai rencontré ce problème. le DropboxSDK.h était définitivement à la portée de search headers Je l'ai même ajouté au chemin de recherche framework headers, include d le .h directement à toutes sortes de choses pour essayer de trouver DropboxSDK.h.

Solution

EXPLICITE faites glisser le fichier DropboxSDK.framework dans le fichier Project Navigation de Xcode et assurez-vous que Copy Files if needed est coché. Assurez-vous également que votre cible est cochée au besoin.

Avertissement

La définition de l'emplacement du cadre explicite dans build phases N'a pas fonctionné pour moi. Je devais faire glisser le .framework dans Xcode et m'assurer que les fichiers étaient copiés dans mon projet.

# mbp2015 # xcode7 # ios9

0
Jacksonkr

Mise à jour: Xcode 9

Les réponses ci-dessus ne fonctionnaient pas pour moi avec Xcode 9, mais ceci réponse fonctionnait parfaitement pour moi. J'ai ajouté $(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include à mes "chemins de recherche d'en-tête" et Xcode a lié l'en-tête de ma bibliothèque statique sans aucun problème.

0
Mohammed Abdullatif