O problema, pelo que entendi, é o seguinte. Você tem várias bibliotecas, algumas estáticas, algumas dinâmicas e algumas estáticas e dinâmicas. O comportamento padrão do gcc é vincular "principalmente dinâmico". Ou seja, o gcc se vincula a bibliotecas dinâmicas quando possível, mas de outra forma recorre a bibliotecas estáticas. Quando você usa a opção -static para gcc, o comportamento é apenas vincular bibliotecas estáticas e sair com um erro se nenhuma biblioteca estática puder ser encontrada, mesmo se houver uma biblioteca dinâmica apropriada.
Outra opção, que em várias ocasiões desejei que o gcc tivesse, é o que chamo de -mostly-static e é essencialmente o oposto de -dynamic (o padrão). -mostly-static , se existisse, preferiria vincular-se a bibliotecas estáticas, mas voltaria para bibliotecas dinâmicas.
Esta opção não existe, mas pode ser emulada com o seguinte algoritmo:
Construindo a linha de comando do link sem incluir -static .
Repita as opções de link dinâmico.
Acumule caminhos de biblioteca, ou seja, aquelas opções da forma -L <lib_dir> em uma variável <lib_path>
Para cada opção de link dinâmico, ou seja, aqueles do formulário -l <lib_name> , execute o comando gcc <lib_path> -print-file-name = lib <lib_name> .a e capture a saída.
Se o comando imprimir algo diferente do que você passou, será o caminho completo para a biblioteca estática. Substitua a opção de biblioteca dinâmica pelo caminho completo para a biblioteca estática.
Enxágue e repita até processar toda a linha de comando do link. Opcionalmente, o script também pode obter uma lista de nomes de bibliotecas para excluir da vinculação estática.
O seguinte script bash parece fazer o truque:
#!/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
Por exemplo:
mostlyStatic gcc -o test test.c -ldl -lpthread
no meu sistema retorna:
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 com uma exclusão:
mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread
Eu então obtenho:
gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"