在与GCC链接时,如何仅将某些特定库静态链接到我的二进制文件?
gcc ... -static ...
尝试静态链接所有链接库,但我没有其中一些的静态版本(例如:libX11)。
答案 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.so
和libs1.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 会更喜欢链接静态库,但会回归动态库。
此选项不存在,但可以使用以下算法进行模拟:
构建包含 -static 的链接命令行。
迭代动态链接选项。
累积库路径,即变量&lt; lib_path&gt;
对于每个动态链接选项,即 -l&lt; lib_name&gt; 形式的选项,运行命令 gcc&lt; lib_path&gt; -print-file-name = lib&lt; lib_name&gt; .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
例如:
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
否则,它将无法正常工作。我花了一些时间才弄明白。