Як я можу статично пов’язати лише деякі певні бібліотеки до моїх бінарних файлів при з'єднанні з 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 - і, можливо, інші), то ви можете використовувати відповідний варіант.
Якщо ви знаєте, з якими бібліотеками ви хочете статично зв’язати, ви можете просто вказати статичний файл бібліотеки у рядку посилань - повним шляхом.