Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

symbole non référencé dans une librairie statique

15 réponses
Avatar
Snoopy
Hello,

Il m'arrive de d=E9finir des objets que je me contente de stoquer dans une =
cha=EEne de pointeurs. Ces objets sont des membres statiques de classe et s=
'auto-inscrivent dans la cha=EEne =E0 leur cr=E9ation. Mon probl=E8me est l=
e suivant : Les objets n'etant jamais r=E9f=E9ranc=E9s directement, mon com=
pilo (gcc 3.3.5) se permet de les supprimer !

d=E9tails :
---------
J'utilise un 'pseudo RTTI' pour construire des objets =E0 partir d'un fichi=
er de config. (et donc =E0 partir de cha=EEne de char). Tous le code ci-des=
sous est dans une librairie statique (sinon, ca fonctionne normalement)

Mes objets ressemblent =E0 ca :
-----------------------------
class obj : public objBase {
private:
static objFactory _factory;
};


L'usine d'objets ressemble =E0 =E7a :
---------------------------------
typedef objBase (*objCtor)();

class objFactory {
public:
objFactory(string name, objCtor ctor) :=20
_name(name),
_ctor(ctor),=20
_next(_first) {
_first =3D this;
}
=20
string _name;
objCtor _ctor;
objFactory* _next;
static objFactory* _first;
};

Impl=E9mentation de l'objet :
---------------------------
objBase* ctorForObj() {
return new obj;
}
objFactory obj::_factory("Obj", (objCtor) ctorForObj);
=20

Fonction de construction via RTTI :
-----------------------------------
objBase* create(string name) {
objFactory* factory =3D objFactory::_first;
while (factory) {
if (factory->_name =3D=3D name)=20
return factory->_ctor();=20
factory =3D factory->_next;
}
return NULL;
}


Conclusion :
-----------
Je me retrouve avec un objet non r=E9f=E9renc=E9 =E0 l'ext=E9rieur de la li=
b (obj) qui contient un objet statique encore moin r=E9f=E9renc=E9 (obj::fa=
ctory). =E0 l'=E9ddition des liens, ce dernier est supprim=E9.


Comment contourner le probl=E8me ?
Voyez-vous une autre m=E9thode pour faire cel=E0 sans avoir de fonction d'i=
nitialisation de la librairie ?

Merci


--
sn00py

10 réponses

1 2
Avatar
Loïc Joly
Hello,

Il m'arrive de définir des objets que je me contente de stoquer dans
une chaîne de pointeurs. Ces objets sont des membres statiques de
classe et s'auto-inscrivent dans la chaîne à leur création. Mon
problème est le suivant : Les objets n'etant jamais référancés
directement, mon compilo (gcc 3.3.5) se permet de les supprimer !

[...]


Comment contourner le problème ? Voyez-vous une autre méthode pour
faire celà sans avoir de fonction d'initialisation de la librairie ?


Il doit être possible par une option du linker de lui dire de ne pas
supprimer une référence à un objet d'une bibliothèque, même si cet objet
n'a pas l'air utilisé dans le programme principal. Avec les compilateurs
que je connais, il faut pour ça donner le nom décorré de l'objet, ce qui
est un peu rugueux.

--
Loïc

Avatar
Snoopy
Loïc Joly wrote:

Hello,

Il m'arrive de définir des objets que je me contente de stoquer dans
une chaîne de pointeurs. Ces objets sont des membres statiques de
classe et s'auto-inscrivent dans la chaîne à leur création. Mon
problème est le suivant : Les objets n'etant jamais référancés
directement, mon compilo (gcc 3.3.5) se permet de les supprimer !

[...]


Comment contourner le problème ? Voyez-vous une autre méthode pour
faire celà sans avoir de fonction d'initialisation de la librairie ?


Il doit être possible par une option du linker de lui dire de ne pas
supprimer une référence à un objet d'une bibliothèque, même si cet objet
n'a pas l'air utilisé dans le programme principal. Avec les compilateur s
que je connais, il faut pour ça donner le nom décorré de l'objet, c e qui
est un peu rugueux.



