Faire une build static d'un programme qui utilise sqlite

Le problème exposé dans ce sujet a été résolu.

Hello tout le monde :) .

TL;DR: aller directement à la partie "problème" (mais vous aurez probablement besoin de tout lire anyway)

Contexte : je fais une petite expérience pour comprendre comment fonctionnent les builds static/dynamic linking. J’ai googlé un peu la chose et ça ne donne pas beaucoup de résultats… Mais peut être que je cherche au mauvais endroit.

Première étape : le programme à faire fonctionner. J’utilise sqlite3 pour illustrer.

#include <stdio.h>
#include <sqlite3.h>

int main() {
   printf("Hello, World!\n");
   printf("%s\n", sqlite3_libversion()); 

   return 0;
}

Building : j’ai le Makefile suivant qui fonctionne.

build:
    gcc -o test main.c -lsqlite3

Build statique : C’est là où tout se complique. J’ai tenté ce makefile mais ça ne fonctionne pas…

build.o:
    gcc -c main.c

build.static: build.o
    gcc main.o /usr/lib/x86_64-linux-gnu/libsqlite3.a /usr/lib/x86_64-linux-gnu/libpthread.a -o static-test

Détails sur pourquoi je fais ça : 1. J’utilise libsqlite3.a pour remplacer libsqlite3.so (logique) 2. Après avoir tenté la compilation une première fois, des erreurs avec pthread sont remontées, donc j’ai essayé de l’ajouter en binaire (ça a retiré des erreurs)

Le problème : J’ai toujours des erreurs. J’ai des erreurs qui me parlent de dlopen qui - en plus de devoir être ajouté automatiquement (pourquoi ça n’est pas le cas ??) - pose un problème puisqu’il sert lui-même à inclure d’autres librairies dynamiques… J’ai l’impression que je suis dans un enfer de dépendances, comment faire pour gérer cela ?

$ make build.static                   
gcc -c main.c
gcc main.o /usr/lib/x86_64-linux-gnu/libsqlite3.a /usr/lib/x86_64-linux-gnu/libpthread.a -o static-test
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libsqlite3.a(sqlite3.o) : dans la fonction « fts5Bm25Function » :
(.text+0x2c914) : référence indéfinie vers « log »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libsqlite3.a(sqlite3.o) : dans la fonction « unixDlError » :
(.text+0x345e3) : référence indéfinie vers « dlerror »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libsqlite3.a(sqlite3.o) : dans la fonction « unixDlClose » :
(.text+0x8358) : référence indéfinie vers « dlclose »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libsqlite3.a(sqlite3.o) : dans la fonction « unixDlSym » :
(.text+0x836b) : référence indéfinie vers « dlsym »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libsqlite3.a(sqlite3.o) : dans la fonction « unixDlOpen » :
(.text+0x837d) : référence indéfinie vers « dlopen »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(pthread_create.o) : dans la fonction « allocate_stack » :
/build/glibc-ZN95T4/glibc-2.31/nptl/allocatestack.c:525 : référence indéfinie vers « _dl_stack_flags »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/allocatestack.c:647 : référence indéfinie vers « _dl_stack_flags »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(elision-lock.o) : dans la fonction « do_set_elision_enable » :
/build/glibc-ZN95T4/glibc-2.31/nptl/../sysdeps/unix/sysv/linux/x86/elision-conf.c:66 : référence indéfinie vers « _dl_x86_cpu_features »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(nptl-init.o) : dans la fonction « __pthread_initialize_minimal_internal » :
/build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:335 : référence indéfinie vers « _dl_pagesize »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:344 : référence indéfinie vers « _dl_pagesize »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:360 : référence indéfinie vers « _dl_init_static_tls »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:362 : référence indéfinie vers « _dl_wait_lookup_done »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(nptl-init.o) : dans la fonction « __pthread_get_minstack » :
/build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:393 : référence indéfinie vers « _dl_pagesize »
collect2: error: ld returned 1 exit status
make: *** [Makefile:8 : build.static] Erreur 1
+0 -0

Salut,

Quelle est l’erreur exacte ? Que ce passe-t-il si tu ajoute -static à ta ligne de commande ? Que contient libsqlite3.a (ar -tv libsqlite3.a) ?

Pour info, sqlite3 peut s’amalgamer en un fichier .c, que tu peux ajouter à ton projet. Ça peut être plus simple qu’utiliser une bibliothèque statique. Voir .

+0 -0

Wow! Je ne connaissais pas cette commande ^^ . En voici le résultat :

$ ar -tv /usr/lib/x86_64-linux-gnu/libsqlite3.a
rw-r--r-- 0/0 1619576 Jan  1 01:00 1970 sqlite3.o

Et c’est ce que j’espérais, donc tout va bien.

