статические ссылки только на некоторые библиотеки

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

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

Ответ 1

gcc -lsome_dynamic_lib code.c some_static_lib.a

Ответ 2

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

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

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

Ответ 3

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.

Ответ 4

Из 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 всегда связан динамически, даже если указан с полным именем файла/пути.

Ответ 5

Проблема, как я понимаю, заключается в следующем. У вас несколько библиотек, некоторые статические, некоторые динамические и некоторые как статические, так и динамические. 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"

Ответ 6

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

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

Ответ 7

Существует также вариант -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

Ответ 8

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

gcc -lssl main.o -lFooLib -o main

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