Oui, j'y avait pensé, et avec gcc il faut effectivement lister tous les o bjets, ce qui s'avère encore plus contraingant que de créer une fonctio n d'initialisation de la librairie.
Ce qui me parait étrange c'est que je déclare une instance de cet objet . Je veux bien que le compilo supprimer des symboles non définits, mais p ourquoi supprimerait-il des instances d'objets ?


Avatar
James Kanze
Snoopy wrote:

Il m'arrive de définir des objets que je me contente de
stoquer dans une chaîne de pointeurs. Ces objets sont des
membres statiques de classe et s'auto-inscrivent dans la
chaîne à leur création. Mon problème est le suivant : Les
objets n'etant jamais référancés directement, mon compilo (gcc
3.3.5) se permet de les supprimer !


Seulement si c'est ce que tu lui as démandé.

détails :
---------
J'utilise un 'pseudo RTTI' pour construire des objets à partir
d'un fichier de config. (et donc à partir de chaîne de char).
Tous le code ci-dessous est dans une librairie statique
(sinon, ca fonctionne normalement)


Précisement. Par définition, une bibliothèque sert à contenir
des objets qui ne sont incorporés au programme que
conditionnellement, s'ils résoudent une référence externe non
résolue. C'est la définition même d'une bibliothèque (et en
fait, les DLL de Windows ne sont pas de bibliothèques, mais des
objets chargés dynamiquement). Si ce n'est pas le comportement
voulu, la réponse est facile, n'utilise pas une bibliothèque.

[... l'idiome est très connu]

Conclusion :
-----------
Je me retrouve avec un objet non référencé à l'extérieur de la
lib (obj) qui contient un objet statique encore moin référencé
(obj::factory). à l'éddition des liens, ce dernier est
supprimé.


Il n'est pas supprimé. Il n'a jamais fait partie du programme
pour commencer.

Comment contourner le problème ?


La solution classique, c'est de ne pas utiliser une
bibliothèque:-). Mais il y a bien d'autres moyens de tricher.

Voyez-vous une autre méthode pour faire celà sans avoir de
fonction d'initialisation de la librairie ?


Tu n'as pas besoin d'une fonction. Tu as simplement besoin d'un
symbole externe qui déclenche une chaîne d'externes
non-résolues. Par exemple, quand tu construis la bibliothèque,
tu as bien une liste des fichiers qu'elle contient. C'est assez
facile alors de :

-- définir un symbole dans le namespace globale, selon une
convention (nommage, type, etc.) que tu établis,

-- lors de la création de la bibliothèque, parcourir tous les
sources, en extrayant ces symboles pour en créer une source
supplémentaire qui contient un tableau de pointeurs à ces
éléments, et

-- s'arranger qu'une des unités de compilation avec un symbole
externe qui sert réelement prend l'adresse de ce tableau.

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

Avatar
James Kanze
Loïc Joly wrote:

Il m'arrive de définir des objets que je me contente de
stoquer dans une chaîne de pointeurs. Ces objets sont des
membres statiques de classe et s'auto-inscrivent dans la
chaîne à leur création. Mon problème est le suivant : Les
objets n'etant jamais référancés directement, mon compilo
(gcc 3.3.5) se permet de les supprimer !



[...]


Comment contourner le problème ? Voyez-vous une autre méthode
pour faire celà sans avoir de fonction d'initialisation de la
librairie ?



Il doit être possible par une option du linker de lui dire de
ne pas supprimer une référence à un objet d'une bibliothèque,
même si cet objet n'a pas l'air utilisé dans le programme
principal. Avec les compilateurs que je connais, il faut pour
ça donner le nom décorré de l'objet, ce qui est un peu
rugueux.


Si c'est un objet (mettons un tableau avec des pointeur à tous
ce dont on veut forcer l'incorporation), le nom n'est pas
décoré, au moins avec les compilateurs que je connais (dont
g++).


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


Avatar
Gabriel Dos Reis
James Kanze writes:

