TetaTricks/chap/plugins.tex

111 lines
3.5 KiB
TeX

\chapter{Plugins}
\index{plugin}
% ------------------------------------
Le concept de bibliothèque partagée
(\textsl{shared library} en anglais est apparu, du moins
dans le monde Unix, avec \textsl{SunOS 4}, en 1989.
Mais il est probable que ce concept existait déja dans
d'autres mondes, peut-être avec \textsl{AmigaOS} ou
\textsl{VAX/VMS}\index{VMS}\dots
Une bibliothèque partagé (aka \texttt{.so}) est une collection
de fonctions, chargée une seule fois en mémoire centrale,
mais qui peut être utilisée par plusieurs programmes en
même temps.\index{.so}
Et c'est en partie sur ce concept qu'est basé le premier
mécanisme que nous allons découvrir~:
\texttt{dlopen} et sa petite famille.
% ------------------------------------
\section{Mécanisme}
\index{dlopen} \index{dlclose}
\texttt{dlclose, dlopen, dlmopen - open and close a shared object}
\begin{quote}
The function dlopen() loads the dynamic shared object (shared library)
file named by the null-terminated string filename and returns an opaque
"handle" for the loaded object. This handle is employed with other
functions in the dlopen API, such as dlsym(3), dladdr(3), dlinfo(3),
and dlclose().
\end{quote}
Traduit en clair, la fonction \texttt{dlopen} permet de charger
manuellement une bibliothèque partagée (un \texttt{.so})
en mémoire centrale, au lieu de
laisser faire le loader (ld.so) automatiquement au lancement
d'un binaire. la fonction \texttt{dlclose} va, elle, vidanger
la zone mémoire dans laquelle est le plugin.
% ------------------------------------
\section{Un exemple ?}
\label{ex_dlopen}
Comme d'habitude, je vais proposer un exemple un peu artificiel,
mais qui, de part sa simplicité, illustrera clairement
les concepts de base. Partons du principe que nous avons
un tableau de quatre nombres flottants, et que nous souhaitons
proposer un affichage de ce tableau modifiable à volonté.
Nous allons donc écrire notre fonction personnelle d'affichage
dans un fichier \textsc{.c} indépendant
(ci-après dénommé «le plugiciel») et qui
sera chargé dynamiquement au \textsl{run-time} par le logiciel
principal (l'appelant).
\subsection{Le plugiciel}
C'est ici que nous trouverons le code actif de l'exemple,
l'utilité de notre \textsl{usecase} reste à déterminer par nos
lecteurs, mais seulement à titre d'exercice.
\lstinputlisting[language=c]{code/plugiciel.c}
On peut difficilement faire plus simple pour une première
approche, mais attendez la suite des opérations,
la cinquième va vous étonner.
\subsection{L'appelant}
Voyons maintenant comment mettre ça en œuvre depuis le programme
principal.
Nous supposerons que le binaire du plugin est dans le répertoire
courant. Pour les autres cas, il faut jouer avec la variable
d'environnement \texttt{LD\_LIBRARY\_PATH} (cf man dlopen(3)) ou
le fichier \texttt{/etc/ld.so.cache} (cf man ldconfig(8)).
\lstinputlisting[language=c]{code/appelant.c}
Ah, les choses se corsent un peu, il y a un pointeur bien
tortueux à déchiffrer. Il était temps.
\texttt{void (*funcname)(const char*, const float *);}
\subsection{Le run}
\begin{verbatim}
tth@fubar:~/Documents/TetaTricks/code$ make plugin
gcc -Wall -shared -fPIC plugiciel.c -o plugiciel.so
gcc -Wall appelant.c -ldl -o appelant
tth@fubar:~/Documents/TetaTricks/code$ ./appelant
rgb * a = : 6.685000 8.320000 1.570795
tth@fubar:~/Documents/TetaTricks/code$
\end{verbatim}
% ------------------------------------
\section{Autres langages}
En Perl\index{Perl} ?
En Fortran\index{Fortran} ?
% -------------- to be continued