OVH Cloud OVH Cloud

[Solaris][g++] symbol _ZNSs20_S_empty_rep_storageE: referenced symbol not found

14 réponses
Avatar
florian.coroller
Bonjour,

A l'aide de JNI, j'appelle depuis un .java un .cpp qui lui m=EAme
appelle des librairies C++ fournies (dont je n'ai pas la source). Le
lien Java -> C++ fonctionne.

Lorsque j'int=E8gre les m=E9thodes issues des librairies cpp fournies, la
compilation (=E0 l'aide de g++) fonctionne, mais au moment de
l'execution du .class, j'ai l'erreur suivante :

java.lang.UnsatisfiedLinkError: no ISE in java.library.path

Je ne pense pas qu'il s'agisse d'une erreur de classpath. En rajoutant
l'option verbose :
java -verbose:jni ISE, j'obtiens un message plus d=E9taill=E9 :

[Unable to load native library: /space2/data/tmp/fcor/ise/libISE.so]
ld.so.1:
/usr/bin/../java/bin/../jre/bin/../bin/sparc/native_threads/java:
fatal: relocation error: file /space2/data/tmp/fcor/ise/libISE.so:
symbol _ZNSs20_S_empty_rep_storageE: referenced symbol not found

Il semblerait que _ZNSs20_S_empty_rep_storageE est inclue dans les
librairies du compilateur ?

Le probl=E8me peut-il venir d'une incompatibilit=E9 entre les
compilations c++ (la mienne, avec gcc sous solaris, et celle des libs
fournies avec cc sous linux) et comment les r=E9soudre ?

Merci par avance

4 réponses

1 2
Avatar
kanze
Alain Gaillard wrote:

java -Djava.library.path=/le_repertoire qui_contient_le_so MaClasse


Sauf que si j'ai bien compris, il trouve sa propre classe. Ce
sont les bibliothèques utilisées par ses classes qui posent le
problème.


Il n'est pas question ici de trouver sa propre classe, mais bien les
bibliothèques native utilisées pas ses classes Java. A moins que tu a is
voulu dire sa propre librairie native. De toutes façons, normalement un
-Djava.library.path (ou un LD_LIBRARY_PATH) correctement positionné
règle ce problème.


Il me semble avoir vu une variable statique dans
l'implémentation de std::string chez g++ (mais dans quelle
version -- je ne m'en souviens plus) qui avail le même nom, ou
un nom semblable, à celui qui lui manque. Du coup, je soupçonne
quelque chose qui sert dans son propre code : soit qu'il ne
trouve pas libstdc++, soit que la version installée n'est pas
compatible avec la version dont il s'est servi pour générer son
code.

Enfin bref, si la ou les librairies sont pointées
correctement, sous Linux c'est impossible que ça ne marche
pas.


Je vois que tu n'as pas beaucoup d'expérience dans le domaine.
Si la bibliothèque n'est pas installée sur la machine (souvent
le cas de libstdc++.so), tu ne peux pas le rétrouver, quoique tu
mets dans LD_LIBRARY_PATH. Et si la version installée n'est pas
compatible avec la version dont tu t'es servi lors de la
génération de ton programme, ça risque de poser des problèmes
aussi.

C'est pourquoi je lie toujours libstdc++ en statique.

Ou alors comme tu l'as dit dans un autre post, c'est qu'il
utilise sous Linux une librairie compilée pour Solaris. Mais
ça paraît tellement incroyable....


À moi aussi. Mais s'il est rélativement débuttant, et que sa
seule expérience jusqu'ici est en Java (ou Basic, ou d'autres
langages qui sont plus ou moins interprétés).

Dans ce cas la solution c'est évidemment de compiler sous
Linux.... et ce n'est même pas la peine de regarder la doc de
g++. Spécialement pour ça je veut dire.


Il reste que s'il compile avec g++ 4.1.0, et le g++ installait
sur la machine où exécute le programme est g++ 2.95.2, ça ne va
certainement pas marcher sans l'option -static-libgcc. Et que
pour le connaître, il faut bien avoir lu le manual g++.

Je viens de vérifier sur mes copies des sources de g++. Le
symbole dont il a besoin est bien référencé dans
basic_string.tcc ; il est donc démandé si son code C++ utilise
std::string. Et il est défini dans un fichier string-inst.o, qui
fait bien partie de libstdc++ -- dans libstdc++.so.6.0.7 du g++
4.1.0. Dans libstdc++.so.6.0.3, du g++ 3.4.3, le nom est
légèrement différent. Donc, s'il développe avec g++ 4.1.0, mais
que le g++ installé où le programme tourne est g++ 3.4.3, il
aurait exactement l'erreur qu'il décrit.

