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.so
和libs1.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进行仿真:
-
构build包含静态链接的命令行。
-
迭代dynamic链接选项。
-
累积库path,即variables<lib_path>中forms为-L <lib_dir>的选项
-
对于每个dynamic链接选项,即forms为-l <lib_name>的那些选项,运行命令gcc <lib_path> -print-file-name = lib <lib_name> .a并捕获输出。
-
如果该命令打印的内容不是您传递的内容,则它将成为静态库的完整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也可以search
libnamespec.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
否则,它将无法正常工作。 它需要我一些时间来弄清楚。