web-dev-qa-db-fra.com

Que signifie réellement "Symbole non trouvé / attendu dans: espace de noms plat"?

Lorsque j'importe un module que j'ai construit, j'obtiens cette erreur liée à boost-python:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: dlopen(./myMod.so, 2): Symbol not found: __ZN5boost6python7objects15function_objectERKNS1_11py_functionERKSt4pairIPKNS0_6detail7keywordES9_E
  Referenced from: ./myMod.so
  Expected in: flat namespace
 in ./myMod.so

Qu'est-ce que cela signifie réellement? Pourquoi cette erreur a-t-elle été déclenchée?

24
kilojoules

La description

Le problème était dû au mélange d'objets compilés avec libc++ et d'objets compilés avec libstdc++.

Dans notre cas, la bibliothèque myMod.so (Compilée avec libstdc++) a besoin de boost-python Compilée avec libstdc++ (boost-python-libstdc++ À partir de maintenant). Lorsque boost-python Est boost-python-libstdc++, Cela fonctionnera correctement. Sinon - sur l'ordinateur que son boost-python A compilé avec libc++ (ou une autre bibliothèque c ++), il aura un problème de chargement et d'exécution.

Dans notre cas, cela se produit parce que les développeurs libc++ ont intentionnellement changé le nom de tous leurs symboles pour vous empêcher (et vous sauver) de mélanger le code de leur bibliothèque et le code de une autre: myMod.so a besoin d'une fonction qui prend un argument du type. Dans libc++, Le nom de ce type est std::__1::pair. Par conséquent, ce symbole n'a pas été trouvé.

Pour comprendre pourquoi le mélange de deux versions de la même API est mauvais, considérez cette situation: Il existe deux bibliothèques: Foo et Bar. Ils ont tous deux une fonction qui prend un std::string Et l'utilise pour quelque chose mais ils utilisent une bibliothèque c ++ différente. Lorsqu'un std::string Créé par Foo sera passé à Bar, Bar pensera qu'il s'agit d'une instance de sa bibliothèque c ++ std::string Et alors de mauvaises choses peuvent arriver (ce sont des objets complètement différents).

Remarque : Dans certains cas, il n'y aurait aucun problème avec deux ou plusieurs versions différentes de la même API dans des parties complètement différentes d'un programme. Il y aura un problème s'ils passent les objets de cette API entre eux. Cependant, vérifier cela peut être très difficile, surtout s'ils passent l'objet API uniquement en tant que membre d'un autre objet. De plus, la fonction d'initialisation d'une bibliothèque peut faire des choses qui ne devraient pas se produire deux fois. Une autre version peut refaire ces choses.

Comment résoudre ça?

  • Vous pouvez toujours recompiler vos bibliothèques et les faire correspondre.

  • Vous pouvez lier boost-python À votre bibliothèque en tant que bibliothèque statique. Ensuite, il fonctionnera sur presque tous les ordinateurs (même celui sur lequel boost-python N'est pas installé). Voir plus à ce sujet ici .

Sommaire

myMod.so A besoin d'une autre version de boost-python, Une version compilée avec une bibliothèque c ++ spécifique. Par conséquent, cela ne fonctionnerait pas avec une autre version.

18
Shmuel H.

Je rencontre le même problème.

Expected in: flat namespace

Ajouter l'indicateur de l'éditeur de liens résout le problème

-lboost_python37

remplacez le nom de la bibliothèque dynamique par celui installé sur le système d'exploitation.

Soit dit en passant, mon système d'exploitation est macOS High Sierra et j'utilise brew pour installer boost_python3.

4
zhaofeng-shu33

Symbole non trouvé signifie que la définition de la fonction ou de la variable déclarée est introuvable. Lorsqu'un fichier d'en-tête d'un objet partagé est compilé avec votre programme, l'éditeur de liens ajoute des symboles de fonctions et d'objets déclarés à votre programme compilé. Lorsque votre programme est chargé par le chargeur du système d'exploitation, les symboles sont résolus afin que leur définition soit chargée. Ce n'est qu'à ce moment où si l'implémentation est manquante, le chargeur se plaint qu'il n'a pas pu trouver la définition car il est possible qu'il ne parvienne pas à résoudre le chemin d'accès réel à la bibliothèque ou la bibliothèque elle-même n'a pas été compilée avec le fichier d'implémentation/source où la définition de la fonction ou de l'objet réside. Il y a un bon article à ce sujet dans le journal linux http://www.linuxjournal.com/article/646 .

1
Misgevolution

Voici ce que j'ai appris (osx):

Si cela est censé fonctionner (c'est-à-dire qu'il fonctionne sur un autre ordinateur), vous pouvez rencontrer des problèmes de clang/gcc. Pour déboguer cela, utilisez otool -l sur le fichier .so qui provoque l'erreur, ou une bibliothèque suspecte (dans mon exemple, c'est un fichier boost-python dylib) et examinez le contenu. Tout ce qui se trouve dans le dossier/System/est construit avec clang et devrait être installé ailleurs avec le compilateur gcc. Ne supprimez jamais rien dans le dossier/System.

1
kilojoules

Les fichiers .so Sont des bibliothèques dynamiques (donc = objet partagé). Sous Windows, ils sont appelés .dll (Bibliothèque de liens dynamiques). Ils contiennent du code compilé qui contient des fonctions disponibles pour une utilisation avec tout exécutable qui les relie.

Ce qui est important de noter ici, c'est que ces .so Ne sont pas des fichiers Python. Ils ont probablement été compilés à partir de code C ou C++ et contiennent des fonctions publiques qui peuvent être utilisées à partir de Python code (voir la documentation sur Extension Python avec C ou C++ ).

Dans votre cas, eh bien, vous avez un .so Corrompu. Essayez de réinstaller les bibliothèques concernées, ou Python, ou les deux.

1
zvone