Gcc 仅静态链接某些库

Gcc 仅静态链接某些库,gcc,linker,static-libraries,Gcc,Linker,Static Libraries,在使用GCC链接时,如何仅将特定库静态链接到二进制文件 gcc-静态…尝试静态链接所有链接的库,但我没有得到其中一些库的静态版本(例如:libX11)。来自ld的手册页(这不适用于gcc),参考--static选项: 您可以多次使用此选项 命令行上的时间:它影响 库搜索-l选项,其中 跟着它走 一种解决方案是将动态依赖项放在命令行上的--static选项之前 另一种可能是不使用--static,而是提供静态对象文件的完整文件名/路径(即不使用-l选项),以便静态链接到特定库中。例如: # ech

在使用GCC链接时,如何仅将特定库静态链接到二进制文件


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

来自
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
不在动态链接库的列表中,因为它是静态链接的

注意:
。因此
文件始终是动态链接的,即使指定了完整的文件名/路径。

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


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

gcc-lsome\u dynamic\u lib code.c some\u static\u lib.a

您也可以使用
ld
选项
-Bdynamic

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

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

据我所知,问题如下。您有几个库,一些是静态库,一些是动态库,还有一些是静态库和动态库gcc的默认行为是链接“大部分是动态的”。也就是说,gcc在可能的情况下链接到动态库,但在其他情况下返回到静态库。当您将-static选项用于gcc时,行为是仅链接静态库,如果找不到静态库,即使存在适当的动态库,也会以错误退出

另一个选项,我曾多次希望gcc拥有,我称之为——大部分是静态的,本质上与——动态的(默认设置)相反-如果存在的话,大部分是静态的会倾向于链接静态库,但会退回到动态库

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

  • 构造带有out的链接命令行,包括-static

  • 迭代动态链接选项

  • 累积库路径,即变量中形式为-L的选项

  • 对于每个动态链接选项,即-l格式的选项,运行命令gcc-print file name=lib.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
    
    在我的系统返回上:

    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"
    
    您还可以为gcc库使用:
    -static libgcc-static libstdc++
    标志


    请记住,如果
    libs1.so
    libs1.a
    都存在,则链接器将选择
    libs1.so
    ,如果它在
    -Wl,-Bstatic
    之前或
    -Wl,-Bdynamic
    之后。在调用
    -ls1
    之前,不要忘记传递
    -L/libs1 library location/
    ,还有
    -L:libstatic1.gcc中-L选项的一个
    (减去L冒号)变体,可用于链接静态库(感谢)。有文件记录吗?不在gcc的官方文件中(对于共享LIB也不准确):

    链接时搜索名为library的库。(将库作为单独参数的第二个备选方案仅用于POSIX合规性,不推荐使用。)。。。使用-l选项和指定文件名之间的唯一区别是-l用“lib”和“.a”包围库,并搜索多个目录

    binutils ld文档对此进行了描述。
    -lname
    选项将搜索
    libname.so
    ,然后搜索
    libname.a
    添加lib前缀和
    .so
    (如果此时启用)或
    .a
    后缀。但是
    -l:name
    选项只会精确搜索指定的名称:

    namespec
    指定的存档或对象文件添加到 要链接的文件。此选项可以使用任意次数。如果
    namespec
    的格式为
    :filename
    ,ld将搜索库路径 对于名为
    filename
    的文件,否则将搜索库路径 对于名为
    libnamespec.a
    的文件

    在支持共享库的系统上,ld还可以搜索
    libnamespec.a以外的文件
    。特别是在ELF和SunOS上 系统,ld将搜索一个名为
    libnamespec.so
    在搜索名为
    libnamespec.a的文件之前。(由
    约定,一个
    。因此
    扩展名表示一个共享库。)注意 此行为不适用于始终指定 文件名为
    filename

    Th
    gcc -o test test.c -ldl "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/libpthread.a"
    
    gcc objectfiles -o program -Wl,-Bstatic -ls1 -ls2 -Wl,-Bdynamic -ld1 -ld2
    
    -llibrary
    -l library 
    
    -l namespec
    --library=namespec