共享库:Windows 与 Linux 方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16737347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shared Libraries: Windows vs Linux method
提问by QAH
I have a quick question about Windows shared libraries (DLLs) vs Linux shared libraries (SOs).
我有一个关于 Windows 共享库 (DLL) 与 Linux 共享库 (SO) 的快速问题。
Why is it that when you create a Windows DLL it requires the client program to also link against a static library (.lib file), but applications created in Linux does not require any linking against such static library.
为什么当您创建 Windows DLL 时,它需要客户端程序也链接到静态库(.lib 文件),但在 Linux 中创建的应用程序不需要链接到此类静态库。
Does it have anything to do with code relocation and the like? Thanks.
和代码重定位之类的有什么关系吗?谢谢。
采纳答案by rodrigo
Not actually with code relocation, that's a totally different issue. It is about a difference in architecture:
实际上不是代码重定位,这是一个完全不同的问题。这是关于架构上的差异:
In Windows, a DLL is just like a executables (EXE). The main difference between an EXE and a DLL is that the EXE has an entry point (main/WinMain function) and so it can be used to start a process, while DLLs can only be loaded into a pre-existing process. But see (1)
In Linux, a .so work similar to a static library (.a). The main difference is that the .so file can be linked with a running program, while the .a file can only be linked when compiling the program.
在 Windows 中,DLL 就像一个可执行文件 (EXE)。EXE 和 DLL 之间的主要区别在于 EXE 有一个入口点(main/WinMain 函数),因此它可用于启动进程,而 DLL 只能加载到预先存在的进程中。但见(1)
在 Linux 中,.so 的工作类似于静态库 (.a)。主要区别在于.so文件可以与正在运行的程序链接,而.a文件只能在编译程序时链接。
A consequence of this approach is that in linux the same file can be used to build and run the program. But in Windows you need a proper library (LIB) to link the program. Actually the lib that corresponds to a DLL usually have nothing more than the names of the functions, to satisfy the linker, and the stubs to do the relocation. But see (2)
这种方法的结果是在 linux 中可以使用相同的文件来构建和运行程序。但是在 Windows 中,您需要一个合适的库 (LIB) 来链接程序。实际上,对应于DLL 的lib 通常只有函数的名称,以满足链接器和进行重定位的存根。但见(2)
(1) Well, DLLs have entry point too, but it is not used as the main function, just as some sort of initialization/finalization hook.
(1) 嗯,DLL 也有入口点,但它不用作主函数,只是作为某种初始化/终结钩子。
(2) Some linkers are smart enough to be able, in some simple cases, to link to a DLL by using the DLL itself, without the need of an additional LIB file. I think that at least the MinGW linker can do that.
(2) 一些链接器足够聪明,在一些简单的情况下,可以通过使用 DLL 本身链接到 DLL,而无需额外的 LIB 文件。我认为至少 MinGW 链接器可以做到这一点。
回答by James Holderness
In Windows, the client program does not need to link with a static library in order to access functions in a DLL. The dynamic linking can happen entirely at run time without the client program even being aware of the existence of the DLL at the time it was compiled.
在 Windows 中,客户端程序不需要链接静态库来访问 DLL 中的函数。动态链接可以完全在运行时发生,而客户端程序甚至在编译时都不知道 DLL 的存在。
For example, if you wanted to call a function name "foo" in a DLL named "bar.dll", you could write code like this:
例如,如果您想在名为“bar.dll”的 DLL 中调用名为“foo”的函数,您可以编写如下代码:
HINSTANCE hinst = LoadLibrary("bar.dll");
FARPROC foo = GetProcAddress(hinst, "foo");
foo();
And "foo" and "bar.dll" could easily have been values that were only established at run time, say via a configuration file or some other user input.
“foo”和“bar.dll”很容易成为仅在运行时建立的值,比如通过配置文件或其他一些用户输入。
The purpose of the static library is to automate this dynamic loading process, by creating stubs that appear like to be regular functions as far as the client program is concerned, but are linked to the DLL at runtime. Typically this linking happens at the time the client process is loaded, but libraries can also be generated that will load and link on demand, so the DLL won't be brought into memory until it is actually needed. It is the static library that determines when the linking occurs.
静态库的目的是通过创建存根来自动执行此动态加载过程,这些存根就客户端程序而言似乎是常规函数,但在运行时链接到 DLL。通常,这种链接发生在加载客户端进程时,但也可以生成将按需加载和链接的库,因此在实际需要之前不会将 DLL 带入内存。静态库决定了何时发生链接。
For the most part, a compiler can generate these libraries automatically, so technically they aren't needed when just linking to DLL functions. However, the one exception to this (that I'm aware of) is when linking to shared variables.
大多数情况下,编译器可以自动生成这些库,因此从技术上讲,仅在链接到 DLL 函数时不需要它们。但是,对此的一个例外(我知道)是链接到共享变量时。
In a Windows DLL you can create a shared data segment with variables that can be accessed by any process that has loaded that DLL. The information about the size and types of those variables is stored in the associated static library, and can't be determined from the DLL alone. In order to access those variables, the client program must link against the static library for that DLL.
在 Windows DLL 中,您可以创建一个带有变量的共享数据段,任何加载该 DLL 的进程都可以访问这些变量。有关这些变量的大小和类型的信息存储在相关的静态库中,不能仅从 DLL 中确定。为了访问这些变量,客户端程序必须链接到该 DLL 的静态库。
As far as I'm aware, Linux Shared Libraries don't support such a concept.
据我所知,Linux 共享库不支持这样的概念。
Update
更新
I should also mention that on Windows it's possible to create a DLL where the function entry points are only exported by ordinal (number) rather than name. This can be thought of as a form of data hiding and will typically be used when an implementor wants certain functions to remain private.
我还应该提到,在 Windows 上可以创建一个 DLL,其中函数入口点仅按序数(数字)而不是名称导出。这可以被认为是一种数据隐藏形式,通常在实现者希望某些功能保持私有时使用。
Someone with access to the static library would be able to call those functions by name, since the library would have the details linking the function name to the appropriate ordinal. Anyone who only had the DLL would have to manually link to the functions by ordinal or generate their own static library with made up names.
有权访问静态库的人将能够按名称调用这些函数,因为该库将具有将函数名称链接到适当序数的详细信息。任何只有 DLL 的人都必须按顺序手动链接到函数,或者使用编造的名称生成自己的静态库。
回答by datenwolf
Why is it that when you create a Windows DLL it requires the client program to also link against a static library (.lib file), but applications created in Linux does not require any linking against such static library.
为什么当您创建 Windows DLL 时,它需要客户端程序也链接到静态库(.lib 文件),但在 Linux 中创建的应用程序不需要链接到此类静态库。
This is a historic design decision made by Microsoft so that the linker could add DLL references into an executable without having a particular version of the DLL being present at link time. The reason for this was, that there always have been different versions of Windows around, with different versions of DLLs. Also at that time Microsoft was cooperating with IBM on OS/2 and the plan was, that Windows programs could be executed on OS/2 as well. Well, Microsoft decided to "backstab" OS/2, by rolling their own professional grade OS, based on the NT kernel. But this meant, that for development you wanted developers to be able to link against system DLLs, without having all the different variants of the DLL available. Instead a dynamic linkage "template" would have been used for creating both the DLL and the executables (both being in the PE format), which are these particular .lib
files, which are not libraries at all, but merely symbol and ordinal tables (this is a little known fact, but PE binary symbols can be loaded not only by a string identifier, but also by a integer number, the so called ordinal).
这是 Microsoft 做出的历史性设计决策,因此链接器可以将 DLL 引用添加到可执行文件中,而无需在链接时存在特定版本的 DLL。这样做的原因是,总是有不同版本的 Windows,具有不同版本的 DLL。也是当时微软在 OS/2 上与 IBM 合作,计划是 Windows 程序也可以在 OS/2 上执行。好吧,Microsoft 决定通过推出基于 NT 内核的他们自己的专业级操作系统来“支持”OS/2。但这意味着,对于开发,您希望开发人员能够链接系统 DLL,而无需提供 DLL 的所有不同变体。取而代之的是动态链接“模板”.lib
文件,它们根本不是库,而只是符号和序数表(这是一个鲜为人知的事实,但 PE 二进制符号不仅可以通过字符串标识符加载,还可以通过整数加载,即所谓的序数)。
A side effect of ordinals is, that they allow to hide the human readable symbols, so that you could make use of the DLL only if you knew the ordinal ←→ function relationship.
序数的一个副作用是,它们允许隐藏人类可读的符号,因此只有当您知道序数 ←→ 函数关系时才能使用 DLL。
In Unix the tradition was, "you build it on the system you're going to run it on", or "you have all the target system files in place". So there was never an incentive so separate library and linkage information. Technically the same would work for DLLs, too. PEs can export a symbol and relocation table, which DLLs do, and a linker could grab all the information it requires from that, just fine.
在 Unix 中,传统是“在要运行它的系统上构建它”,或者“你拥有所有目标系统文件”。所以从来没有一个激励如此分开的图书馆和链接信息。从技术上讲,同样适用于 DLL。PE 可以导出符号和重定位表,DLL 可以这样做,链接器可以从中获取它需要的所有信息,就好了。
If you were to hide symbols with Unix shared objects, you'd normally do this by using a single struct
with all the function pointers in it, and only exporting a global constant instance of this struct by name, which contains a lot of not explicitly named pointers. You could do exactly the same with Windows DLLs, though.
如果你要隐藏带有 Unix 共享对象的符号,你通常会通过使用一个struct
包含所有函数指针的单个来做到这一点,并且只按名称导出此结构的全局常量实例,其中包含许多未明确命名的指针。不过,您可以对 Windows DLL 执行完全相同的操作。
TL;DR: The reason for this is not a technical one, but a marketing and distribution decision one.
TL;DR:这样做的原因不是技术原因,而是营销和分销决策。