为什么不能静态 link 动态库?
Why cant you statically link dynamic libraries?
在使用外部库时,您经常需要决定是使用库的静态版本还是动态版本。通常,你不能交换它们:如果库是作为动态库构建的,你不能link静态地反对它。
为什么会这样?
示例:我正在 windows 上构建一个 C++ 程序并使用一个库,该库为 link 人提供一个小的 .lib
文件和一个大的 .dll
文件运行 我的可执行文件时必须存在。 .dll
中的库代码如果可以在运行时解析,为什么不能在编译时解析直接放入我的可执行文件中呢?
Why is this the case?
大多数 linker(AIX linker 是一个明显的例外)丢弃 linking 过程中的信息。
例如,假设您有 foo.o
和 foo
,以及 bar.o
和 bar
。假设 foo
调用 bar
.
在 link foo.o
和 bar.o
一起进入共享库后,linker 合并代码和数据部分,并解析引用。从 foo
到 bar
的调用变为 CALL $relative_offset
。执行此操作后,您将无法再分辨来自 foo.o
的代码和来自 bar.o
的代码之间的边界在哪里,也无法分辨 CALL $relative_offset
在 foo.o
中使用的名称-- 重定位条目已被丢弃。
假设现在您想 link foobar.so
与您的 main.o
静态,并假设 main.o
已经定义了它自己的 bar
.
如果你有 libfoobar.a
,那将是微不足道的:link 人会从存档中提取 foo.o
, 不会 使用bar.o
从存档中,并从 main.o
.
解析从 foo.o
到 bar
的调用
但应该清楚上面的 none 可以用 foobar.so
-- 调用已经解析到 other bar
,并且您不能丢弃来自 bar.o
的代码,因为您不知道该代码在哪里。
在 AIX 上,可以(或者至少 10 年前它曾经是可能的)"unlink" 共享库并将其转回存档,然后可以静态 linked进入不同的共享库或主可执行文件。
If foo.o
and bar.o
are linked into a foobar.so
, wouldn't it make sense that the call from foo
to bar
is always resolved to the one in bar.o
?
这是 UNIX 共享库与 Windows DLL 工作方式截然不同的一个地方。在 UNIX 上(通常情况下),从 foo
到 bar
的调用将解析为主可执行文件中的 bar
。
这允许一个人,例如在主 a.out
中实现 malloc
和 free
,并让 all 调用 malloc
使用那个 one 堆实现一致。在 Windows 上,您必须始终跟踪 "which heap implementation did this memory come from"。
虽然 UNIX 模型并非没有缺点,因为共享库不是一个独立的主要封闭单元(不像 Windows DLL)。
Why would you want to resolve it to another bar
from main.o
?
如果您不解析对 main.o
的调用,与 link 对 libfoobar.a
.
相比,您最终会得到一个完全不同的程序
在使用外部库时,您经常需要决定是使用库的静态版本还是动态版本。通常,你不能交换它们:如果库是作为动态库构建的,你不能link静态地反对它。
为什么会这样?
示例:我正在 windows 上构建一个 C++ 程序并使用一个库,该库为 link 人提供一个小的 .lib
文件和一个大的 .dll
文件运行 我的可执行文件时必须存在。 .dll
中的库代码如果可以在运行时解析,为什么不能在编译时解析直接放入我的可执行文件中呢?
Why is this the case?
大多数 linker(AIX linker 是一个明显的例外)丢弃 linking 过程中的信息。
例如,假设您有 foo.o
和 foo
,以及 bar.o
和 bar
。假设 foo
调用 bar
.
在 link foo.o
和 bar.o
一起进入共享库后,linker 合并代码和数据部分,并解析引用。从 foo
到 bar
的调用变为 CALL $relative_offset
。执行此操作后,您将无法再分辨来自 foo.o
的代码和来自 bar.o
的代码之间的边界在哪里,也无法分辨 CALL $relative_offset
在 foo.o
中使用的名称-- 重定位条目已被丢弃。
假设现在您想 link foobar.so
与您的 main.o
静态,并假设 main.o
已经定义了它自己的 bar
.
如果你有 libfoobar.a
,那将是微不足道的:link 人会从存档中提取 foo.o
, 不会 使用bar.o
从存档中,并从 main.o
.
foo.o
到 bar
的调用
但应该清楚上面的 none 可以用 foobar.so
-- 调用已经解析到 other bar
,并且您不能丢弃来自 bar.o
的代码,因为您不知道该代码在哪里。
在 AIX 上,可以(或者至少 10 年前它曾经是可能的)"unlink" 共享库并将其转回存档,然后可以静态 linked进入不同的共享库或主可执行文件。
If
foo.o
andbar.o
are linked into afoobar.so
, wouldn't it make sense that the call fromfoo
tobar
is always resolved to the one inbar.o
?
这是 UNIX 共享库与 Windows DLL 工作方式截然不同的一个地方。在 UNIX 上(通常情况下),从 foo
到 bar
的调用将解析为主可执行文件中的 bar
。
这允许一个人,例如在主 a.out
中实现 malloc
和 free
,并让 all 调用 malloc
使用那个 one 堆实现一致。在 Windows 上,您必须始终跟踪 "which heap implementation did this memory come from"。
虽然 UNIX 模型并非没有缺点,因为共享库不是一个独立的主要封闭单元(不像 Windows DLL)。
Why would you want to resolve it to another
bar
frommain.o
?
如果您不解析对 main.o
的调用,与 link 对 libfoobar.a
.