{"id":1454,"date":"2012-01-28T10:00:43","date_gmt":"2012-01-28T09:00:43","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=1454"},"modified":"2012-01-28T10:00:43","modified_gmt":"2012-01-28T09:00:43","slug":"mise-au-point-de-bibliotheque-dynamique-1-compilation-versions-et-liens-symboliques","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/01\/28\/mise-au-point-de-bibliotheque-dynamique-1-compilation-versions-et-liens-symboliques\/","title":{"rendered":"Mise au point de biblioth\u00e8que dynamique (1\/3)"},"content":{"rendered":"<p style=\"text-align: justify;\">(<a title=\"Development of a dynamic library (1\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/01\/28\/development-of-a-dynamic-library-13\/\">English translation here<\/a>)<\/p>\n<p style=\"text-align: justify;\">Lors d&rsquo;une r\u00e9cente session de formation, une conversation avec un participant m&rsquo;a pouss\u00e9 \u00e0 v\u00e9rifier les options n\u00e9cessaires pour effectuer du d\u00e9bogage et des tests en couverture sur une biblioth\u00e8que partag\u00e9e.<\/p>\n<p>\n<!--more-->\n<\/p>\n<p style=\"padding-left: 60px; text-align: justify;\">Une biblioth\u00e8que dynamique (fichier <code>lib<em>XXXX<\/em>.so<\/code> &#8211; <code>so<\/code> pour <em>Shared Object<\/em>) est charg\u00e9e dans la m\u00e9moire du processus au moment de son d\u00e9marrage. Le fichier ex\u00e9cutable et la biblioth\u00e8que sont ind\u00e9pendants avant le lancement de l&rsquo;application, et peuvent \u00eatre maintenus s\u00e9par\u00e9ment.<\/p>\n<p style=\"text-align: justify;\">J&rsquo;ai r\u00e9alis\u00e9 que certains points \u00e9taient loin d&rsquo;\u00eatre \u00e9vidents, par exemple la gestion des num\u00e9ros de version ou l&rsquo;activation des tests en couverture. Voici un petit r\u00e9capitulatif des \u00e9tapes de mise au point d&rsquo;une biblioth\u00e8que dynamique. Le premier article est consacr\u00e9 \u00e0 la compilation, la gestion des versions et la cr\u00e9ation des liens symboliques n\u00e9cessaires. <a title=\"Mise au point de biblioth\u00e8que dynamique (2\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/02\/04\/mise-au-point-de-bibliotheque-dynamique-23\/\" target=\"_blank\">Le second<\/a> s&rsquo;int\u00e9ressera au d\u00e9bogage et au suivi pas-\u00e0-pas du code de la biblioth\u00e8que depuis une application. Le troisi\u00e8me d\u00e9crira comment effectuer des tests en couverture sur le contenu de la biblioth\u00e8que.<\/p>\n<h1>Compilation et installation de la biblioth\u00e8que<\/h1>\n<h2>Compilation du code de la biblioth\u00e8que<\/h2>\n<p style=\"text-align: justify;\">Commen\u00e7ons par cr\u00e9er une petite biblioth\u00e8que dynamique, avec une fonction relativement simple&nbsp;: l&rsquo;impl\u00e9mentation de la fonction math\u00e9matique \u00ab\u00a0factorielle\u00a0\u00bb.<\/p>\n<p style=\"text-align: justify;\">Je cr\u00e9e un r\u00e9pertoire de travail <code>factorielle<\/code> regroupant tous les fichiers concernant cette biblioth\u00e8que. Nous y cr\u00e9ons trois sous-r\u00e9pertoires\u00a0:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><code>src\/<\/code> qui contiendra le code source de la biblioth\u00e8que,<\/li>\n<li style=\"text-align: justify;\"><code>lib\/<\/code> o\u00f9 seront regoup\u00e9s les fichiers binaires et les liens symboliques d\u00e9crits plus bas,<\/li>\n<li style=\"text-align: justify;\"><code>include\/<\/code> dans lequel les fichiers d&rsquo;en-t\u00eate de la biblioth\u00e8que seront stock\u00e9s.<\/li>\n<\/ul>\n<pre>[~]$ <strong>mkdir factorielle<\/strong>\n[~]$ <strong>mkdir factorielle\/src<\/strong>\n[~]$ <strong>mkdir factorielle\/include<\/strong>\n[~]$ <strong>mkdir factorielle\/lib<\/strong>\n[~]$ <strong>cd factorielle<\/strong>\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Cr\u00e9ons un fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact.c\" target=\"_blank\"><code>src\/fact.c<\/code><\/a> impl\u00e9mentant notre fonction.<\/p>\n<p style=\"text-align: justify; padding-left: 60px;\">Et si vous pensez avoir trouv\u00e9 un bug dans le code ci-dessous, ayez la gentillesse de lire l&rsquo;article en entier avant de m&rsquo;envoyer un mail de moquerie \ud83d\ude09<\/p>\n<pre>#include &lt;fact.h&gt;\n\nlong long int factorielle(long int n)\n{\n        long long int f = 1;\n        do {\n                f = f * n;\n                n = n - 1;\n        } while (n &gt; 1);\n        return f;\n}<\/pre>\n<p style=\"text-align: justify;\">Ce fichier commence par inclure son propre fichier d&rsquo;en-t\u00eate, ce qui permet de s&rsquo;assurer \u00e0 la compilation de la concordance du prototype et de l&rsquo;impl\u00e9mentation.<\/p>\n<p style=\"text-align: justify;\">Le fichier <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact.h\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact.h\" target=\"_blank\"><code>include\/fact.h<\/code><\/a> contient les lignes suivantes.<\/p>\n<pre>#ifndef LIB_FACT_H\n#define LIB_FACT_H\n    long long int factorielle(long int n);\n#endif<\/pre>\n<p style=\"text-align: justify;\">Lors de la compilation de ce fichier nous fournirons sur la ligne de commande de <code>gcc<\/code> les options:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><code>-c<\/code> pour arr\u00eater <code>gcc<\/code> apr\u00e8s la phase de compilation et obtenir ainsi un fichier objet (pas d&rsquo;\u00e9dition des liens).<\/li>\n<li style=\"text-align: justify;\"><code>-I include\/<\/code> qui indique \u00e0 <code>gcc<\/code> de rechercher les fichiers d&rsquo;en-t\u00eate <code>.h<\/code> dans le r\u00e9pertoire <code>include\/<\/code> en suppl\u00e9ment des r\u00e9pertoires usuels (<code>\/usr\/include<\/code>\u2026).<\/li>\n<li style=\"text-align: justify;\"><code>-fPIC<\/code> pour demander la g\u00e9n\u00e9ration d&rsquo;un code relogeable (<em>Position Independant Code<\/em>) comme c&rsquo;est n\u00e9cessaire pour la cr\u00e9ation de biblioth\u00e8ques partag\u00e9es m\u00eame si cette option n&rsquo;est pas\u00a0 indispensable sur certaines architectures (x86 32 bits par exemple).<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Voici un exemple de compilation.<\/p>\n<pre>[factorielle]$ <strong>ls src\/<\/strong>\nfact.c\n[factorielle]$ <strong>ls include\/<\/strong>\nfact.h\n[factorielle]$ <strong>gcc -c -I include\/ -fPIC -Wall -o src\/fact.o src\/fact.c<\/strong>\n[factorielle]$ <strong>ls src\/<\/strong>\nfact.c fact.o\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Cette compilation a g\u00e9n\u00e9r\u00e9 un fichier objet <code>fact.o<\/code> que nous utiliserons ci-apr\u00e8s.<\/p>\n<p style=\"text-align: justify;\">On notera que durant la phase de test et de mise au point, il ne faut utiliser aucune option d&rsquo;optimisation, sinon le compilateur risque de modifier le code ex\u00e9cutable cr\u00e9\u00e9 (en regroupant des blocs de code par exemple) et il n&rsquo;y aura plus de correspondance exacte avec le fichier source.<\/p>\n<h2>G\u00e9n\u00e9ration de la biblioth\u00e8que<\/h2>\n<p style=\"text-align: justify;\">La biblioth\u00e8que proprement dite est obtenue en invoquant <code>gcc<\/code> avec l&rsquo;option <code>-shared<\/code>. Nous allons lui demander d&rsquo;enregistrer la biblioth\u00e8que dans le fichier <code>libfact.so.1.0<\/code>. Les num\u00e9ros <code>1<\/code> et <code>0<\/code> correspondent respectivement aux num\u00e9ros majeur et mineur de version de la biblioth\u00e8que.<\/p>\n<p style=\"text-align: justify;\">Il est d&rsquo;usage de consid\u00e9rer qu&rsquo;un changement de num\u00e9ro majeur repr\u00e9sente une rupture de la compatibilit\u00e9 binaire de la biblioth\u00e8que et n\u00e9cessite une recompilation des applications, alors qu&rsquo;une variation du num\u00e9ro mineur signifie des corrections ou des am\u00e9liorations internes n&rsquo;influant pas sur l&rsquo;interface de programmation.<\/p>\n<p style=\"text-align: justify;\">Nous allons indiquer \u00e0 <code>gcc<\/code> d&rsquo;enregistrer dans l&rsquo;en-t\u00eate de la biblioth\u00e8que son nom officiel incluant le num\u00e9ro majeur de version avec l&rsquo;option <code>-Wl<\/code>. Celle-ci transmet au <em>linker<\/em> la cha\u00eene de caract\u00e8res qui la suit apr\u00e8s avoir remplac\u00e9 les virgules par des espaces. C&rsquo;est donc l&rsquo;option <code>-soname libfact.so.1<\/code> qui est pass\u00e9e.<\/p>\n<p style=\"text-align: justify;\">Il est conseill\u00e9 de r\u00e9p\u00eater les options pass\u00e9es lors de la compilation pr\u00e9c\u00e9dente, comme <code>-fPIC<\/code>.<\/p>\n<pre>[factorielle]$ <strong>gcc -fPIC -shared -Wl,-soname,libfact.so.1 -o lib\/libfact.so.1.0 src\/fact.o<\/strong>\n[factorielle]$ <strong>ls lib\/<\/strong>\nlibfact.so.1.0\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Nous disposons donc d&rsquo;un fichier <code>libfact.so.1.0<\/code> dont l&rsquo;en-t\u00eate contient le nom <code>libfact.so.1<\/code><\/p>\n<h2>Cr\u00e9ation des liens symboliques<\/h2>\n<p style=\"text-align: justify;\">Lorsque nous compilerons une application, nous pr\u00e9ciserons \u00e0 <code>gcc<\/code> de la lier avec la biblioth\u00e8que <code>fact<\/code>. Celui-ci recherchera un fichier <code>libfact.so<\/code>. Et non pas <code>libfact.so.1.0<\/code>. Aussi va-t-il falloir cr\u00e9er un lien symbolique pour indiquer le chemin vers le fichier. Ce lien est cr\u00e9\u00e9 manuellement avec la commande <code>ln<\/code>.<\/p>\n<pre>[factorielle]$ <strong>cd lib\/<\/strong>\n[lib]$ <strong>ln -sf libfact.so.1.0 libfact.so<\/strong>\n[lib]$ <strong>ls -l lib*<\/strong>\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:04 libfact.so -&gt; libfact.so.1.0\n-rwxrwxr-x 1 cpb cpb 6659 2012-01-27 10:02 libfact.so.1.0\n[lib]$<\/pre>\n<p style=\"text-align: justify;\">Lors de la compilation, <code>gcc<\/code> enregistrera dans le fichier ex\u00e9cutable g\u00e9n\u00e9r\u00e9 le nom de la biblioth\u00e8que qu&rsquo;il a utilis\u00e9. Il s&rsquo;agit du nom \u00ab\u00a0officiel\u00a0\u00bb qu&rsquo;il trouve dans la section <code>SONAME<\/code> que nous avons renseign\u00e9e avec l&rsquo;argument <code>-Wl,-soname<\/code> pr\u00e9c\u00e9dement.<\/p>\n<p style=\"text-align: justify;\">A l&rsquo;ex\u00e9cution, le chargeur recherche donc la biblioth\u00e8que dont le num\u00e9ro majeur correspond \u00e0 celui utilis\u00e9 lors de la compilation. Il va donc falloir qu&rsquo;il trouve un fichier <code>libfact.so.1<\/code>, ou plut\u00f4t un lien <code>libfact.so.1<\/code> qui pointe vers <code>libfact.so.1.0<\/code>.<\/p>\n<p style=\"text-align: justify;\">La cr\u00e9ation du premier lien symbolique \u00e9tait n\u00e9cessaire pour pouvoir <em>compiler<\/em> une application avec la biblioth\u00e8que, le second lien est indispensable pour pouvoir <em>ex\u00e9cuter<\/em> un programme li\u00e9 avec elle. Ce lien est donc utilis\u00e9 beaucoup plus fr\u00e9quemment que le pr\u00e9c\u00e9dent. Pour simplifier la vie de l&rsquo;administrateur, une commande nomm\u00e9e <code>ldconfig<\/code> va l&rsquo;aider \u00e0 cr\u00e9er automatiquement les liens dont son syst\u00e8me a besoin pour que les utilisateurs puissent ex\u00e9cuter les applications. Elle parcourt les r\u00e9pertoires-syst\u00e8me contenant des biblioth\u00e8ques (<code>\/lib<\/code>, <code>\/usr\/lib<\/code>, <code>\/usr\/local\/lib<\/code>, etc. plus tous ceux indiqu\u00e9s dans <code>\/etc\/ld.so.conf<\/code>) et cr\u00e9e sur chaque fichier de biblioth\u00e8que un lien avec le nom contenu dans sa section <code>SONAME<\/code>. Nous allons en voir un exemple en for\u00e7ant <code>ldconfig<\/code> \u00e0 explorer uniquement notre r\u00e9pertoire gr\u00e2ce \u00e0 son option <code>-n<\/code>.<\/p>\n<pre>[lib]$ <strong>ldconfig -n .<\/strong>\n[lib]$ <strong>ls -l lib*<\/strong>\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:04 libfact.so -&gt; libfact.so.1.0\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:05 libfact.so.1 -&gt; libfact.so.1.0\n-rwxrwxr-x 1 cpb cpb 6659 2012-01-27 10:02 libfact.so.1.0\n[lib]$<\/pre>\n<p style=\"text-align: justify;\">Les liens pr\u00e9sents permettront donc de compiler une application n\u00e9cessitant notre biblioth\u00e8que (par le biais de <code>libfact.so<\/code>) puis de l&rsquo;ex\u00e9cuter en s&rsquo;assurant que la version majeure soit la bonne (gr\u00e2ce \u00e0 <code>libfact.so.1<\/code>).<\/p>\n<h1>Utilisation de la biblioth\u00e8que<\/h1>\n<h2>Compilation d&rsquo;une application<\/h2>\n<p style=\"text-align: justify;\">\u00c9crivons un petit programme qui utilise notre biblioth\u00e8que. Le fichier <code><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/factorielle.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/factorielle.c\" target=\"_blank\">factorielle.c<\/a><\/code> va invoquer notre fonction <code>factorielle()<\/code> sur tous les nombres fournis sur sa ligne de commande.<\/p>\n<pre>#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;fact.h&gt;\n\nint main (int argc, char * argv[])\n{\n        long int n;\n        int i;\n        if (argc &lt; 2) {\n                fprintf(stderr, \"usage: %s valeurs...n\", argv[0]);\n                exit(EXIT_FAILURE);\n        }\n        for (i = 1; i &lt; argc; i ++)\n                if (sscanf(argv[i], \"%ld\", &amp; n) == 1)\n                        fprintf(stdout, \"%ld! = %lldn\", n, factorielle(n));\n        return EXIT_SUCCESS;\n}<\/pre>\n<p style=\"text-align: justify;\">Ce programme se trouve dans le r\u00e9pertoire <code>factorielle\/test\/<\/code> que nous cr\u00e9ons pour l&rsquo;occasion. Il inclut le fichier d&rsquo;en-t\u00eate <code>&lt;fact.h&gt;<\/code>. Il faudra donc que le compilateur puisse le trouver. Pour cela deux solutions\u00a0:<\/p>\n<ul>\n<li style=\"text-align: justify;\">placer le fichier d&rsquo;en-t\u00eate dans <code>\/usr\/include<\/code>, <code>\/usr\/local\/include<\/code> ou tout autre r\u00e9pertoire que <code>gcc<\/code> consulte &#8211; ceci doit \u00eatre r\u00e9serv\u00e9 aux fichiers cruciaux pour plusieurs applications utiles pour l&rsquo;ensemble du syst\u00e8me,<\/li>\n<li style=\"text-align: justify;\">laisser le fichier dans un r\u00e9pertoire sp\u00e9cifique \u00e0 notre biblioth\u00e8que et indiquer \u00e0 <code>gcc<\/code> o\u00f9 le trouver.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">C&rsquo;est naturellement la seconde option que je vais utiliser.<\/p>\n<p style=\"text-align: justify;\">En outre, nous ajouterons en fin de ligne l&rsquo;argument <code>-lfact<\/code> qui demande au <em>linker<\/em> de r\u00e9aliser l&rsquo;\u00e9dition des liens avec la biblioth\u00e8que <code>libfact.so<\/code>. Comme pour le fichier d&rsquo;en-t\u00eate il faudra pr\u00e9ciser \u00e0 <code>gcc<\/code> o\u00f9 il pourra trouver le fichier <code>libfact.so<\/code> que nous avons cr\u00e9\u00e9 plus haut sous forme de lien symbolique. C&rsquo;est le r\u00f4le de l&rsquo;option <code>-L<\/code>.<\/p>\n<pre>[factorielle]$ <strong>gcc -I .\/include\/ -L .\/lib\/ -o .\/test\/factorielle .\/test\/factorielle.c -lfact<\/strong>\n[factorielle]$ <strong><\/strong>\n[factorielle]$ <strong>ls -l test\/<\/strong>\ntotal 12\n-rwxrwxr-x 1 cpb cpb 7359 2012-01-27 10:41 factorielle\n-rw-r--r-- 1 cpb cpb  382 2012-01-25 18:29 factorielle.c\n[factorielle]$<\/pre>\n<h2>Ex\u00e9cution de l&rsquo;application<\/h2>\n<p style=\"text-align: justify;\">Si nous testons directement notre programme, son ex\u00e9cution \u00e9choue.<\/p>\n<pre>$ <strong>.\/test\/factorielle 4 5 6<\/strong>\n.\/test\/factorielle: error while loading shared libraries: libfact.so.1: cannot open shared object file: No such file or directory\n$<\/pre>\n<p style=\"text-align: justify;\">En effet, l&rsquo;\u00e9diteur de liens dynamique qui doit d\u00e9marrer le processus ne sait pas o\u00f9 trouver la biblioth\u00e8que. On remarque au passage qu&rsquo;il recherche bien le fichier <code>libfact.so.1<\/code> (avec le num\u00e9ro majeur comme extension). Si notre application est suffisamment importante pour \u00eatre employ\u00e9e r\u00e9guli\u00e8rement par diff\u00e9rents utilisateurs, il est l\u00e9gitime de placer les fichiers de biblioth\u00e8que dans <code>\/usr\/local\/lib<\/code> o\u00f9 le <em>linker<\/em> les trouvera. Toutefois si l&rsquo;application est en phase de mise au point ou r\u00e9serv\u00e9e \u00e0 un emploi rare, on pr\u00e9f\u00e9rera laisser les biblioth\u00e8ques dans un r\u00e9pertoire personnel. Dans ce cas, il faudra remplir (\u00e9ventuellement dans un script de lancement) la variable d&rsquo;environnement <code>LD_LIBRARY_PATH<\/code> pour ajouter le chemin d&rsquo;acc\u00e8s \u00e0 ces fichiers.<\/p>\n<pre>[factorielle]$ <strong>export LD_LIBRARY_PATH=.\/lib\/ <\/strong>\n[factorielle]$ <strong>.\/test\/factorielle 4 5 6<\/strong>\n4! = 24\n5! = 120\n6! = 720\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Bien s\u00fbr, le contenu de la variable <code>LD_LIBRARY_PATH<\/code> peut \u00eatre renseign\u00e9 avec un chemin absolu plut\u00f4t que relatif si on souhaite lancer le programme ex\u00e9cutable depuis un emplacement quelconque.<\/p>\n<div id=\"attachment_1497\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/figure-1.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1497\" class=\"size-medium wp-image-1497\" title=\"Biblioth\u00e8que dynamique version 1.0\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/figure-1-300x188.png\" alt=\"Biblioth\u00e8que dynamique version 1.0\" width=\"300\" height=\"188\" \/><\/a><p id=\"caption-attachment-1497\" class=\"wp-caption-text\">Biblioth\u00e8que dynamique version 1.0<\/p><\/div>\n<h1>Maintenance de la biblioth\u00e8que<\/h1>\n<h2>Modification de version mineure<\/h2>\n<p style=\"text-align: justify;\">Notre biblioth\u00e8que semble fonctionner, nous pouvons commen\u00e7er \u00e0 nous livrer \u00e0 des tests intensifs&nbsp;:<\/p>\n<pre>[factorielle]$ <strong>.\/test\/factorielle 3<\/strong>\n3! = 6\n[factorielle]$<\/pre>\n<p style=\"padding-left: 60px;\">Tr\u00e8s bien&nbsp;!<\/p>\n<pre>[factorielle]$ <strong>.\/test\/factorielle 2<\/strong>\n2! = 2\n[factorielle]$<\/pre>\n<p style=\"padding-left: 60px;\">Parfait&nbsp;!<\/p>\n<pre>[factorielle]$ <strong>.\/test\/factorielle 1<\/strong>\n1! = 1\n[factorielle]$<\/pre>\n<p style=\"padding-left: 60px;\">Aucun souci.<\/p>\n<pre>[factorielle]$ <strong>.\/test\/factorielle 0<\/strong>\n0! = 0\n[factorielle]$<\/pre>\n<p style=\"padding-left: 60px;\">A\u00efe&nbsp;!<\/p>\n<p style=\"text-align: justify;\">Et oui, par convention, il est pos\u00e9 que <code>0! = 1<\/code> (vous pouvez <a title=\"http:\/\/fr.wikipedia.org\/wiki\/Factorielle\" href=\"http:\/\/fr.wikipedia.org\/wiki\/Factorielle\" target=\"_blank\">v\u00e9rifier sur Wikip\u00e9dia<\/a> si vous le souhaitez). Notre programme est donc d\u00e9fectueux. La correction est relativement simple, il suffit de remplacer la boucle<\/p>\n<pre>        do {\n                f = f * n;\n                n = n - 1;\n        } while (n &gt; 1);<\/pre>\n<p>par<\/p>\n<pre>        while (n &gt; 1) {\n                f = f * n;\n                n = n - 1;\n        }<\/pre>\n<p style=\"text-align: justify;\">C&rsquo;est ce que j&rsquo;ai fait dans le fichier <code><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact-2.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact-2.c\" target=\"_blank\">fact-2.c<\/a><\/code>. En principe je devrais garder le m\u00eame nom de fichier source et le remplacer simplement pour la nouvelle version de la biblioth\u00e8que. Je veux ici conserver la version pr\u00e9c\u00e9dente simplement \u00e0 titre p\u00e9dagogique.<\/p>\n<p style=\"text-align: justify;\">Je vais le compiler, puis g\u00e9n\u00e9rer une nouvelle version de biblioth\u00e8que en incr\u00e9mentant le num\u00e9ro mineur. L&rsquo;interface de la fonction n&rsquo;\u00e9tant pas modifi\u00e9e, les fichiers ex\u00e9cutables qui en d\u00e9pendent doivent continuer \u00e0 fonctionner normalement.<\/p>\n<pre>[factorielle]$ <strong>gcc -c -I include\/ -fPIC -Wall -o src\/fact.o src\/fact-2.c<\/strong>\n[factorielle]$ <strong>gcc -fPIC -shared -Wl,-soname,libfact.so.1 -o lib\/libfact.so.1.1 src\/fact.o<\/strong><\/pre>\n<p style=\"text-align: justify;\">Notre biblioth\u00e8que a \u00e9t\u00e9 re-g\u00e9n\u00e9r\u00e9e dans un nouveau nom de fichier, aussi faut-il relancer la commande <code>ldconfig<\/code>.<\/p>\n<pre>[factorielle]$ <strong>ldconfig -n lib\/<\/strong>\n[factorielle]$ <strong>ls -l lib\/<\/strong>\ntotal 16\nlrwxrwxrwx 1 cpb cpb   12 2012-01-27 10:04 libfact.so -&gt; libfact.so.1\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:11 libfact.so.1 -&gt; libfact.so.1.1\n-rwxrwxr-x 1 cpb cpb 6659 2012-01-27 10:02 libfact.so.1.0\n-rwxrwxr-x 1 cpb cpb 6661 2012-01-27 10:10 libfact.so.1.1\n[factorielle]$\n[factorielle]$ <strong>.\/test\/factorielle 0 1 2<\/strong>\n0! = 1\n1! = 1\n2! = 2\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Notre programme fonctionne correctement pour <code>0!<\/code>, et l&rsquo;ancienne version de la biblioth\u00e8que n&rsquo;\u00e9tant plus utilis\u00e9e, il est possible de l&rsquo;effacer.<\/p>\n<pre>[factorielle]$ <strong>rm -f lib\/libfact.so.1.0 <\/strong>\n[factorielle]$<\/pre>\n<div id=\"attachment_1498\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/figure-2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1498\" class=\"size-medium wp-image-1498\" title=\"Biblioth\u00e8que dynamique version 1.1\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/figure-2-300x188.png\" alt=\"Biblioth\u00e8que dynamique version 1.1\" width=\"300\" height=\"188\" \/><\/a><p id=\"caption-attachment-1498\" class=\"wp-caption-text\">Biblioth\u00e8que dynamique version 1.1<\/p><\/div>\n<h2>Modification de version majeure<\/h2>\n<p style=\"text-align: justify;\">Apr\u00e8s quelques essais, nous arrivons face \u00e0 un nouveau probl\u00e8me avec notre biblioth\u00e8que.<\/p>\n<pre>[factorielle]$ <strong>.\/test\/factorielle -3<\/strong>\n-3! = 1\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Notre fonction renvoie une valeur lorsqu&rsquo;on lui passe un nombre n\u00e9gatif. La v\u00e9ritable factorielle math\u00e9matique n&rsquo;est d\u00e9finie que sur l&rsquo;ensemble des entiers naturels, pas pour les entiers relatifs n\u00e9gatifs. Notre fonction devrait donc signaler l&rsquo;erreur d&rsquo;argument et non pas renvoyer une valeur, coh\u00e9rente il est vrai mais trompeuse.<\/p>\n<p style=\"text-align: justify;\">Nous choisissons de modifier l&rsquo;interface de notre routine, qui va prendre en argument un pointeur sur un entier <code>long long<\/code> dans lequel elle stockera le r\u00e9sultat, et renverra une valeur de r\u00e9ussite (z\u00e9ro) ou d&rsquo;\u00e9chec (-1). Cette modification d&rsquo;interface va impliquer une adaptation et une recompilation des applications utilisant la biblioth\u00e8que, aussi devrons-nous changer de version majeure.<\/p>\n<p>La nouvelle fonction <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact-3.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact-3.c\" target=\"_blank\"><code>fact-3.c<\/code><\/a> est d\u00e9finie comme suit.<\/p>\n<pre>int factorielle(long int n, long long int * result)\n{\n        * result = 1;\n        if (n &lt; 0)\n                return -1;\n         do {\n                 (*result) = (*result) * n;\n                 n = n - 1;\n         } while (n &gt; 1);\n        return 0;\n}<\/pre>\n<p>Bien sur, on modifie le fichier d&rsquo;en-t\u00eate en (<a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact-3.h\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/fact-3.h\" target=\"_blank\"><code>fact-3.h<\/code><\/a>):<\/p>\n<pre>#ifndef LIB_FACT_H\n#define LIB_FACT_H\n        int factorielle(long int n, long long int * result);\n#endif<\/pre>\n<p style=\"text-align: justify;\">Compilons notre biblioth\u00e8que comme pr\u00e9c\u00e9demment.<\/p>\n<pre>[factorielle]$ <strong>gcc -c -I include\/ -fPIC -Wall -o src\/fact.o src\/fact-3.c<\/strong>\n[factorielle]$ <strong>gcc -fPIC -shared -Wl,-soname,libfact.so.2 -o lib\/libfact.so.2.0 src\/fact.o<\/strong>\n[factorielle]$ <strong>ldconfig -n lib\/<\/strong>\n[factorielle]$ <strong>ls -l lib\/<\/strong>\ntotal 16\nlrwxrwxrwx 1 cpb cpb   12 2012-01-27 10:04 libfact.so -&gt; libfact.so.1\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:11 libfact.so.1 -&gt; libfact.so.1.1\n-rwxrwxr-x 1 cpb cpb 6661 2012-01-27 10:10 libfact.so.1.1\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:26 libfact.so.2 -&gt; libfact.so.2.0\n-rwxrwxr-x 1 cpb cpb 6661 2012-01-27 10:26 libfact.so.2.0\n[factorielle]$ <strong>cd lib\/<\/strong>\n[lib]$ <strong>ln -sf libfact.so.2 libfact.so<\/strong>\n[lib]$ <strong>ls -l<\/strong>\ntotal 16\nlrwxrwxrwx 1 cpb cpb   12 2012-01-27 10:27 libfact.so -&gt; libfact.so.2\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:11 libfact.so.1 -&gt; libfact.so.1.1\n-rwxrwxr-x 1 cpb cpb 6661 2012-01-27 10:10 libfact.so.1.1\nlrwxrwxrwx 1 cpb cpb   14 2012-01-27 10:26 libfact.so.2 -&gt; libfact.so.2.0\n-rwxrwxr-x 1 cpb cpb 6661 2012-01-27 10:26 libfact.so.2.0\n[lib]$ <strong>cd ..<\/strong>\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Les liens sont en place pour compiler une nouvelle version du programme de test (<a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/factorielle-2.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-28\/factorielle-2.c\" target=\"_blank\"><code style=\"text-align: justify;\">factorielle-2.c<\/code><\/a>).<\/p>\n<pre>#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;fact.h&gt;\n\nint main (int argc, char * argv[])\n{\n        long int n;\n        long long int f;\n        int i;\n        if (argc &lt; 2) {\n                fprintf(stderr, \"usage: %s valeurs...n\", argv[0]);\n                exit(EXIT_FAILURE);\n        }\n        for (i = 1; i &lt; argc; i ++)\n                if (sscanf(argv[i], \"%ld\", &amp; n) == 1) {\n                        if (factorielle(n, &amp; f) == 0)\n                                fprintf(stdout, \"%ld! = %lldn\", n, f);\n                        else\n                                fprintf(stdout, \"%ld! n'existe pasn\", n);\n                }\n        return EXIT_SUCCESS;\n}<\/pre>\n<p style=\"text-align: justify;\">Compilons et essayons-le&nbsp;:<\/p>\n<pre>[factorielle]$ <strong>gcc -I .\/include\/ -L .\/lib\/ -o .\/test\/factorielle-2 .\/test\/factorielle-2.c -lfact<\/strong>\n[factorielle]$ <strong>.\/test\/factorielle-2 3 0 -3<\/strong>\n3! = 6\n0! = 0\n-3! n'existe pas\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Cette fois notre programme se comporte correctement. On peut noter que la pr\u00e9sence de l&rsquo;ancienne version majeure permet \u00e0 notre pr\u00e9c\u00e9dent ex\u00e9cutable de continuer \u00e0 fonctionner.<\/p>\n<pre>[factorielle]$ <strong>.\/test\/factorielle 3 0 -3<\/strong>\n3! = 6\n0! = 1\n-3! = 1\n[factorielle]$<\/pre>\n<div id=\"attachment_1499\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/figure-3.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1499\" class=\"size-medium wp-image-1499\" title=\"Biblioth\u00e8que dynamique version 2.0\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/01\/figure-3-300x188.png\" alt=\"Biblioth\u00e8que dynamique version 2.0\" width=\"300\" height=\"188\" \/><\/a><p id=\"caption-attachment-1499\" class=\"wp-caption-text\">Biblioth\u00e8que dynamique version 2.0<\/p><\/div>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">La gestion des num\u00e9ros majeurs et mineurs de version pour les biblioth\u00e8ques dynamiques offre les avantages suivants&nbsp;:<\/p>\n<ul>\n<li style=\"text-align: justify;\">Les modifications internes uniquement, repr\u00e9sent\u00e9es par des \u00e9volutions du num\u00e9ro mineur, permettent aux ex\u00e9cutables d\u00e9j\u00e0 compil\u00e9s de fonctionner directement avec la nouvelle version de la biblioth\u00e8que et de b\u00e9n\u00e9ficier &#8211; sans recompilation &#8211; des am\u00e9liorations.<\/li>\n<li style=\"text-align: justify;\">Les transformations de l&rsquo;interface externe de la biblioth\u00e8que impliquent une recompilation (\u00e9ventuellement apr\u00e8s adaptation) pour pouvoir fonctionner.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Plusieurs versions majeures de la biblioth\u00e8que peuvent cohabiter simultan\u00e9ment permettant un fonctionnement correct de diff\u00e9rentes g\u00e9n\u00e9rations d&rsquo;une application. Toutefois les nouvelles compilations utiliseront la version majeure point\u00e9e par le lien symbolique contenant uniquement le nom de la biblioth\u00e8que (<code>libfact.so<\/code>)<\/p>\n<p style=\"text-align: justify;\">Nous verrons dans <a title=\"Mise au point de biblioth\u00e8que dynamique (2\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/02\/04\/mise-au-point-de-bibliotheque-dynamique-23\/\" target=\"_blank\">le prochain article<\/a> comment d\u00e9boguer le code de la biblioth\u00e8que dynamique en effectuant un suivi pas-\u00e0-pas de l&rsquo;ex\u00e9cution et en examinant le contenu de ses variables.<\/p>\n<p>&nbsp;<\/p>","protected":false},"excerpt":{"rendered":"<p>(English translation here) Lors d&rsquo;une r&eacute;cente session de formation, une conversation avec un participant m&rsquo;a pouss&eacute; &agrave; v&eacute;rifier les options n&eacute;cessaires pour effectuer du d&eacute;bogage et des tests en couverture sur une biblioth&egrave;que partag&eacute;e.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-1454","post","type-post","status-publish","format-standard","hentry","category-linux-2"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1454","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=1454"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1454\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=1454"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=1454"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=1454"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}