静态链接只有一些库

时间:2010-11-11 15:28:47

标签: gcc linker static-libraries

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

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

8 个答案:

答案 0 :(得分:101)

gcc -lsome_dynamic_lib code.c some_static_lib.a

答案 1 :(得分:47)

您还可以使用ld选项-Bdynamic

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

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

答案 2 :(得分:27)

gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2

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

请注意,如果libs1.solibs1.a都存在,则链接器会在libs1.so之前或-Wl,-Bstatic之后选择-Wl,-Bdynamic。在致电-L/libs1-library-location/之前,请不要忘记通过-ls1

答案 3 :(得分:26)

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文件始终是动态链接的,即使使用完整文件名/路径指定也是如此。

答案 4 :(得分:17)

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

我曾多次希望 gcc 的另一种选择是我所谓的 -mostly-static ,并且基本上与 -dynamic <相反/ strong>(默认值)。如果存在的话, -mostly-static 会更喜欢链接静态库,但会回归动态库。

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

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

  2. 迭代动态链接选项。

  3. 累积库路径,即变量&lt; lib_path&gt;

  4. -L&lt; lib_dir&gt; 形式的选项
  5. 对于每个动态链接选项,即 -l&lt; lib_name&gt; 形式的选项,运行命令 gcc&lt; lib_path&gt; -print-file-name = lib&lt; lib_name&gt; .a 并捕获输出。

  6. 如果命令打印的内容不是您传递的内容,则它将是静态库的完整路径。将动态库选项替换为静态库的完整路径。

  7. 冲洗并重复,直到您处理完整个链接命令行。可选地,脚本还可以获取要从静态链接中排除的库名称列表。

    以下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"
    

答案 5 :(得分:5)

gcc中还有-l:libstatic1.a(减去l冒号)-l选项变体,可用于链接静态库(感谢https://stackoverflow.com/a/20728782)。有记录吗?不在gcc的官方文档中(对于共享库也不是这样):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的{​​{1}}之前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

答案 6 :(得分:3)

一些装载机(链接器)提供用于打开和关闭动态加载的开关。如果GCC在这样的系统上运行(Solaris - 可能还有其他系统),那么您可以使用相关选项。

如果您知道要静态链接哪些库,则只需在链接行中指定静态库文件 - 按完整路径指定。

答案 7 :(得分:1)

要在一行中链接动态库和静态库,必须在动态库和目标文件之后放置静态库,如下所示:

gcc -lssl main.o -lFooLib -o main

否则,它将无法正常工作。我花了一些时间才弄明白。