| Loïc Joly wrote:
|
| >> Il m'arrive de définir des objets que je me contente de
| >> stoquer dans une chaîne de pointeurs. Ces objets sont des
| >> membres statiques de classe et s'auto-inscrivent dans la
| >> chaîne à leur création. Mon problème est le suivant : Les
| >> objets n'etant jamais référancés directement, mon compilo
| >> (gcc 3.3.5) se permet de les supprimer !
|
| > [...]
|
| >> Comment contourner le problème ? Voyez-vous une autre méthode
| >> pour faire celà sans avoir de fonction d'initialisation de la
| >> librairie ?
|
| > Il doit être possible par une option du linker de lui dire de
| > ne pas supprimer une référence à un objet d'une bibliothèque,
| > même si cet objet n'a pas l'air utilisé dans le programme
| > principal. Avec les compilateurs que je connais, il faut pour
| > ça donner le nom décorré de l'objet, ce qui est un peu
| > rugueux.
|
| Si c'est un objet (mettons un tableau avec des pointeur à tous
| ce dont on veut forcer l'incorporation), le nom n'est pas
| décoré, au moins avec les compilateurs que je connais (dont
| g++).

merlin[11:54]% cat jk.C && g++ -S jk.C | cat jk.s && (cat jk.s | c++filt )
struct foo {
static int* bar[];
};

int* foo::bar[42];

.file "jk.C"
.globl _ZN3foo3barE
.bss
.align 32
.type _ZN3foo3barE, @object
.size _ZN3foo3barE, 168
_ZN3foo3barE:
.zero 168
.ident "GCC: (GNU) 4.1.0 20050721 (experimental)"
.section .note.GNU-stack,"",@progbits
.file "jk.C"
.globl foo::bar
.bss
.align 32
.type foo::bar, @object
.size foo::bar, 168
foo::bar:
.zero 168
.ident "GCC: (GNU) 4.1.0 20050721 (experimental)"
.section .note.GNU-stack,"",@progbits

-- Gaby
Avatar
Gabriel Dos Reis
Snoopy writes:

| Loïc Joly wrote:
|
| > > Hello,
| > >
| > > Il m'arrive de définir des objets que je me contente de stoquer dans
| > > une chaîne de pointeurs. Ces objets sont des membres statiques de
| > > classe et s'auto-inscrivent dans la chaîne à leur création. Mon
| > > problème est le suivant : Les objets n'etant jamais référancés
| > > directement, mon compilo (gcc 3.3.5) se permet de les supprimer !
| > >
| > [...]
| > >
| > > Comment contourner le problème ? Voyez-vous une autre méthode pour
| > > faire celà sans avoir de fonction d'initialisation de la librairie ?
| >
| > Il doit être possible par une option du linker de lui dire de ne pas
| > supprimer une référence à un objet d'une bibliothèque, même si cet objet
| > n'a pas l'air utilisé dans le programme principal. Avec les compilateurs
| > que je connais, il faut pour ça donner le nom décorré de l'objet, ce qui
| > est un peu rugueux.
| >
|
| Oui, j'y avait pensé, et avec gcc il faut effectivement lister tous
| les objets, ce qui s'avère encore plus contraingant que de créer une
| fonction d'initialisation de la librairie.
| Ce qui me parait étrange c'est que je déclare une instance de cet
| objet. Je veux bien que le compilo supprimer des symboles non
| définits, mais pourquoi supprimerait-il des instances d'objets ?

Je n'ai pas l'impression que tu as définis cet objet...

-- Gaby
Avatar
plouf79
Tu n'as pas besoin d'une fonction. Tu as simplement besoin d'un
symbole externe qui déclenche une chaîne d'externes
non-résolues. Par exemple, quand tu construis la bibliothèque,
tu as bien une liste des fichiers qu'elle contient. C'est assez
facile alors de :

-- définir un symbole dans le namespace globale, selon une
convention (nommage, type, etc.) que tu établis,

