Як я можу статично пов’язати лише деякі певні бібліотеки до моїх бінарних файлів при з'єднанні з GCC?
gcc ... -static ...
намагається статично зв’язати всі пов'язані бібліотеки, але я не отримав статичну версію деяких з них (наприклад: libX11).
Як я можу статично пов’язати лише деякі певні бібліотеки до моїх бінарних файлів при з'єднанні з GCC?
gcc ... -static ...
намагається статично зв’язати всі пов'язані бібліотеки, але я не отримав статичну версію деяких з них (наприклад: libX11).
Відповіді:
gcc -lsome_dynamic_lib code.c some_static_lib.a
code.c
файлу гарантує, що символи в ній будуть ігноровані, якщо не трапиться main()
функції в одному з бібліотеки об'єктних файлів.
Ви також можете скористатися 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
.
-static
десь команди не вдається (я припускаю, що вона намагається зв’язати більше речей статично, ніж лише потрібні мені бібліотеки).
-Wl,-Bstatic
і -Wl,-Bdynamic
важливий.
На сторінці сторінки 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
файл завжди пов'язується динамічно, навіть якщо вказано повне ім’я файлу / шлях.
ldd a.out
?
ldd
виводить потрібні бібліотеки, і libX11 не відображається у цьому списку.
Як я розумію, проблема полягає в наступному. У вас є кілька бібліотек, деякі статичні, деякі динамічні, а деякі і статичні, і динамічні. Типова поведінка gcc - це пов'язувати "переважно динамічний". Тобто, gcc посилається на динамічні бібліотеки, коли це можливо, але в іншому випадку повертається до статичних бібліотек. Коли ви використовуєте -static варіант для gcc, поведінка полягає в тому, щоб зв'язати лише статичні бібліотеки та вийти з помилкою, якщо статичної бібліотеки не знайти, навіть якщо є відповідна динамічна бібліотека.
Інший варіант, який я декілька разів хотів, щоб gcc мав, - це те, що я називаю - переважно статичним і по суті є протилежним до -динамічного (за замовчуванням). Найбільш-статичні , якби вони існували, воліли б пов'язувати статичні бібліотеки, але повернулися б до динамічних бібліотек.
Ця опція не існує, але її можна емулювати за допомогою наступного алгоритму:
Побудова командного рядка посилання з out, включаючи -static .
Ітерація над параметрами динамічного посилання.
Накопичуйте бібліотечні шляхи, тобто ті параметри форми -L <lib_dir> у змінній <lib_path>
Для кожного параметра динамічного посилання, тобто для форми -l <lib_name> , запустіть команду gcc <lib_path> -print-file-name = lib <lib_name> .a та зафіксуйте вихід.
Якщо команда друкує щось інше, ніж те, що ви передали, це буде повний шлях до статичної бібліотеки. Замініть параметр динамічної бібліотеки на повний шлях до статичної бібліотеки.
Промийте та повторіть, поки не обробите весь командний рядок посилання. Необов’язково сценарій також може приймати список імен бібліотеки, щоб виключити статичне посилання.
Наступний скрипт bash, здається, робить трюк:
#!/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"
Існує також -l:libstatic1.a
(мінус l двокрапка) варіант -l в gcc, який можна використовувати для зв’язку статичної бібліотеки (Завдяки https://stackoverflow.com/a/20728782 ). Це документально підтверджено? Не в офіційній документації gcc (що також не точно для спільних ліб): https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
-llibrary -l 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
.Лінкер буде шукати архів лише один раз у тому місці, де він вказаний у командному рядку. Якщо архів визначає символ, який не був визначений в якомусь об'єкті, який з’явився перед архівом у командному рядку, то вкладач буде містити відповідні файли з архіву. Однак невизначений символ в об'єкті, який з’явиться пізніше в командному рядку, не призведе до того, що лінкер знову шукатиме архів.
Дивіться
-(
варіант, як змусити лінкер шукати архіви кілька разів.Ви можете вказати один і той же архів декілька разів у командному рядку.
Цей тип пошуку в архіві є стандартним для посилань Unix. Однак, якщо ви використовуєте ld на AIX, зауважте, що він відрізняється від поведінки лінкера AIX.
Варіант -l:namespec
задокументований з версії binutils 2.18 (2007): https://sourceware.org/binutils/docs-2.18/ld/Options.html
Деякі навантажувачі (лінкери) надають вимикачі для включення та вимкнення динамічного навантаження. Якщо GCC працює в такій системі (Solaris - і, можливо, інші), то ви можете використовувати відповідний варіант.
Якщо ви знаєте, з якими бібліотеками ви хочете статично зв’язати, ви можете просто вказати статичний файл бібліотеки у рядку посилань - повним шляхом.