Dans les faits : à l'encontre de la bibliothèque C, il n'y a
pas de API « standard » pour la bibliothèque C++. Chaque
implémenteur en fait ce qu'il veut, et c'est plutôt courant que
ça change d'une version à l'autre. (G++ n'est pas le seul à se
comporter comme ça.) En plus, la bibliothèque C++ n'est
typiquement présente que si le compilateur g++ a été installé
sur le système -- si c'est souvent le cas avec Linux, c'est
bien moins fréquent sous Unix. Du coup, au moins de vouloir
vraiment des emmerdes, on doit 1) lier libstdc++ en statique, au
moyen de l'option -static-libgcc, 2) ne pas utiliser quoique ce
soit de la bibliothèque C++ à l'interface entre les .so, et 3)
ne pas laisser des exceptions traverser l'interface des .so.

En ce qui concerne les JNI, les deux dernières conditions sont
remplies d'office. Qu'il ajoute -static-libgcc à la ligne de
commande qui génère le .so, et tout doit rentrer dans l'ordre.
(À condition que tout marche comme ça doit marcher ; il me
semble avoir vu un rapport de bug sur -static-libgcc, qu'il ne
marche pas toujours comme il faut.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Alain Gaillard


Modifier ou positionner le LD_LIBRARY_PATH ne sert à rien (pour le
moment en tout cas), pour la simple est bonne raison que si j'essaye de
faire un executable C++ ça ne fonctionne pas non plus (donc rien à
voir avec le Java).


Dis donc, ce que tu nous dis là ne reflète pas ta question initiale je
trouve... :-S


fournis). Au moment de la compilation, il ne trouve pas les librairies
math_iso.h (ainsi que d'autres librairies).


Mais alors si tu en es là seulement, comment tu peux nous dire que le
JVM te lève exception UnsatisfiedKinnError ?

Bref, peu importe. Maintenant à relire ton post initial, on dirait que
tu te heurtes à un problème de décoration de noms de fonctions.
Normalement quand tu compiles pour JNI tu n'as pas ce problème cat dans
jni.h il y a


#ifdef __cplusplus
extern "C" {
#endif

qui t'arrange le coup automatiquement, au moins sur g++. C'est pour ça
que je disais qu'il n'y a même pas besoin de lire la doc.
Mais si tu utilise d'autres librairies en plus que celle que tu as
écrites, alors peut être que quand tu compiles un nom de fonction est
décoré "à la C++". Vois s'il n'y manque pas un extern "C" quelque part,
dans la zone d'un "empty_rep_storage" comme ton post initial le suggère.


J'ai cependant une question, est-il possible de compiler un fichier
.cpp pour en faire une dll qui intégrerait en elle toutes les
dépendances possibles afin d'obtenir une unique librairie


Si tu as tous les sources pourquoi pas ?
Mais ça risque de te demander du travail.

Merci encore pour votre aide.


De rien, en espérant t'avoir mieux aidé cette fois.



--
Alain

Avatar
kanze
SamR wrote:

Pour commencer, merci à tous pour vos réponses.

Je continue d'avancer dans l'investigation de ce problème.

kanze est certainement la personne la plus proche. Modifier
ou positionner le LD_LIBRARY_PATH ne sert à rien (pour le
moment en tout cas), pour la simple est bonne raison que si
j'essaye de faire un executable C++ ça ne fonctionne pas non
plus (donc rien à voir avec le Java).


LD_LIBRARY_PATH n'a rien à voir avec Java. N'oublie pas que la
JVM qui exécute ton Java est écrit, lui aussi, en C ou en C++.
Et qu'elle utilise, à la base, les mêmes bibliothèques système
que ton C++ (en l'occurance, les fonctions dlopen/dlsym).

Je résume la situation :

Java ---JNI----> C++ (solaris) -----> C++ (linux)

Les librairies C++ fournies par mon client ont visiblement été
compilées sous Linux.


Avec quelle version de g++ ?

J'essaye pour le moment de les recompiler sous Solaris
(Sparc2.8). Or ces librairies utilisent le package OpenSSL et
notamment les libraires libcrypto.so et libSSL.so. J'ai donc
téléchargé ce package pour permettre l'éxecution.


En format source, ou comme .so. Si le code est en C++, et que
les bibliothèques ont été compilées avec Sun CC, elles ne
marcheront pas avec du code compilé avec g++.

J'ai tenté de le compiler en modifiant le makefile pour
Solaris (à l'aide des scripts fournis). Au moment de la
compilation, il ne trouve pas les librairies math_iso.h (ainsi
que d'autres librairies). Je découvre en fait que mon
environnement n'est pas vraiment viable pour le développement
C++.


Quel environnement ? Je développe à 90% sous Solaris, et avec
Sun CC et avec g++, et je n'ai pas de problème. Le fichier
math_iso.h se trouve dans /usr/include/iso ; il fait parti du
package SUNWlibm, qui doit être installé d'office (je crois).

Ensuite, si g++ est installé correctement, il doit le trouver.
(Il le trouve chez moi.) Essaie g++ -v sur une source triviale,
et régarder le chemin qu'il cherche : /usr/include doit être à
la fin (et l'include doit être de <iso/math_iso.h> dans le
math.h qu'il trouve). Sinon, c'est un problème d'installation de
g++, et il faudrait démander dans les groupes spécialisées gcc.

Je vais donc tant bien que mal essayer de trouver toutes les
dépendances et recompiler tout ce bazar.

J'ai cependant une question, est-il possible de compiler un
fichier .cpp pour en faire une dll qui intégrerait en elle
toutes les dépendances possibles afin d'obtenir une unique
librairie (et ce afin de faciliter le déploiement sur d'autres
environnement (qualif, prod)).


Je crois, si tu as des .a, et non seulement des .so. Je ne l'ai
pas essayé, mais je crois que si tu précises -B static avant le
-l option, l'éditeur de liens prends la version .a de
préférence, et l'incorpore statiquement. Si tu invoques
l'éditeur de liens à travers g++ (fortement conseillé), il faut
bien lui dire de passer et le -B et le static à l'éditeur de
liens, donc :
g++ ... -Xlinker -B -Xlinker static -lcrypto
-Xlinker -B -Xlinker static -lSSl ...
(Je ne suis pas trop sûr si ça marche pour la génération des
objets dynamiques, mais on s'en sert extensivement ici pour les
binaires. Aussi, un essaie rapide me donne l'impression que
-static-libgcc ne fonctionne pas, au moins sur Solaris.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Alain Gaillard


Il me semble avoir vu une variable statique dans
l'implémentation de std::string chez g++ (mais dans quelle
version -- je ne m'en souviens plus) qui avail le même nom, ou
un nom semblable, à celui qui lui manque. Du coup, je soupçonne
quelque chose qui sert dans son propre code : soit qu'il ne
trouve pas libstdc++, soit que la version installée n'est pas
compatible avec la version dont il s'est servi pour générer son
code.


Ah oui ça pourrait expliquer bien des choses.

Enfin bref, si la ou les librairies sont pointées
correctement, sous Linux c'est impossible que ça ne marche
pas.



Je vois que tu n'as pas beaucoup d'expérience dans le domaine.
Si la bibliothèque n'est pas installée sur la machine


Ah ce bon vieux James. Toujours aussi taquin et plein d'humour.
Allons allons... :-)
J'ai écrit "si la ou les librairies sont pointées correctement"
Pour qu'elles soient pointées faut aussi qu'elles soit présentes. Ca
tombe quand même sous le sens.

(souvent
le cas de libstdc++.so), tu ne peux pas le rétrouver,


Si tu l'as paumée c'est ton problème :-)

quoique tu
mets dans LD_LIBRARY_PATH.


N'importe quoi.... Si LD_LIBRARY_PATH pointe dessus tu la trouves.
En admettant même qu'il faille toucher à cette variable d'environnement.
Sur une distribution Linux "d'origine' si je peux dire, libstdc++.so est
toujours pointée depuis le ld.so.conf. Enfin je n'ai jamais vu autre
chose. Il y a tellement de distrib tu me diras...

Evidemment si un autre g++ a été installé à posteriori ou si plusieurs
versions cohabitent c'est autre chose. Mais si quelqu'un sait faire ça,
ça m'étonnerait qu'il fasse une édition de liens incorrecte.

Et si la version installée n'est pas
compatible avec la version dont tu t'es servi lors de la
génération de ton programme, ça risque de poser des problèmes
aussi.


Ah ça oui, c'est bien possible.


C'est pourquoi je lie toujours libstdc++ en statique.


Oui je suis d'accord, c'est une sage précaution.

Je viens de vérifier sur mes copies des sources de g++. Le
symbole dont il a besoin est bien référencé dans
basic_string.tcc ; il est donc démandé si son code C++ utilise
std::string. Et il est défini dans un fichier string-inst.o, qui
fait bien partie de libstdc++ -- dans libstdc++.so.6.0.7 du g++
4.1.0. Dans libstdc++.so.6.0.3, du g++ 3.4.3, le nom est
légèrement différent. Donc, s'il développe avec g++ 4.1.0, mais
que le g++ installé où le programme tourne est g++ 3.4.3, il
aurait exactement l'erreur qu'il décrit.


Oui ça explique bien des choses.

En fait comme il disait que la librairie native ne chargeait pas sous
JVM, je suis parti du principe quelle fonctionnait correctement par elle
même. Si la librairie n'a pas été construite correctement, c'est une
autre affaire.
D'ailleurs à lire le post de ce matin du posteur initial, c'est bien là
que se situe la difficulté.


--
Alain


1 2