статическое связывание только некоторых библиотек - PullRequest
95 голосов
/ 11 ноября 2010

Как я могу статически связать только некоторые конкретные библиотеки с моим двоичным файлом при связывании с GCC?

gcc ... -static ... пытается статически связать все связанные библиотеки, но у меня нет статической версии некоторых из них (например, libX11).

Ответы [ 8 ]

102 голосов
/ 11 ноября 2010

gcc -lsome_dynamic_lib code.c some_static_lib.a

47 голосов
/ 15 ноября 2010

Вы также можете использовать ld параметр -Bdynamic

gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2

Все библиотеки после него (включая системные, связанные с gcc автоматически) будут связаны динамически.

27 голосов
/ 18 июля 2013
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.

26 голосов
/ 11 ноября 2010

Из справочной страницы 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 отсутствует в списке динамически связанных библиотек, так как он был связан статически.

Осторожно: An .so файл всегда связан динамически, даже если указан с полным именем файла / путем.

17 голосов
/ 06 декабря 2012

Проблема, насколько я понимаю, заключается в следующем. У вас есть несколько библиотек, некоторые статические, некоторые динамические, а некоторые статические и динамические. Поведение gcc по умолчанию состоит в том, чтобы связывать «в основном динамически». То есть gcc по возможности ссылается на динамические библиотеки, но в противном случае возвращается к статическим библиотекам. Когда вы используете опцию -static для gcc , происходит только связывание статических библиотек и выход с ошибкой, если статическая библиотека не найдена, даже если есть соответствующая динамическая библиотека .

Другой вариант, который я несколько раз хотел, чтобы gcc имел, - это то, что я называю -само-статический и, по сути, противоположен -динамический (по умолчанию). -stly-static предпочел бы, если бы он существовал, связываться со статическими библиотеками, но использовал бы динамические библиотеки.

Эта опция не существует, но ее можно эмулировать с помощью следующего алгоритма:

  1. Построение командной строки ссылки без -static .

  2. Перебирать параметры динамической ссылки.

  3. Накапливать пути к библиотекам, то есть эти параметры вида -L в переменной

  4. Для каждого параметра динамической ссылки, т. Е. Вида -l <имя_библиотеки> , введите команду gcc -print-file-name = lib <имя_библиотеки> .a и захватить вывод.

  5. Если команда напечатает что-то отличное от того, что вы передали, это будет полный путь к статической библиотеке. Замените параметр динамической библиотеки на полный путь к статической библиотеке.

Промойте и повторяйте, пока не обработаете всю командную строку ссылки. При желании сценарий может также взять список имен библиотек для исключения из статического связывания.

Следующий скрипт 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"
6 голосов
/ 24 мая 2017

Существует также -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 Systems, ld будет искать в каталоге библиотеку libnamespec.so перед поиском одного по имени libnamespec.a. (От условно, расширение .so обозначает общую библиотеку.) Обратите внимание, что это поведение не относится к :filename, который всегда указывает файл называется filename.

Компоновщик будет искать архив только один раз, в том месте, где он указывается в командной строке. Если архив определяет символ который был неопределен в каком-то объекте, который появился перед архивом в командной строке компоновщик включит соответствующий файл (ы) из архива. Тем не менее, неопределенный символ в объекте появляется позже в командной строке компоновщик не будет искать архив снова.

См. Параметр -( для способа заставить компоновщик искать архивы. несколько раз.

Вы можете перечислить один и тот же архив несколько раз в командной строке.

Этот тип поиска в архиве является стандартным для линкеров Unix. Тем не мение, если вы используете ld в AIX, обратите внимание, что он отличается от поведение компоновщика AIX.

Вариант -l:namespec документирован начиная с версии 2.18 binutils (2007): https://sourceware.org/binutils/docs-2.18/ld/Options.html

3 голосов
/ 11 ноября 2010

Некоторые загрузчики (линкеры) предоставляют переключатели для включения и выключения динамической загрузки. Если в такой системе работает GCC (Solaris - и, возможно, другие), вы можете использовать соответствующую опцию.

Если вы знаете, какие библиотеки вы хотите связать статически, вы можете просто указать файл статической библиотеки в строке ссылки - по полному пути.

1 голос
/ 02 ноября 2017

чтобы связать динамическую и статическую библиотеку в одну строку, вы должны поместить статические библиотеки после динамических библиотек и объектных файлов, например:

gcc -lssl main.o -lFooLib -o main

в противном случае, она не будет работать.мне нужно время, чтобы понять это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...