-- lors de la création de la bibliothèque, parcourir tous les
sources, en extrayant ces symboles pour en créer une source
supplémentaire qui contient un tableau de pointeurs à ces
éléments, et

-- s'arranger qu'une des unités de compilation avec un symbole
externe qui sert réelement prend l'adresse de ce tableau.


Une petite question, juste pour être sûr :

Si on a les 3 fichiers suivants :

/// main.cpp ///
int main()
{
return 0;
}

/// libtoto.h ///
#include <iostream>
using namespace std;

class toto
{
public:

toto()
{
cout << "Toto is used" << endl ;
}
};

/// libtoto.cpp ///
#include "libtoto.h"
toto T;

/// Fin des fichiers ///


... et qu'on fait :

g++ -g -c -Wall libtoto.cpp
g++ -g -c -Wall main.cpp
g++ -g -Wall main.o libtoto.o -o tototest

Alors on a bien de manière certaine "tototest"
qui affiche "Toto is used" à l'execution ?

C'est bien garanti par la norme ça ? même s'il
n'y a rien dans le 'main' qui indique que l'objet
toto est utilisé ?

--
P.

Avatar
Snoopy
Une petite question, juste pour être sûr :

Si on a les 3 fichiers suivants :

[...]

... et qu'on fait :
g++ -g -c -Wall libtoto.cpp
g++ -g -c -Wall main.cpp
g++ -g -Wall main.o libtoto.o -o tototest

Alors on a bien de manière certaine "tototest"
qui affiche "Toto is used" à l'execution ?

C'est bien garanti par la norme ça ? même s'il
n'y a rien dans le 'main' qui indique que l'objet
toto est utilisé ?



Dans mon cas j'utilise une bibliothèque statique, pas un .o qui s'appelle libxxxx :
g++ -g -c -Wall libtoto.cpp
ar cru libtoto.a libtoto.o
ranlib libtoto.a
g++ -g -Wall main.c libtoto.a -o tototest

Et dans ce cas on n'a pas de message "Toto is used".
L'explication donnée par James est très logique, malheureusement pour m oi !

--
sn00py

Avatar
James Kanze
wrote:
Tu n'as pas besoin d'une fonction. Tu as simplement besoin
d'un symbole externe qui déclenche une chaîne d'externes
non-résolues. Par exemple, quand tu construis la bibliothèque,
tu as bien une liste des fichiers qu'elle contient. C'est
assez facile alors de :



-- définir un symbole dans le namespace globale, selon une
convention (nommage, type, etc.) que tu établis,



-- lors de la création de la bibliothèque, parcourir tous les
sources, en extrayant ces symboles pour en créer une source
supplémentaire qui contient un tableau de pointeurs à ces
éléments, et



-- s'arranger qu'une des unités de compilation avec un symbole
externe qui sert réelement prend l'adresse de ce tableau.



Une petite question, juste pour être sûr :


Si on a les 3 fichiers suivants :


/// main.cpp ///
int main()
{
return 0;
}


/// libtoto.h ///
#include <iostream>
using namespace std;


class toto
{
public:

toto()
{
cout << "Toto is used" << endl ;
}
};

/// libtoto.cpp ///
#include "libtoto.h"
toto T;


/// Fin des fichiers ///


... et qu'on fait :


g++ -g -c -Wall libtoto.cpp
g++ -g -c -Wall main.cpp
g++ -g -Wall main.o libtoto.o -o tototest


Alors on a bien de manière certaine "tototest" qui affiche
"Toto is used" à l'execution ?


Oui.

C'est bien garanti par la norme ça ?


Pas vraiment. Il y a deux questions ici vis-à-vis de la norme.

-- La première, c'est que la norme donne deux alternatifs pour
l'initialisation des statiques : ou bien, ils sont
initialisés avant d'entrer en main, ou bien, ils sont
initialisés avant la première utilisation de l'unité de
compilation qui les contient.

En fait, toutes les implémentations utilisent le permier, et
pour deux raisons. D'abord, il y a de plus en plus de code
qu'y compte, et qu'on ne veut pas casser, et deuxièmement,
le deuxième alternatif n'est pas implémentable s'il y a des
cycles (et la norme dit que si on le choisit, il faut qu'il
marche -- sans exception pour des cycles).