Pour ce qui est du résultat j’ai oublié de le mettre au début désolé, mais le voici.

Pour finir ce qui m’intéresse c’est pas tellement d’inclure sqlite mais plutôt de réussir à remplacer les librairies dynamiques, donc le fichier sqlite3.c ne m’intéresse pas vraiment.

[edit] J’ai trouvé cette ligne dans le makefile de sqlite:

THREADLIB = -lpthread -lm -ldl

Je m’attends donc à voir utilisé libm et libdl. Je les ai donc ajoutées à mon makefile :

build.o:
    gcc -c main.c

build.static: build.o
    gcc main.o /usr/lib/x86_64-linux-gnu/libsqlite3.a /usr/lib/x86_64-linux-gnu/libpthread.a /usr/lib/x86_64-linux-gnu/libm.a /usr/lib/x86_64-linux-gnu/libdl.a -o static-test

Mais ça ne fonctionne toujours pas. Et je trouve ça un peu moyen de devoir aller fouiller le makefile pour avoir cette information, il n’y a pas d’autre moyen ?

$ make build.static                    
gcc -c main.c
gcc main.o /usr/lib/x86_64-linux-gnu/libsqlite3.a /usr/lib/x86_64-linux-gnu/libpthread.a /usr/lib/x86_64-linux-gnu/libm.a /usr/lib/x86_64-linux-gnu/libdl.a -o static-test
/usr/bin/ld: /usr/lib/x86_64-linux-gnu/libsqlite3.a(sqlite3.o) : dans la fonction « unixDlOpen » :
(.text+0x837d): avertissement : Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(pthread_create.o) : dans la fonction « allocate_stack » :
/build/glibc-ZN95T4/glibc-2.31/nptl/allocatestack.c:525 : référence indéfinie vers « _dl_stack_flags »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/allocatestack.c:647 : référence indéfinie vers « _dl_stack_flags »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(elision-lock.o) : dans la fonction « do_set_elision_enable » :
/build/glibc-ZN95T4/glibc-2.31/nptl/../sysdeps/unix/sysv/linux/x86/elision-conf.c:66 : référence indéfinie vers « _dl_x86_cpu_features »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(nptl-init.o) : dans la fonction « __pthread_initialize_minimal_internal » :
/build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:335 : référence indéfinie vers « _dl_pagesize »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:344 : référence indéfinie vers « _dl_pagesize »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:360 : référence indéfinie vers « _dl_init_static_tls »
/usr/bin/ld : /build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:362 : référence indéfinie vers « _dl_wait_lookup_done »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libpthread.a(nptl-init.o) : dans la fonction « __pthread_get_minstack » :
/build/glibc-ZN95T4/glibc-2.31/nptl/nptl-init.c:393 : référence indéfinie vers « _dl_pagesize »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libm-2.31.a(e_log.o) : dans la fonction « __ieee754_log_ifunc » :
(.text+0x2c6) : référence indéfinie vers « _dl_x86_cpu_features »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libdl.a(dlopen.o) : dans la fonction « dlopen » :
(.text+0x9) : référence indéfinie vers « __dlopen »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libdl.a(dlclose.o) : dans la fonction « dlclose » :
(.text+0x5) : référence indéfinie vers « __dlclose »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libdl.a(dlsym.o) : dans la fonction « dlsym » :
(.text+0x9) : référence indéfinie vers « __dlsym »
/usr/bin/ld : /usr/lib/x86_64-linux-gnu/libdl.a(dlerror.o) : dans la fonction « dlerror » :
(.text+0x5) : référence indéfinie vers « __dlerror »
collect2: error: ld returned 1 exit status
make: *** [Makefile:8 : build.static] Erreur 1
+0 -0

avertissement : Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

Je pense que tu ne vas pas faire du vrai statique, ici.

Si tu simplifie ton main.c pour ne plus dépendre de libsqlite, ça marche ? Je n’ai pas libsqlite3.a dans mes dépots, donc je ne peux pas tester facilement, mais un Hello World normal, ça marche.

+0 -0

Bah je fais tout ça justement pour dépendre de libsqlite haha ^^ .

Pour info j’ai dû faire dpkg -S /usr/lib/x86_64-linux-gnu/libpthread.a pour avoir le fichier dispo (je ne sais pas pourquoi, c’est chelou, je me dis que j’avais peut être mal regardé dans le dossier…).

+0 -0

J’ai compilé sqlite pour avoir le .a pour tester de plus près chez moi. Je retrouve le même message d’erreur. Et je pense avoir la solution :

gcc -o test main.c libsqlite3.a -lm -ldl -lpthread -static

test est alors un exécutable statique.

Pourquoi cette commande, et comment je l’ai trouvé ?


