J'ai un petit morceau de code qui dépend de nombreuses bibliothèques statiques (a_1-a_n). J'aimerais regrouper ce code dans une bibliothèque statique et le rendre disponible à d'autres personnes.
Ma bibliothèque statique, appelons-le X, compile bien.
J'ai créé un exemple de programme simple qui utilise une fonction de X, mais lorsque j'essaie de le lier à X, de nombreuses erreurs sur les symboles manquants apparaissent dans les bibliothèques a_1 - a_n.
Existe-t-il un moyen de créer une nouvelle bibliothèque statique, Y contenant X et toutes les fonctionnalités nécessaires à X (bits sélectionnés de a_1 - a_n), de sorte que je ne puisse distribuer que Y pour que les utilisateurs puissent lier leurs programmes?
MISE À JOUR:
J'ai simplement envisagé de tout jeter avec ar et de créer un méga-lib, mais cela finit par inclure un grand nombre de symboles inutiles ( tous les fichiers .o font environ 700 Mo. Toutefois, un exécutable lié statiquement fait 7 Mo). Existe-t-il un bon moyen d’inclure uniquement ce qui est réellement nécessaire?
Cela ressemble étroitement à Comment combiner plusieurs bibliothèques C/C++ en une? .
Les bibliothèques statiques ne sont pas liées à d'autres bibliothèques statiques. La seule façon de procéder consiste à utiliser votre outil librarian/archiver (par exemple ar sous Linux) pour créer une nouvelle bibliothèque statique unique en concaténant plusieurs bibliothèques.
Edit: En réponse à votre mise à jour, le seul moyen que je connaisse pour sélectionner uniquement les symboles requis est de créer manuellement la bibliothèque à partir du sous-ensemble des fichiers .o qui les contiennent. Ceci est difficile, prend du temps et est sujet aux erreurs. Je ne suis au courant d'aucun outil pour aider à faire cela (pour ne pas dire qu'ils n'existent pas), mais cela en ferait un projet assez intéressant.
Si vous utilisez Visual Studio, alors oui, vous pouvez le faire.
L'outil de création de bibliothèques fourni avec Visual Studio vous permet de joindre des bibliothèques sur la ligne de commande. Je ne sais pas comment faire cela dans l'éditeur visuel.
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
Sous Linux ou MingW, avec GNU chaîne d’outils:
ar -M <<EOM
CREATE libab.a
ADDLIB liba.a
ADDLIB libb.a
SAVE
END
EOM
ranlib libab.a
De si vous ne supprimez pas liba.a
et libb.a
, vous pouvez créer une "archive mince":
ar crsT libab.a liba.a libb.a
Sous Windows, avec la chaîne d'outils MSVC:
lib.exe /OUT:libab.lib liba.lib libb.lib
Une bibliothèque statique est juste une archive de .o
fichiers objets. Extrayez-les avec ar
(en supposant Unix) et regroupez-les dans une grande bibliothèque.
Alternativement à Link Library Dependencies
_ Dans les propriétés du projet, il existe un autre moyen de lier des bibliothèques dans Visual Studio.
Add Existing Item...
).Item Type
est Library
Cela inclura les autres bibliothèques dans X comme si vous aviez exécuté
lib /out:X.lib X.lib other1.lib other2.lib
Remarque avant de lire la suite: Le script Shell présenté ici n'est certainement pas sûr à utiliser et a été testé. À utiliser à vos risques et périls!
J'ai écrit un script bash pour accomplir cette tâche. Supposons que votre bibliothèque est lib1 et que vous ayez besoin d'inclure des symboles à partir de lib2. Le script s'exécute maintenant en boucle, où il vérifie d'abord quels symboles non définis de lib1 peuvent être trouvés dans lib2. Il extrait ensuite les fichiers objets correspondants de lib2 avec ar
, les renomme un peu et les met dans lib1. Il peut maintenant y avoir plus de symboles manquants, car les éléments que vous avez inclus dans lib2 ont besoin d’autres éléments de lib2, que nous n’avons pas encore inclus, de sorte que la boucle doit être exécutée à nouveau. Si après quelques passes de la boucle, il n'y a plus de modifications, c'est-à-dire qu'aucun fichier objet de lib2 ajouté à lib1, la boucle peut s'arrêter.
Notez que les symboles inclus sont toujours signalés comme non définis par nm
, je garde donc une trace des fichiers objet, qui ont été ajoutés à lib1, afin de déterminer si la boucle peut être arrêtée.
#! /bin/bash
lib1="$1"
lib2="$2"
if [ ! -e $lib1.backup ]; then
echo backing up
cp $lib1 $lib1.backup
fi
remove_later=""
new_tmp_file() {
file=$(mktemp)
remove_later="$remove_later $file"
eval $1=$file
}
remove_tmp_files() {
rm $remove_later
}
trap remove_tmp_files EXIT
find_symbols() {
nm $1 $2 | cut -c20- | sort | uniq
}
new_tmp_file lib2symbols
new_tmp_file currsymbols
nm $lib2 -s --defined-only > $lib2symbols
prefix="xyz_import_"
pass=0
while true; do
((pass++))
echo "Starting pass #$pass"
curr=$lib1
find_symbols $curr "--undefined-only" > $currsymbols
changed=0
for sym in $(cat $currsymbols); do
for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
echo " Found $sym in $obj."
if [ -e "$prefix$obj" ]; then continue; fi
echo " -> Adding $obj to $lib1"
ar x $lib2 $obj
mv $obj "$prefix$obj"
ar -r -s $lib1 "$prefix$obj"
remove_later="$remove_later $prefix$obj"
((changed=changed+1))
done
done
echo "Found $changed changes in pass #$pass"
if [[ $changed == 0 ]]; then break; fi
done
J'ai nommé ce script libcomp
, vous pouvez donc l'appeler ensuite, par exemple. avec
./libcomp libmylib.a libwhatever.a
où vous voulez inclure des symboles. Cependant, je pense qu'il est plus sûr de tout copier dans un répertoire séparé en premier. Je ne ferais pas autant confiance à mon script (cependant, cela a fonctionné pour moi; je pourrais inclure libgsl.a dans ma bibliothèque numérique avec cela et laisser de côté le commutateur -lgsl du compilateur).