GCC:静态链接只有一些库

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

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

gcc -lsome_dynamic_lib code.c some_static_lib.a

你也可以使用ld选项-Bdynamic

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

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

ld的手册页(这不适用于gcc),参考--static选项:

您可以在命令行上多次使用此选项:它会影响库search后续的-l选项。

一个解决scheme是把你的dynamic依赖关系放在命令行上的--static选项之前。

另一种可能性是不使用--static ,而是提供静态对象文件的完整文件名/path(即不使用-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不在dynamic链接库的列表中,因为它是静态链接的。

注意: .so文件始终是dynamic链接的,即使使用完整的文件名/path指定。

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

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

请记住,如果libs1.solibs1.a都存在,链接器将selectlibs1.so如果它在libs1.so -Wl,-Bstatic之前或libs1.so -Wl,-Bdynamic 。 在调用-ls1之前,不要忘记传递-L/libs1-library-location/

我所了解的问题如下。 你有几个库,一些静态,一些dynamic,一些静态和dynamic。 gcc的默认行为是链接“主要是dynamic的”。 也就是说, gcc尽可能链接到dynamic库,否则会回退到静态库。 当使用-static选项gcc时 ,如果没有find静态库,即使存在适当的dynamic库,行为也只是连接静态库并返回一个错误。

另一个选项,我曾经多次希望gcc有,这就是我所说的 – 几乎是静态的 ,基本上与-dynamic (默认)相反。 大多数情况下,静态的 ,如果它存在,宁愿链接静态库,但会回落到dynamic库。

该选项不存在,但可以使用以下algorithm进行仿真:

  1. 构build包含静态链接的命令行。

  2. 迭代dynamic链接选项。

  3. 累积库path,即variables<lib_path>中forms为-L <lib_dir>的选项

  4. 对于每个dynamic链接选项,即forms为-l <lib_name>的那些选项,运行命令gcc <lib_path> -print-file-name = lib <lib_name> .a并捕获输出。

  5. 如果该命令打印的内容不是您传递的内容,则它将成为静态库的完整path。 将dynamic库选项replace为静态库的完整path。

冲洗并重复,直到处理完整个链接命令行。 或者,脚本还可以从静态链接中取出库名称的列表。

下面的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" 

一些装载机(连接器)提供用于开启和closuresdynamic装载的开关。 如果GCC在这样的系统上运行(Solaris-可能还有其他系统),则可以使用相关的选项。

如果您知道要静态链接哪些库,可以简单地在链接行中指定静态库文件 – 按完整path。

在gcc中还有-l:libstatic1.a (减l冒号)-l选项的变体,可以用来链接静态库(感谢https://stackoverflow.com/a/20728782 )。 有logging吗? 不在gcc的官方文档(这不是确切的共享库): https : //gcc.gnu.org/onlinedocs/gcc/Link-Options.html

 -llibrary -l library 

链接时search名为library的库。 (第二个替代方法是将库作为单独的参数,仅用于POSIX合规性,不推荐使用。)…使用-l选项和指定文件名的唯一区别是-l用lib和'.a'并search几个目录。

binutils ld文档描述了它。 -lname选项将searchlibname.so然后为libname.a添加lib前缀和.so (如果此时启用)或.a后缀。 但-l:name选项只能search指定的名称: https : //sourceware.org/binutils/docs/ld/Options.html

 -l namespec --library=namespec 

将由namespec指定的归档文件或目标文件添加到要链接的文件列表中。 这个选项可以使用任意次数。 如果namespec的格式为:filename ,则ld将search名为filename的文件库path,否则将search名为libnamespec.a的文件的库path。

在支持共享库的系统上,ld也可以searchlibnamespec.a以外的文件。 具体来说,在ELF和SunOS系统上,ld将search名为libnamespec.so的库,然后search名为libnamespec.so的库。 (按照惯例, .so扩展名表示一个共享库。)请注意,这种行为不适用于:filename ,它总是指定一个名为filename

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

请参阅-(可select强制链接器多次search存档的方法。

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

这种types的归档search是Unix连接器的标准。 但是,如果您在AIX上使用ld,请注意它与AIX链接器的行为不同。

变种-l:namespec从binutils(2007)的2.18版本-l:namespec被logging: https -l:namespec

要在一行内连接dynamic库和静态库,必须dynamic库和对象文件之后放置静态库,如下所示:

gcc -lssl main.o -lFooLib -o main

否则,它将无法正常工作。 它需要我一些时间来弄清楚。