Dans la pratique, je crois qu'on peut dire que dans
l'absence des objets linkés dynamiquement, les statiques
sont initialisés avant l'entrée dans main.

-- La norme ne s'adresse pas à la question : comment invoquer
le compilateur, et donc, comment spécifier qu'une source (ou
l'objet qui en dérive) fasse partie du programme. Dans les
faits, la définition d'une bibliothèque est assez générale ;
on voit mal un compilateur oser faire autre chose. (Bien
que... VC++ parle des bibliothèques par rapport aux DLL, et
le comportement d'une DLL ne correspond pas au comportement
traditionnel d'une bibliothèque.) Donc, le fait de spécifier
un objet sur la ligne de commande fait partie de
l'invocation de g++ ; rien n'interdirait (sauf la tradition)
de dire qu'il traite cet objet comme faisant partie d'une
bibliothèque.

Ici, aussi, on a en fait une très longue et très forte
tradition. Tous les éditeurs de liens que je connais (et ça
rémonte prèsque 35 ans dans le temps) ont une façon de
spécifier une liste de fichiers objets, et une façon de
spécifier une liste de fichiers bibliothèques. Et tous
incorpore tous les fichiers objets dans le programme, mais
seulement les objets des bibliothèques qui résolvent un
externe non encore résolu. Ils diffèrent beaucoup dans la
façon de spécifier ces objets et ces bibliothèques (encore
que la ligne de commande soit assez généralisée
aujourd'hui), et ils diffèrent beaucoup dans la façon
(surtout l'ordre) qu'ils traitent les différents éléments.
Ils ont aussi des variations sur des possibilités
supplémentaires. Mais la distinction fichier objet/fichier
bibliothèque est tellement universelle que je crois qu'on
peut y compter.

Donc, si ta question est : est-ce qu'il est garanti par la norme
que, donné les sources ci-dessus, les commandes :

g++ -g -c -Wall libtoto.cpp
g++ -g -c -Wall main.cpp
g++ -g -Wall main.o libtoto.o -o tototest


génèreront un programme qui affiche "toto is used", la résponse
est certainement non -- ces commandes-là, elles ne feront
absolument rien avec VC++, par exemple. Mais, et je crois que
c'est ce qui t'intéresse, tu peux compter que pour tout
compilateur C++, il y a une suite équivalente des commandes, et
que cette suite équivalente donnera bien un programme qui
affiche "toto is used".

même s'il n'y a rien dans le 'main' qui indique que l'objet
toto est utilisé ?


La question n'est pas si toto est utilisé. La question, c'est
d'abord et surtout si libtoto.cpp fait partie de ton programme.
Si libtoto.cpp fait partie du programme, l'objet qu'il contient
doit être initialisé.

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


Avatar
Gabriel Dos Reis
James Kanze writes:


[...]

| > C'est bien garanti par la norme ça ?
|
| Pas vraiment. Il y a deux questions ici vis-à-vis de la norme.
|
| -- La première, c'est que la norme donne deux alternatifs pour
| l'initialisation des statiques : ou bien, ils sont
| initialisés avant d'entrer en main, ou bien, ils sont
| initialisés avant la première utilisation de l'unité de
| compilation qui les contient.
|
| En fait, toutes les implémentations utilisent le permier, et
| pour deux raisons. D'abord, il y a de plus en plus de code
| qu'y compte, et qu'on ne veut pas casser, et deuxièmement,
| le deuxième alternatif n'est pas implémentable s'il y a des
| cycles (et la norme dit que si on le choisit, il faut qu'il
| marche -- sans exception pour des cycles).
|
| Dans la pratique, je crois qu'on peut dire que dans
| l'absence des objets linkés dynamiquement, les statiques
| sont initialisés avant l'entrée dans main.

Sauf que dans la pratique, il y a de plus en plus d'objets dynamiquement
liés.

-- Gaby
1 2