29 votes

Utilisation de bibliothèques statiques C/C++ à partir d'applications iPhone ObjectiveC

Est-il possible d'avoir une API de bibliothèque statique en C, qui utilise le C++ en interne et de le cacher aux utilisateurs de la bibliothèque ?

J'ai écrit une bibliothèque C++ portable que je souhaite lier statiquement à une application iPhone.

J'ai créé un projet Xcode en utilisant le modèle de "bibliothèque statique" de Max OS X, et j'ai copié la source à travers, ainsi que l'écriture d'un wapper C (pour gérer les exceptions) en utilisant (extern "C").

J'essaie d'utiliser la bibliothèque générée (fichier .a) dans une autre application Cocoa pour iPhone.

Tout fonctionne bien si j'utilise des extensions (.mm) sur le fichier ObjectiveC appelant et (.cpp) sur la classe d'implémentation dans la bibliothèque.

Mais j'obtiens des symboles non résolus lors de l'établissement de liens lorsque j'essaie de transformer le fichier d'emballage en une extension (.c), même si tous les fichiers de fonctions d'emballage sont uniquement des fonctions C.

Le fait que le C++ soit utilisé en interne dans une bibliothèque signifie-t-il qu'en externe, elle doit toujours être traitée comme un programme C++ ? N'y a-t-il pas moyen d'imposer cette abstraction ?

Editar: Merci pour les réponses,

J'avais utilisé extern "C", mais je n'étais pas sûr des configurations nécessaires dans le projet appelant. Par exemple, si le projet appelant avait besoin de savoir s'il utilisait C++ ou pouvait être ignorant et penser qu'il s'agissait d'une bibliothèque purement C.

Il semblerait que je ne puisse pas, et que je doive utiliser des fichiers (.mm) sur mes classes ObjectiveC.

34voto

Jason Coco Points 52303

Il est trop difficile de le faire dans les commentaires, je vais donc vous montrer rapidement quels sont les problèmes de liaison que vous rencontrez. Lorsque Xcode rencontre des fichiers, il utilise des règles de construction basées sur le suffixe pour décider du compilateur à utiliser. Par défaut, gcc lie les fichiers à la bibliothèque C standard, mais ne les lie pas à la bibliothèque C++ standard. Les fichiers d'archive (bibliothèques statiques) n'ont aucune résolution de liaison effectuée. Il s'agit essentiellement d'une archive de fichiers d'objets que doivent être liés . Comme vous n'avez pas de fichiers .mm ou .cpp dans votre projet, g++ n'est jamais appelé et vos fichiers ne sont jamais liés aux bibliothèques standard. Pour corriger cela, ajoutez simplement les bibliothèques C++ standard à vos autres drapeaux d'éditeur de liens dans votre projet Xcode, ou ajoutez-les simplement à l'option prédéfinie other flags comme -l (par exemple, -lstdc++).

Voici une démonstration rapide :

stw.h :

#ifdef __cplusplus
extern "C"
#endif
void show_the_world(void);

stw.cpp :

#include <iostream>
#include "stw.h"
using namespace std;

extern "C" void show_the_world() {
  cout << "Hello, world!\n";
}

Construisez la bibliothèque :

$ g++ -c stw.cpp -o stw.cpp -O0 -g
$ ar rcs stw.a stw.o

Utilisation de la bibliothèque à partir d'une application C :

myapp.c :

#include "stw.h"

int main() {
  show_the_world();
  return 0;
}

Construction de l'application C :

$ gcc -o myapp myapp.c stw.a -lstdc++ -g -O0
$ ./myapp
Hello, world!
$

Si vous essayez de compiler sans le -lstdc++ vous obtiendrez tous les problèmes non résolus parce que le compilateur C n'a absolument AUCUNE idée qu'il devrait lier au runtime C++ (et pourquoi le ferait-il, n'est-ce pas !?!?) donc vous devez l'ajouter manuellement. L'autre option que vous avez est de changer la règle de construction de votre projet... au lieu que Xcode utilise gcc pour construire les fichiers .c et .m, dites-lui d'utiliser g++ et vos problèmes seront résolus.

2voto

coppro Points 10692

Vous devez déclarer les fonctions que vous voulez rendre visibles extern "C" . Leur signature doit être compatible avec le langage C, mais pas leur contenu (vous pouvez accéder aux objets C++, par exemple, mais vous ne pouvez pas les transmettre directement ; les pointeurs sont acceptés). Les symboles seront alors visibles dans tout environnement compatible C.

EDIT : Et compilez-le comme un fichier source C++, le C n'a pas la notion de lien de langage. Il y a quelques autres problèmes avec la liaison de langage (comme le fait que tous les fichiers C++ doivent être compilés en C++). extern "C" les fonctions ayant le même nom sont la même fonction, indépendamment de l'espace de noms).

EDIT2 : Dans l'en-tête, vous pouvez vérifier la présence de la macro __cplusplus et l'utiliser pour définir le C++ et les autres langages, respectivement (parce que le C++ nécessitera l'utilisation de extern "C" et les autres langues s'en plaindront probablement).

1voto

Loki Astari Points 116129

En fait, lorsque vous compilez les fonctions C avec un compilateur C++, celui-ci modifie les noms des fonctions et utilise l'ABI C++.

Lorsque vous utilisez l'extension *.cpp ou *.mm, vous utilisez le compilateur C++.

Ce que vous voulez faire, c'est forcer le compilateur à générer des fonctions C avec des noms non-mangles et en utilisant l'ABI C.

Vous pouvez le faire de deux façons :

  • Compilez avec le compilateur C.
  • Compilez avec le compilateur C++ mais assurez-vous de préfixer les déclarations de fonctions avec extern "C".

Une façon préférée de configurer le fichier d'en-tête, afin que le même fichier puisse être inclus dans les fichiers sources C et C++, est la suivante :

#ifndef HEADER_GUARD_1_H
#define HEADER_GUARD_1_H

#ifdef __cplusplus
extern "C" {
#endif

// Declare C function interface here.
int myFunc(int x,char*);

#ifdef __cplusplus
}
#endif

#endif

1voto

Nareshkumar Points 1104

Merci, pour cette bonne discussion.

ce que j'ai fait est :

1) J'ai créé une librairie statique en utilisant l'option librairie statique de cocaotouch. Dans cette librairie, j'ai un mélange de c/c++/obj-c. Cependant, mes exportations ne sont que des classes objc. En fait, j'ai utilisé objc- to c to C++.

2) puis j'ai créé une application iphone dans le projet X-code. J'ai ajouté les drapeaux d'autres liens au nom de ma librairie ( -lxyz ) //mon nom de librairie est libxyz.a J'ai ajouté le chemin de recherche de la librairie et le chemin de recherche de l'en-tête.

3) puis j'ai compilé. J'ai eu des erreurs. disant oeprator new, operator delete not found.

3) puis à part mon appdelegate, contrôleur de vue, j'ai ajouté dummy cpp(.h, .cpp)... atestdummy.h atestdummy.cpp

4) puis je construis à nouveau...

que ça a marché.

Donc, les suggestions qu'ils ont données plus tôt ont fonctionné pour moi. raison de base, à moins que votre application ne voit un fichier .cpp, un fichier .mm avec du code cpp, linked n'utilisera pas g++.

Merci à tous. J'ai lu ce qui précède et j'ai résolu mon problème.

Vous êtes bons pour partager.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X