Je suis parti de gcc -o test main.c -lsqlite3. Car avec ldd, on peut avoir la liste des dépendances.

ldd test                       
        linux-vdso.so.1 (0x00007ffea63c9000)
        libsqlite3.so.0 => /usr/lib64/libsqlite3.so.0 (0x00007f00ba140000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f00b9d85000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f00b9b81000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f00b9962000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f00b962a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f00ba45e000)

Plutôt que de donner le chemin des .a, j’utilise l’option -static, qui fait privilégier (qui force ?) gcc à prendre les bibliothèques statiques plutôt que dynamique. Ça permet de facilement tester l’un puis l’autre.

D’où

gcc -o test main.c   libsqlite3.a  -lm -ldl -lc -lpthread -static

/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: libsqlite3.a(sqlite3.o) : dans la fonction « unixDlOpen » :
/home/gabbro/tmp/sqlite-version-3.34.1/build/sqlite3.c:40174: avertissement : Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld : /usr/lib64/gcc/x86_64-suse-linux/7/../../../../lib64/libpthread.a(lowlevellock.o) : dans la fonction « __lll_lock_wait_private » :
/home/abuild/rpmbuild/BUILD/glibc-2.26/nptl/../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:78 : définitions multiples de « __lll_lock_wait_private »; /usr/lib64/gcc/x86_64-suse-linux/7/../../../../lib64/libc.a(libc-lowlevellock.o):/home/abuild/rpmbuild/BUILD/glibc-2.26/nptl/../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:78 : défini pour la première fois ici
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld : /usr/lib64/gcc/x86_64-suse-linux/7/../../../../lib64/libpthread.a(lowlevellock.o) : dans la fonction « __lll_unlock_wake_private » :
/home/abuild/rpmbuild/BUILD/glibc-2.26/nptl/../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:328 : définitions multiples de « __lll_unlock_wake_private »; /usr/lib64/gcc/x86_64-suse-linux/7/../../../../lib64/libc.a(libc-lowlevellock.o):/home/abuild/rpmbuild/BUILD/glibc-2.26/nptl/../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:328 : défini pour la première fois ici
collect2: error: ld returned 1 exit status

Un truc défini en double. Donc j’essaie de supprimer l’une des bibliothèques ; sûrement qu’en statique, ces bibliothèques embarquent déjà une autre, d’où la double définition. C’était c.


Pour info (1), sans l’option -static, ça compile très bien avec sqlite en statique et le reste en dynamique :

gcc -o test main.c   libsqlite3.a  -lm -ldl  -lpthread   -lc       
~/tmp/ ldd test 
        linux-vdso.so.1 (0x00007ffd2eb4b000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f48f0d92000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f48f0b8e000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f48f096f000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f48f05b4000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f48f10ca000)

Pour info (2), j’ai un warning quand je compile tout en statique, mais ça marche :

/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: libsqlite3.a(sqlite3.o) : dans la fonction « unixDlOpen » :
/home/gabbro/tmp/sqlite-version-3.34.1/build/sqlite3.c:40174: avertissement : Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

Pour info (3), tu peux ajouter -lc à la ligne de commande, à condition de la mettre à la fin :

gcc -o test main.c libsqlite3.a  -lm -ldl  -lpthread   -lc -static # OK
gcc -o test main.c libsqlite3.a  -lm -ldl -lc -lpthread  -static # KO

PS : pas la même distrib que toi, il est possible que ma commande ne marche pas telle quelle. Mais en reproduisant le même cheminement, ça devrait être bon.

+3 -0

Salut,

Pour info j’ai dû faire dpkg -S /usr/lib/x86_64-linux-gnu/libpthread.a pour avoir le fichier dispo (je ne sais pas pourquoi, c’est chelou, je me dis que j’avais peut-être mal regardé dans le dossier…).

Nek

Le paramètre -S de dpkg permet de connaître le paquet d’où provient un fichier (à supposer que celui-ci ait été installé par un paquet, évidemment). Du coup, je ne vois pas très bien en quoi cette commande a pû t’être utile.

Sinon, pour ton souci, tu peux regarder du côté de la commande pkg-config. Elle génère pour toi les options de compilation nécessaires. Essaye d’abord de voir si tu as bien une entrée pour SQLite avec pkg-config --list-all | grep sqlite et, si c’est le cas, tu peux tenter un pkg-config --static --libs <entree_trouvee>.

Si tu obtiens la même sortie avec pkg-config --libs <entree_trouvee>, c’est que la configuration de pkg-config pour un linkage statique n’est pas bonne, mais à défaut cela te donnera une idée des bibliothèques nécessaires et, éventuellement, de l’ordre dans lequel elles doivent être spécifiées (parce que oui, l’ordre est parfois important).

Édit : semi-grillé.

+2 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte