静态链接只有一些库

peo*_*oro 99 linker gcc static-libraries

在与GCC链接时,如何仅将某些特定库静态链接到我的二进制文件?

gcc ... -static ...尝试静态链接所有链接库,但我没有其中一些的静态版本(例如:libX11).

Let*_*_Be 106

gcc -lsome_dynamic_lib code.c some_static_lib.a

  • 请问你详细说明这是如何运作的?仅代码答案对初学者没有帮助. (38认同)
  • @jb默认情况下,gcc动态链接.当您使用-lsome_dynamic_lib时,它会按预期动态链接.但是,当gcc被明确地给出一个静态库时,它总是试图静态地链接它.但是,有一些关于符号得到解决的顺序的棘手细节; 我不太确定这是怎么回事.我已经了解到,如果有疑问,请尝试重新排列库标志的顺序:-) (8认同)
  • 如果您静态链接,例如[GPL库](http://www.gnu.org/licenses/gpl-faq.html#IfLibraryIsGPL),则存在一个lincense问题 (4认同)
  • 在目标文件之后链接库 - 尤其是静态库.在古代和现代版本的链接环境中(我不确定截至2010年11月的适用于旧版本的现状),在`code.c`文件之前列出静态库可以保证忽略其中的符号除非在其中一个库对象文件中发生了`main()`函数. (3认同)

Dmi*_*kov 48

你也可以使用ld选项-Bdynamic

gcc <objectfiles> -static -lstatic1 -lstatic2 -Wl,-Bdynamic -ldynamic1 -ldynamic2
Run Code Online (Sandbox Code Playgroud)

之后的所有库(包括通过gcc自动链接的系统库)将动态链接.

  • -Wl,-Bdynamic需要GNU ld,因此该解决方案不适用于gcc使用系统ld的系统(例如Mac OS X). (18认同)

wgo*_*doy 29

gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2
Run Code Online (Sandbox Code Playgroud)

你也可以使用:-static-libgcc -static-libstdc++gcc库的标志

记住,如果libs1.solibs1.a两者存在,链接器会挑选libs1.so如果它之前的-Wl,-Bstatic或之后-Wl,-Bdynamic.-L/libs1-library-location/在打电话之前别忘了通过-ls1.

  • NB.`-Wl,-Bstatic`和`-Wl,-Bdynamic`的顺序很重要. (3认同)
  • 至少,此解决方案适用于针对 libgomp 的静态链接! (2认同)

ypn*_*nos 27

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)
Run Code Online (Sandbox Code Playgroud)

正如你所看到的例子,libX11是不是在动态链接库的名单,因为它是静态链接.

注意:.so即使使用完整文件名/路径指定,文件也始终动态链接.


jco*_*and 18

我理解的问题如下.你有几个库,一些是静态的,一些是动态的,一些是静态的和动态的. gcc的默认行为是链接"大部分是动态的".也就是说,gcc会在可能的情况下链接到动态库,否则会回退到静态库.当您对gcc使用-static选项时,行为是仅链接静态库并在没有找到静态库的情况下退出,即使有适当的动态库也是如此.

另一种选择,我有好几次想GCC有,就是我所说的-mostly静态的和基本上是相反-dynamic(默认值). 如果存在的话,最常见的是宁愿链接静态库,但会回归到动态库.

此选项不存在,但可以使用以下算法进行模拟:

  1. 构造包含-static的链接命令行.

  2. 迭代动态链接选项.

  3. 累积库路径,即变量<lib_path>中-L <lib_dir>形式的选项

  4. 对于每个动态链接选项,即形式为-l <lib_name>的选项,运行命令gcc <lib_path> -print-file-name = lib <lib_name> .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
Run Code Online (Sandbox Code Playgroud)

例如:

mostlyStatic gcc -o test test.c -ldl -lpthread
Run Code Online (Sandbox Code Playgroud)

在我的系统上返回:

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"
Run Code Online (Sandbox Code Playgroud)

或排除在外:

mostlyStatic --exclude dl gcc -o test test.c -ldl -lpthread
Run Code Online (Sandbox Code Playgroud)

然后我得到:

gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
Run Code Online (Sandbox Code Playgroud)


osg*_*sgx 7

-l:libstatic1.agcc中还有(减l冒号)-l选项的变体,可用于链接静态库(感谢/sf/answers/1451014771/).有记录吗?不在gcc的官方文档中(对于共享库也不是这样):https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

-llibrary
-l library 
Run Code Online (Sandbox Code Playgroud)

链接时搜索名为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
Run Code Online (Sandbox Code Playgroud)

将指定的存档或目标文件添加namespec到要链接的文件列表中.此选项可以使用任意次.如果 namespec是形式:filename,ld将在库路径中搜索被调用的文件filename,否则它将在库路径中搜索一个名为的文件libnamespec.a.

在支持共享库的系统上,ld也可以搜索除以外的文件libnamespec.a.具体来说,在ELF和SunOS系统上,ld将libnamespec.so在搜索被调用的库之前在目录中搜索所调用的库 libnamespec.a.(按照惯例,.so扩展名表示共享库.)请注意,此行为不适用于:filename,它始终指定一个名为的文件filename.

链接器将仅在命令行上指定的位置搜索一次存档.如果存档定义了在命令行上存档之前出现的某个对象中未定义的符号,则链接器将包含存档中的相应文件.但是,稍后在命令行中出现的对象中的未定义符号将不会导致链接器再次搜索存档.

有关-(强制链接器多次搜索存档的方法,请参阅该选项.

您可以在命令行上多次列出相同的存档.

这种类型的归档搜索是Unix链接器的标准.但是,如果您在AIX上使用ld,请注意它与AIX链接器的行为不同.

-l:namespec从2.18版本的binutils(2007)开始记录该变体:https://sourceware.org/binutils/docs-2.18/ld/Options.html