1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
|
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE manualpage SYSTEM "./style/manualpage.dtd">
<?xml-stylesheet type="text/xsl" href="./style/manual.fr.xsl"?>
<!-- French translation : Lucien GENTIS -->
<!-- Reviewed by : Vincent Deffontaines -->
<!-- English Revision : 1199481 -->
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manualpage metafile="dso.xml.meta">
<title>Support des objets dynamiques partagés (DSO)</title>
<summary>
<p>La conception modulaire du serveur HTTP Apache permet à l'administrateur
de choisir les fonctionnalités à inclure dans le serveur en sélectionnant
un certain nombre de modules. Les modules seront compilés en tant
qu'Objets Dynamiques Partagés (Dynamic Shared Objects ou DSOs)
qui mènent une existence séparée du fichier binaire principal
<program>httpd</program>. Les modules DSO peuvent être compilés en
même temps que le serveur, ou compilés et ajoutés ultérieurement via
l'Outil des Extensions à Apache (Apache Extension Tool ou
<program>apxs</program>).</p>
<p>Les modules peuvent aussi être intégrés statiquement dans le
binaire <program>httpd</program> lors de la compilation de ce
dernier.</p>
<p>Ce document décrit l'utilisation des modules DSO ainsi que les dessous
de leur fonctionnement.</p>
</summary>
<section id="implementation"><title>Implémentation</title>
<related>
<modulelist>
<module>mod_so</module>
</modulelist>
<directivelist>
<directive module="mod_so">LoadModule</directive>
</directivelist>
</related>
<p>Le support DSO pour le chargement de modules individuels d'Apache
httpd est
assuré par un module nommé <module>mod_so</module> qui doit être compilé
statiquement dans le coeur d'Apache httpd. Il s'agit du seul module avec le
module <module>core</module> à ne pas pouvoir être compilé en tant que
module DSO lui-même. Pratiquement tous les autres modules d'Apache httpd
distribués seront alors compilés en tant que modules DSO. Une fois
compilé en tant que module DSO nommé <code>mod_foo.so</code>, un
module peut être chargé en mémoire au
démarrage ou redémarrage du serveur à l'aide de
la directive <directive module="mod_so">LoadModule</directive> du module
<module>mod_so</module>, placée
dans votre fichier <code>httpd.conf</code>.</p>
<p>La compilation en mode DSO peut être désactivée pour certains
modules via l'option <code>--enable-mods-static</code> du script
<program>configure</program>, comme expliqué dans la <a
href="install.html">Documentation sur l'installation</a>.</p>
<p>Un utilitaire permet de simplifier la création de
fichiers DSO pour les modules d'Apache httpd
(particulièrement pour les modules tiers) ; il s'agit du programme nommé
<program>apxs</program> (<dfn>APache
eXtenSion</dfn>). On peut l'utiliser pour construire des modules de type
DSO <em>en dehors</em> de l'arborescence des sources d'Apache httpd. L'idée est
simple : à l'installation du serveur HTTP Apache, la procédure <code>make install</code>
du script <program>configure</program> installe les fichiers d'en-têtes
d'Apache httpd et positionne, pour la plateforme de compilation, les drapeaux du compilateur et de
l'éditeur de liens à l'intérieur du programme
<program>apxs</program>, qui sera utilisé pour la construction de fichiers DSO.
Il est ainsi possible d'utiliser le programme <program>apxs</program>
pour compiler ses sources de modules Apache httpd sans avoir besoin de
l'arborescence des sources de la distribution d'Apache, et sans avoir à
régler les drapeaux du compilateur et de l'éditeur de liens pour le support DSO.</p>
</section>
<section id="usage"><title>Mode d'emploi succinct</title>
<p>Afin que vous puissiez vous faire une idée des fonctionnalités DSO
du serveur HTTP Apache 2.x, en voici un résumé court et concis :</p>
<ol>
<li>
<p>Construire et installer un module Apache httpd <em>faisant partie de la
distribution</em>, par exemple <code>mod_foo.c</code>,
en tant que module DSO <code>mod_foo.so</code> :</p>
<example>
$ ./configure --prefix=/chemin/vers/installation --enable-foo<br />
$ make install
</example>
</li>
<li>
<p>Configure le serveur HTTP Apache avec tous les modules
activés. Seul un jeu de modules de base sera chargé au
démarrage du serveur. Vous pouvez modifier ce jeu de modules
chargés au démarrage en activant ou désactivant les directives <directive
module="mod_so">LoadModule</directive> correspondantes dans le
fichier <code>httpd.conf</code>.</p>
<example>
$ ./configure --enable-mods-shared=all<br />
$ make install
</example>
<p>L'argument <code>most</code> de l'option
<code>--enable-modules</code> indique que tous les modules
non-expérimentaux ou qui ne sont pas là à titre d'exemple seront
compilés.</p>
</li>
<li>
<p>Certains modules ne sont utilisés que par les développeurs et
ne seront pas compilés. Si vous voulez les utiliser, spécifiez
l'option <em>all</em>. Pour compiler tous les modules disponibles,
y compris les modules de développeurs, spécifiez l'option
<em>reallyall</em>. En outre, la directive <directive
module="mod_so">LoadModule</directive> peut être activée pour tous
les modules compilés via l'option du script configure
<code>--enable-load-all-modules</code>.</p>
<example>
$ ./configure --enable-mods-shared=reallyall --enable-load-all-modules<br />
$ make install
</example>
</li>
<li>
Construire et installer un module Apache httpd <em>tiers</em>, par exemple
<code>mod_foo.c</code>, en tant que module DSO
<code>mod_foo.so</code> <em>en dehors</em> de l'arborescence des sources
d'Apache httpd à l'aide du programme <program>apxs</program> :
<example>
$ cd /chemin/vers/module_tiers<br />
$ apxs -cia mod_foo.c
</example>
</li>
</ol>
<p>Dans tous les cas, une fois le module partagé compilé, vous devez
ajouter une directive <directive module="mod_so">LoadModule</directive>
dans le fichier <code>httpd.conf</code> pour qu'Apache httpd active le module.</p>
<p>Voir la <a href="programs/apxs.html">documentation sur apxs</a>
pour plus de détails.</p>
</section>
<section id="background"><title>Les dessous du fonctionnement des DSO</title>
<p>Les clônes modernes d'UNIX proposent un mécanisme
appelé édition de liens et chargement dynamiques d'
<em>Objets Dynamiques Partagés</em> (DSO), qui permet de construire un
morceau de programme dans un format spécial pour le rendre chargeable
à l'exécution dans l'espace d'adressage d'un programme exécutable.</p>
<p>Ce chargement peut s'effectuer de deux manières : automatiquement par
un programme système appelé <code>ld.so</code> quand un programme
exécutable est démarré, ou manuellement à partir du programme en cours
d'exécution via sa propre interface système vers le chargeur Unix à l'aide
des appels système <code>dlopen()/dlsym()</code>.</p>
<p>Dans la première méthode, les DSO sont en général appelés
<em>bibliothèques partagées</em> ou encore <em>bibliothèques DSO</em>, et
possèdent des noms du style
<code>libfoo.so</code> ou <code>libfoo.so.1.2</code>. Ils résident dans un
répertoire système (en général <code>/usr/lib</code>)
et le lien avec le programme exécutable est établi à la compilation en
ajoutant <code>-lfoo</code> à la commande de l'éditeur de liens. Les
références à la bibliothèque sont ainsi codées en dur dans le fichier du
programme exécutable de façon à ce qu'au démarrage du programme, le
chargeur Unix soit capable de localiser <code>libfoo.so</code> dans
<code>/usr/lib</code>, dans des chemins codés en dur à l'aide d'options de
l'éditeur de liens comme <code>-R</code> ou dans des chemins définis par la
variable d'environnement
<code>LD_LIBRARY_PATH</code>. Le chargeur peut dès lors résoudre tous les symboles
(jusque là non encore résolus) du DSO dans le programme exécutable.</p>
<p>Les symboles du programme exécutable ne sont en général pas
référencés par le DSO (car c'est une bibliothèque de code à usage général
et réutilisable),
et ainsi aucune résolution supplémentaire n'est nécessaire. De son côté,
le programme exécutable ne doit accomplir aucune action particulière
pour utiliser les
symboles du DSO car toutes les résolutions sont effectuées par le chargeur
Unix. En fait, le code permettant d'invoquer
<code>ld.so</code> fait partie du code de démarrage pour l'exécution qui
est lié dans tout programme exécutable non statiquement lié.
L'avantage du chargement dynamique du code d'une bibliothèque partagée est
évident : le code de la bibliothèque ne doit être stocké qu'une seule fois
dans une bibliothèque système telle que <code>libc.so</code>, ce qui permet
d'économiser de l'espace disque pour les autres programmes.</p>
<p>Dans la seconde méthode, les DSO sont en général appelés <em>objets
partagés</em> ou <em>fichiers DSO</em>, et peuvent être nommés avec
l'extension de son choix (bien que le nom conseillé soit du style
<code>foo.so</code>). Ces fichiers résident en général dans un répertoire
spécifique à un programme, et aucun lien n'est automatiquement établi avec
le programme exécutable dans lequel ils sont utilisés.
Le programme exécutable charge manuellement le DSO à l'exécution dans son
espace d'adressage à l'aide de l'appel système <code>dlopen()</code>.
A ce moment, aucune résolution de symboles du DSO n'est effectuée pour le
programme exécutable. Par contre le chargeur Unix
résoud automatiquement tout symbole du DSO (non encore résolu)
faisant partie de l'ensemble de symboles exporté par le programme
exécutable et ses bibliothèques DSO déjà chargées (et en particulier tous
les symboles de la bibliothèque à tout faire <code>libc.so</code>).
De cette façon, le DSO prend connaissance de l'ensemble de symboles du
programme exécutable comme s'il avait été lié statiquement avec lui
auparavant.</p>
<p>Finalement, pour tirer profit de l'API des DSO, le programme exécutable
doit résoudre certains symboles du DSO à l'aide de l'appel système
<code>dlsym()</code> pour une utilisation ultérieure dans les tables de
distribution, <em>etc...</em> En d'autres termes, le programme exécutable doit
résoudre manuellement tous les symboles dont il a besoin pour pouvoir les
utiliser.
Avantage d'un tel mécanisme : les modules optionnels du programme n'ont pas
besoin d'être chargés (et ne gaspillent donc pas de ressources mémoire)
tant qu'il ne sont pas nécessaires au programme en question. Si nécessaire,
ces modules peuvent être chargés dynamiquement afin d'étendre les
fonctionnalités de base du programme.</p>
<p>Bien que ce mécanisme DSO paraisse évident, il comporte au moins une
étape difficile : la résolution des symboles depuis le programme exécutable
pour le DSO lorsqu'on utilise un DSO pour étendre les fonctionnalités d'un
programme (la seconde méthode). Pourquoi ? Parce que la "résolution
inverse" des symboles DSO à partir du jeu de symboles du programme
exécutable dépend de la conception de la bibliothèque (la bibliothèque n'a
aucune information sur le programme qui l'utilise) et n'est ni standardisée
ni disponible sur toutes les plateformes. En pratique, les symboles globaux
du programme exécutable ne sont en général pas réexportés et donc
indisponibles pour l'utilisation dans un DSO. Trouver une méthode pour
forcer l'éditeur de liens à exporter tous les symboles globaux est le
principal problème que l'on doit résoudre lorsqu'on utilise un DSO pour
étendre les fonctionnalités d'un programme au moment de son exécution.</p>
<p>L'approche des bibliothèques partagées est la plus courante, parce que
c'est dans cette optique que le mécanisme DSO a été conçu ; c'est cette
approche qui est ainsi
utilisée par pratiquement tous les types de bibliothèques que fournit le
système d'exploitation.</p>
</section>
<section id="advantages"><title>Avantages et inconvénients</title>
<p>Les fonctionnalités ci-dessus basées sur les DSO présentent les
avantages suivants :</p>
<ul>
<li>Le paquetage du serveur est plus flexible à l'exécution car le
processus serveur peut être assemblé à l'exécution via la
directive <directive module="mod_so">LoadModule</directive> du fichier de
configuration <code>httpd.conf</code> plutôt que par des options du script
<program>configure</program> à la compilation. Par exemple,
on peut ainsi exécuter différentes instances du serveur
(standard et version SSL, version minimale et version dynamique
[mod_perl, mod_php], <em>etc...</em>) à partir d'une seule installation
d'Apache httpd.</li>
<li>Le paquetage du serveur peut être facilement étendu avec des modules
tiers, même après l'installation. Ceci présente un gros
avantage pour les mainteneurs de paquetages destinés aux distributions,
car ils peuvent créer un paquetage Apache httpd de base, et des paquetages
additionnels contenant des extensions telles que PHP, mod_perl, mod_fastcgi,
<em>etc...</em></li>
<li>Une facilité de prototypage des modules Apache httpd, car la paire
DSO/<program>apxs</program> vous permet d'une part de travailler en
dehors de l'arborescence des sources d'Apache httpd, et d'autre part de n'avoir
besoin que de la commande <code>apxs -i</code>
suivie d'un <code>apachectl restart</code> pour introduire une nouvelle
version de votre module fraîchement développé dans le serveur HTTP Apache
en cours d'exécution.</li>
</ul>
<p>Inconvénients des DSO :</p>
<ul>
<li>Le serveur est environ 20 % plus lent au démarrage
à cause des résolutions de symboles supplémentaires que le chargeur
Unix doit effectuer.</li>
<li>Le serveur est environ 5 % plus lent à l'exécution
sur certaines plates-formes, car le code indépendant de la position (PIC)
nécessite parfois des manipulations compliquées en assembleur pour
l'adressage relatif qui ne sont pas toujours aussi rapides que celles
que permet l'adressage absolu.</li>
<li>Comme les modules DSO ne peuvent pas être liés avec d'autres
bibliothèques basées sur DSO (<code>ld -lfoo</code>) sur toutes les
plates-formes
(par exemple, les plates-formes basées sur a.out ne fournissent en
général pas cette fonctionnalité alors que les plates-formes basées sur
ELF le font), vous ne pouvez pas utiliser le mécanisme DSO pour tous les
types de modules. Ou en d'autres termes, les modules compilés comme
fichiers DSO sont contraints de n'utiliser que les symboles du coeur
d'Apache httpd, de la bibliothèque C
(<code>libc</code>) et toutes autres bibliothèques statiques ou
dynamiques utilisées par le coeur d'Apache httpd, ou d'archives statiques
(<code>libfoo.a</code>) contenant du code indépendant de la
position (PIC).
Il y a deux solutions pour utiliser un autre type de code : soit le
coeur d'Apache httpd contient déjà lui-même une référence au code, soit vous
chargez le code vous-même via <code>dlopen()</code>.</li>
</ul>
</section>
</manualpage>
|