Ответ 1
gcc -lsome_dynamic_lib code.c some_static_lib.a
Как я могу статически связывать только некоторые конкретные библиотеки с моим двоичным кодом при связывании с GCC?
gcc ... -static ...
пытается статически связать связанные все связанные библиотеки, но у меня нет статической версии некоторых из них (например: libX11).
gcc -lsome_dynamic_lib code.c some_static_lib.a
Вы также можете использовать опцию ld
-Bdynamic
gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2
Все библиотеки после него (включая системные, связанные gcc автоматически) будут связаны динамически.
gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2
вы также можете использовать флаги -static-libgcc -static-libstdc++
для библиотек gcc
помните, что если существуют libs1.so
и libs1.a
, компоновщик будет выбирать libs1.so
, если он до -Wl,-Bstatic
или после -Wl,-Bdynamic
. Не забудьте передать -L/libs1-library-location/
перед вызовом -ls1
.
Из manpage ld
(это не работает с gcc), ссылаясь на опцию --static
:
Вы можете использовать эту опцию несколько раза в командной строке: это влияет на библиотека, которая ищет опции -l, которые следуйте за ним.
Одним из решений является размещение ваших динамических зависимостей перед параметром --static
в командной строке.
Другая возможность - не использовать --static
, а вместо этого предоставить полное имя файла/путь для файла статического объекта (т.е. не использовать -l) для статической привязки конкретной библиотеки. Пример:
# echo "int main() {}" > test.cpp
# c++ test.cpp /usr/lib/libX11.a
# ldd a.out
linux-vdso.so.1 => (0x00007fff385cc000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f9a5b233000)
libm.so.6 => /lib/libm.so.6 (0x00007f9a5afb0000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f9a5ad99000)
libc.so.6 => /lib/libc.so.6 (0x00007f9a5aa46000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a5b53f000)
Как вы можете видеть в примере, libX11
не входит в список динамически связанных библиотек, поскольку он был связан статически.
Остерегайтесь: файл .so
всегда связан динамически, даже если указан с полным именем файла/пути.
Проблема, как я понимаю, заключается в следующем. У вас несколько библиотек, некоторые статические, некоторые динамические и некоторые как статические, так и динамические. gcc поведение по умолчанию - это ссылка "в основном динамическая". То есть gcc ссылки на динамические библиотеки, когда это возможно, но в противном случае возвращается к статическим библиотекам. Когда вы используете параметр -статический для gcc, поведение должно связывать только статические библиотеки и выходить с ошибкой, если статическая библиотека не найдена, даже если есть соответствующая динамическая библиотека.
Другой вариант, который я неоднократно желал иметь gcc, это то, что я называю -mostly-static и по существу является противоположностью -dynamic (по умолчанию). -mostly-static, если он существует, предпочитает ссылаться на статические библиотеки, но возвращается к динамическим библиотекам.
Эта опция не существует, но ее можно эмулировать следующим алгоритмом:
Построение командной строки ссылки без вывода -статического.
Итерации по параметрам динамической ссылки.
Накопить пути библиотек, то есть эти параметры формы -L <lib_dir > в переменной <lib_path >
Для каждой опции динамической ссылки, то есть для форм -l <lib_name > , выполните команду gcc <lib_path > -print-file-name = lib <lib_name > .a и захватить вывод.
Если команда печатает что-то, отличное от того, что вы передали, это будет полный путь к статической библиотеке. Замените параметр динамической библиотеки полным путем на статическую библиотеку.
Промойте и повторите, пока вы не обработали всю командную строку связи. Опционально script также может принимать список имен библиотек для исключения из статической ссылки.
Следующий bash script, кажется, делает трюк:
#!/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
Например:
mostlyStatic gcc -o test test.c -ldl -lpthread
в моей системе возвращается:
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"
или с исключением:
mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread
Затем я получаю:
gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
Некоторые загрузчики (компоновщики) предоставляют переключатели для включения и выключения динамической загрузки. Если GCC работает на такой системе (Solaris - и, возможно, другие), вы можете использовать соответствующую опцию.
Если вы знаете, какие библиотеки вы хотите связать статически, вы можете просто указать файл статической библиотеки в линии ссылок - полным путем.
Существует также вариант -l:libstatic1.a
(минус один двоеточие) опции -l в gcc, который может использоваться для связывания статической библиотеки (спасибо fooobar.com/questions/68919/...), Документировано? Не в официальной документации gcc (что тоже не точно для общих libs): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
-llibrary -l library
Ищите библиотеку с именем library при связывании. (Вторая альтернатива с библиотекой в качестве отдельного аргумента предназначена только для соответствия POSIX и не рекомендуется.)... Единственная разница между использованием параметра -l и указанием имени файла заключается в том, что -l окружает библиотеку с помощью lib и '.a и ищет несколько каталогов.
Этот файл описывает binutils ld doc. Опция -lname
выполнит поиск libname.so
, а затем libname.a
добавит префикс lib и .so
(если он включен в данный момент) или суффикс .a
. Но параметр -l:name
будет выполнять поиск только для указанного имени:
https://sourceware.org/binutils/docs/ld/Options.html
-l namespec --library=namespec
Добавьте архив или объектный файл, указанный
namespec
в список файлы для связи. Эта опция может использоваться любое количество раз. Еслиnamespec
имеет вид:filename
, ld будет искать путь к библиотеке для файла с именемfilename
, иначе он будет искать путь к библиотеке для файла с именемlibnamespec.a
.В системах, поддерживающих общие библиотеки, ld также может искать файлы, отличные от
libnamespec.a
. В частности, на ELF и SunOS системы, ld будет искать каталог для библиотеки, называемойlibnamespec.so
перед поиском одного из них, называемогоlibnamespec.a
. (От соглашение, расширение.so
указывает на общую библиотеку.) Обратите внимание, что это поведение не относится к:filename
, которое всегда указывает файл с именемfilename
.Линкеров будет искать архив только один раз, в том месте, где он указан в командной строке. Если архив определяет символ который был undefined в некотором объекте, который появился перед архивом в командной строке компоновщик будет содержать соответствующий файл из архива. Однако символ undefined в объекте, появляющемся позже в командной строке не будет вызывать компоновщик для поиска архив снова.
См. параметр
-(
для того, чтобы заставить компоновщик искать архивы несколько раз.Вы можете указать один и тот же архив несколько раз в командной строке.
Этот тип поиска архива является стандартным для Unix-линкеров. Однако, если вы используете ld в AIX, обратите внимание, что он отличается от поведение компоновщика AIX.
Вариант -l:namespec
задокументирован с версии binusils версии 2.18 (2007): https://sourceware.org/binutils/docs-2.18/ld/Options.html
чтобы связать динамическую и статическую библиотеку в одной строке, вы должны поставить статические библиотеки после динамических библиотек и объектных файлов, например:
gcc -lssl main.o -lFooLib -o main
в противном случае это не сработает. мне иногда нужно понять это.