Au moins dans le cas de la statique des bibliothèques, vous pouvez le contourner assez facilement.
Tenir compte de ces en-têtes des bibliothèques de foo et bar. Pour l'amour de ce tutoriel, je vais aussi vous donner les fichiers source
exemples/ex01/foo.h
int spam(void);
double eggs(void);
exemples/ex01/foo.c (ce qui peut être opaque/non disponible)
int the_spams;
double the_eggs;
int spam()
{
return the_spams++;
}
double eggs()
{
return the_eggs--;
}
exemple/ex01/bar.h
int spam(int new_spams);
double eggs(double new_eggs);
exemples/ex01/bar.c (ce qui peut être opaque/non disponible)
int the_spams;
double the_eggs;
int spam(int new_spams)
{
int old_spams = the_spams;
the_spams = new_spams;
return old_spams;
}
double eggs(double new_eggs)
{
double old_eggs = the_eggs;
the_eggs = new_eggs;
return old_eggs;
}
Nous voulons utiliser ces dans un programme de foobar
exemple/ex01/foobar.c
#include <stdio.h>
#include "foo.h"
#include "bar.h"
int main()
{
const int new_bar_spam = 3;
const double new_bar_eggs = 5.0f;
printf("foo: spam = %d, eggs = %f\n", spam(), eggs() );
printf("bar: old spam = %d, new spam = %d ; old eggs = %f, new eggs = %f\n",
spam(new_bar_spam), new_bar_spam,
eggs(new_bar_eggs), new_bar_eggs );
return 0;
}
Un problème apparaît immédiatement: C ne connaît pas la surcharge. Nous avons donc deux fois deux fonctions avec
nom identique mais de signature différente. Nous avons donc besoin d'un moyen pour distinguer ceux-ci. De toute façon, permet de voir ce qu'est un
compilateur a à dire à ce sujet:
example/ex01/ $ make
cc -c -o foobar.o foobar.c
In file included from foobar.c:4:
bar.h:1: error: conflicting types for ‘spam'
foo.h:1: note: previous declaration of ‘spam' was here
bar.h:2: error: conflicting types for ‘eggs'
foo.h:2: note: previous declaration of ‘eggs' was here
foobar.c: In function ‘main':
foobar.c:11: error: too few arguments to function ‘spam'
foobar.c:11: error: too few arguments to function ‘eggs'
make: *** [foobar.o] Error 1
Bon, ce n'était pas une surprise, il m'a seulement dit de nous, ce que nous savions déjà, ou au moins soupçonné.
Si nous pouvons en quelque sorte résoudre que l'identifiant de collision sans modifier l'original des bibliothèques
le code source ou les en-têtes? En fait, nous pouvons.
D'abord, permet de régler le temps de compilation des questions. Pour cela, nous avons entourent l'en-tête comprend un
tas de préprocesseur #define
directives du préfixe tous les symboles exportés par la bibliothèque.
Plus tard, nous le faisons avec quelques agréables wrapper-d'en-tête, mais juste pour le plaisir de démontrer
ce qu'il se passe sur le faisaient mot à mot dans l' foobar.c fichier source:
exemple/ex02/foobar.c
#include <stdio.h>
#define spam foo_spam
#define eggs foo_eggs
# include "foo.h"
#undef spam
#undef eggs
#define spam bar_spam
#define eggs bar_eggs
# include "bar.h"
#undef spam
#undef eggs
int main()
{
const int new_bar_spam = 3;
const double new_bar_eggs = 5.0f;
printf("foo: spam = %d, eggs = %f\n", foo_spam(), foo_eggs() );
printf("bar: old spam = %d, new spam = %d ; old eggs = %f, new eggs = %f\n",
bar_spam(new_bar_spam), new_bar_spam,
bar_eggs(new_bar_eggs), new_bar_eggs );
return 0;
}
Maintenant, si nous compilons ce...
example/ex02/ $ make
cc -c -o foobar.o foobar.c
cc foobar.o foo.o bar.o -o foobar
bar.o: In function `spam':
bar.c:(.text+0x0): multiple definition of `spam'
foo.o:foo.c:(.text+0x0): first defined here
bar.o: In function `eggs':
bar.c:(.text+0x1e): multiple definition of `eggs'
foo.o:foo.c:(.text+0x19): first defined here
foobar.o: In function `main':
foobar.c:(.text+0x1e): undefined reference to `foo_eggs'
foobar.c:(.text+0x28): undefined reference to `foo_spam'
foobar.c:(.text+0x4d): undefined reference to `bar_eggs'
foobar.c:(.text+0x5c): undefined reference to `bar_spam'
collect2: ld returned 1 exit status
make: *** [foobar] Error 1
... d'abord il semble que les choses ont empiré. Mais regardez de plus près: en Fait, la phase de compilation
est allé très bien. C'est juste l'éditeur de liens qui se plaignent aujourd'hui qu'il y a des symboles de la collision
et il nous raconte l'emplacement (fichier source et ligne) où cela se produit. Et comme on peut le voir
ces symboles sont unprefixed.
Nous allons prendre un regard sur les tables de symboles avec la nm utilitaire:
example/ex02/ $ nm foo.o
0000000000000019 T eggs
0000000000000000 T spam
0000000000000008 C the_eggs
0000000000000004 C the_spams
example/ex02/ $ nm bar.o
0000000000000019 T eggs
0000000000000000 T spam
0000000000000008 C the_eggs
0000000000000004 C the_spams
Alors maintenant, nous avons des problèmes avec l'exercice de préfixe de ces symboles dans certains binaire opaque. Oui, je sais
dans le cadre de cet exemple, nous avons les sources et la possibilité de changer cela. Mais pour l'instant, il suffit de supposer
vous avez seulement ceux .o fichiers, ou un .un (qui est en fait juste un tas de .o).
objcopy à la rescousse
Il est un outil particulièrement intéressant pour nous: objcopy
objcopy travaille sur des fichiers temporaires, de sorte que nous pouvons l'utiliser comme s'il s'agissait d'exploitation en place. Il y en a un
option/opération appelée" --prefix-symboles et vous avez 3 devine ce qu'il fait.
Donc, nous allons jeter ce gars sur notre têtu bibliothèques:
example/ex03/ $ objcopy --prefix-symbols=foo_ foo.o
example/ex03/ $ objcopy --prefix-symbols=bar_ bar.o
nm nous montre que cela semblait fonctionner:
example/ex03/ $ nm foo.o
0000000000000019 T foo_eggs
0000000000000000 T foo_spam
0000000000000008 C foo_the_eggs
0000000000000004 C foo_the_spams
example/ex03/ $ nm bar.o
000000000000001e T bar_eggs
0000000000000000 T bar_spam
0000000000000008 C bar_the_eggs
0000000000000004 C bar_the_spams
Permet d'essayer de lier ce truc:
example/ex03/ $ make
cc foobar.o foo.o bar.o -o foobar
Et en effet, il a travaillé:
example/ex03/ $ ./foobar
foo: spam = 0, eggs = 0.000000
bar: old spam = 0, new spam = 3 ; old eggs = 0.000000, new eggs = 5.000000
Maintenant, je laisse en exercice au lecteur de mettre en œuvre un outil ou un script qui extrait automatiquement les
symboles d'une bibliothèque à l'aide nm, écrit un wrapper fichier d'en-tête de la structure
/* wrapper header wrapper_foo.h for foo.h */
#define spam foo_spam
#define eggs foo_eggs
/* ... */
#include <foo.h>
#undef spam
#undef eggs
/* ... */
et applique le symbole du préfixe à la bibliothèque statique de l'objet de fichiers à l'aide de objcopy.
Quid des bibliothèques partagées?
En principe, la même chose peut être fait avec les bibliothèques partagées. Cependant bibliothèques partagées, le nom l'indique,
sont partagés entre de multiples programmes, afin de jouer avec une bibliothèque partagée de cette façon n'est pas une bonne idée.
Vous n'obtiendrez pas autour de l'écriture d'un trampoline wrapper. Pire encore vous ne pouvez pas lier à l'encontre de la bibliothèque partagée
sur le fichier d'objet de niveau, mais sont contraints de faire le chargement dynamique. Mais cela mérite son propre article.
Restez à l'écoute, et bon codage.