Le problème tel que je le comprends est le suivant. Vous disposez de plusieurs bibliothèques, certaines statiques, d'autres dynamiques et d'autres à la fois statiques et dynamiques. Le comportement par défaut de gcc est de lier "principalement dynamique". Autrement dit, gcc crée des liens vers des bibliothèques dynamiques lorsque cela est possible, mais revient autrement aux bibliothèques statiques. Lorsque vous utilisez l' option -static pour gcc, le comportement consiste à ne lier que les bibliothèques statiques et à quitter avec une erreur si aucune bibliothèque statique ne peut être trouvée, même s'il existe une bibliothèque dynamique appropriée.
Une autre option, que j'ai à plusieurs reprises souhaité que gcc ait, est ce que j'appelle -mostly-static et est essentiellement l'opposé de -dynamic (la valeur par défaut). -mostly-static , s'il existait, préférerait se lier à des bibliothèques statiques mais retomberait dans des bibliothèques dynamiques.
Cette option n'existe pas mais elle peut être émulée avec l'algorithme suivant:
Construire la ligne de commande de lien sans inclure -static .
Parcourez les options de lien dynamique.
Accumuler les chemins de bibliothèque, c'est-à-dire les options de la forme -L <lib_dir> dans une variable <lib_path>
Pour chaque option de lien dynamique, c'est-à-dire celles de la forme -l <lib_name> , exécutez la commande gcc <lib_path> -print-file-name = lib <lib_name> .a et capturez la sortie.
Si la commande imprime autre chose que ce que vous avez transmis, ce sera le chemin complet de la bibliothèque statique. Remplacez l'option de bibliothèque dynamique par le chemin complet de la bibliothèque statique.
Rincez et répétez jusqu'à ce que vous ayez traité toute la ligne de commande du lien. En option, le script peut également prendre une liste de noms de bibliothèques à exclure de la liaison statique.
Le script bash suivant semble faire l'affaire:
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Usage: $0 [--exclude <lib_name>]. . . <link_command>"
fi
exclude=()
lib_path=()
while [ $# -ne 0 ]; do
case "$1" in
-L*)
if [ "$1" == -L ]; then
shift
LPATH="-L$1"
else
LPATH="$1"
fi
lib_path+=("$LPATH")
echo -n "\"$LPATH\" "
;;
-l*)
NAME="$(echo $1 | sed 's/-l\(.*\)/\1/')"
if echo "${exclude[@]}" | grep " $NAME " >/dev/null; then
echo -n "$1 "
else
LIB="$(gcc $lib_path -print-file-name=lib"$NAME".a)"
if [ "$LIB" == lib"$NAME".a ]; then
echo -n "$1 "
else
echo -n "\"$LIB\" "
fi
fi
;;
--exclude)
shift
exclude+=(" $1 ")
;;
*) echo -n "$1 "
esac
shift
done
echo
Par exemple:
mostlyStatic gcc -o test test.c -ldl -lpthread
sur mon système renvoie:
gcc -o test test.c "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libdl.a" "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
ou avec une exclusion:
mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread
J'obtiens alors:
gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"