目标文件与库文件,为什么? [英] Object files vs Library files and why?

查看:44
本文介绍了目标文件与库文件,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解编译的基础知识.源文件编译为目标文件,然后链接程序将其链接到可执行文件中.这些目标文件由包含定义的源文件组成.

I understand the basics of compilation. Source files compiled to object files which the linker then links into executables. These object files are comprised of source files containing definitions.

所以我的问题是:

  • 为什么我们有一个单独的库实现?.a .lib,.dll ...
  • 我可能会误会,但是在我看来,.o文件本身和图书馆是一样的东西吗?
  • 有人不能给您他们对某项的.o实现声明(.h),您可以将其替换并链接到成为可执行相同功能的可执行文件,但是使用不同的操作?

推荐答案

从历史上看,对象文件要么完全链接,要么根本不链接到可执行文件(如今,有些例外,例如功能级链接整个程序优化变得越来越流行),因此,如果使用目标文件的一个功能,则可执行文件会接收所有这些功能.

Historically, an object file gets linked either completely or not at all into an executable (nowadays, there are exceptions like function level linking or whole program optimization becoming more popular), so if one function of an object file is used, the executable receives all of them.

为使可执行文件更小且没有死代码,标准库被拆分为许多小目标文件(通常为数百个).出于效率方面的考虑,拥有数百个小文件是非常不希望的:打开许多文件效率很低,并且每个文件都有一定的余量(文件末尾的未使用磁盘空间).这就是为什么将目标文件分组到库中的原因,这有点像没有压缩的ZIP文件.在链接时,将读取整个库,并且当链接程序开始读取库或它们所需的目标文件时,该库中所有解析符号的对象文件都已包含在输出中.这可能意味着整个库必须一次在内存中以递归方式解决依赖关系.由于内存量非常有限,链接器一次只能加载一个库,因此链接器命令行上稍后提到的库不能使用命令行前面提到的库中的函数.

To keep executables small and free of dead code, the standard library is split into many small object files (typically in the order of hundreds). Having hundreds of small files is very undesirable for efficiency reasons: Opening many files is inefficient, and every file has some slack (unused disk space at the end of the file). This is why object files get grouped into libraries, which is kind of like a ZIP file with no compression. At link time, the whole library is read, and all object files from that library that resolve symbols already known as unresolved when the linker started reading a library or object files needed by them are included into the output. This likely means that the whole library has to be in memory at once to recursively solve dependencies. As the amount of memory was quite limited, the linker only loads one library at a time, so a library mentioned later on the command line of the linker can not use functions from a library mentioned earlier on the command line.

为提高性能(加载整个库需要一些时间,尤其是从软盘之类的慢速介质加载),库通常包含一个 index ,它告诉链接器哪些对象文件提供了哪些符号.索引是由诸如 ranlib 之类的工具或库管理工具(Borland的 tlib 具有用于生成索引的开关)创建的.一旦有了索引,即使所有目标文件都在磁盘高速缓存中并且从磁盘高速缓存中加载文件都是免费的,库肯定比链接单个目标文件更有效.

To improve the performance (loading a whole library takes some time, especially from slow media like floppy disks), libraries often contain an index that tells the linker what object files provide which symbols. Indexes are created by tools like ranlib or the library management tool (Borland's tlib has a switch to generate the index). As soon as there is an index, libraries are definitely more efficient to link then single object files, even if all object files are in the disk cache and loading files from the disk cache is free.

您完全正确,我可以在保留头文件的同时替换 .o .a 文件,并更改函数的功能(或它们的工作方式).这由 LPGL-license 使用,它要求使用 LGPL-licensed 库的程序的作者为用户提供通过修补程序替换该库的可能性.,改进或替代的实施方式.交付自己应用程序的目标文件(可能被分组为库文件)足以为用户提供所需的自由度.无需运送源代码(例如 GPL ).

You are completely right that I can replace .o or .a files while keeping the header files, and change what the functions do (or how they do it). This is used by the LPGL-license, which requires the author of a program that uses an LGPL-licensed library to give the user the possibility to replace that library by a patched, improved or alternative implementation. Shipping the object files of the own application (possibly grouped as library files) is enough to give the user the required freedom; no need to ship the source code (like with the GPL).

如果两组库(或目标文件)可以成功用于相同的头文件,则它们被认为与 ABI兼容,其中ABI表示 Application Binary Interface >.这比仅具有两组库(或目标文件)以及它们各自的头文件要狭窄得多,并保证如果您为此特定库使用头文件,则可以使用每个库.这称为 API兼容性,其中API表示应用程序接口.作为区别的示例,请看以下三个头文件:

If two sets of libraries (or object files) can be used successfully with the same header files, they are said to be ABI compatible, where ABI means Application Binary Interface. This is more narrow than just having two sets of libraries (or object files) accompanied by their respective headers, and guaranteeing that you can use each library if you use the headers for this specific library. This would be called API compatibility, where API means Application Program Interface. As an example of the difference, look at the following three header files:

文件1:

typedef struct {
    int a;
    int __undocumented_member;
    int b;
} magic_data;
magic_data* calculate(int);

文件2:

struct __tag_magic_data {
    int a;
    int __padding;
    int b;
};
typedef __tag_magic_data magic_data;
magic_data* calculate(const int);

文件3:

typedef struct {
    int a;
    int b;
    int c;
} magic_data;
magic_data* do_calculate(int, void*);
#define calculate(x) do_calculate(x, 0)

前两个文件并不相同,但是它们提供了可交换的定义(据我所期望的)不违反一个定义规则",因此提供File 1作为头文件的库也可以与File一起使用.2作为头文件.另一方面,文件3提供了与程序员非常相似的界面(库作者向库用户承诺的所有界面可能都是相同的),但是用文件3编译的代码无法与旨在使用的库链接使用文件1或文件2,因为为文件3设计的库将不会导出 calculate ,而只会导出 do_calculate .同样,该结构具有不同的成员布局,因此使用文件1或文件2而不是文件3将无法正确访问b.提供文件1和文件2的库与ABI兼容,但是所有三个库都与API兼容(假设c和功能更强大的函数 do_calculate 不计入该API).

The first two files are not identical, but they provide exchangeable definitions that (as far as I expect) do not violate the "one definition rule", so a library providing File 1 as header file can be used as well with File 2 as a header file. On the other hand, File 3 provides a very similar interface to the programmer (which might be identical in all that the library author promises the user of the library), but code compiled with File 3 fails to link with a library designed to be used with File 1 or File 2, as the library designed for File 3 would not export calculate, but only do_calculate. Also, the structure has a different member layout, so using File 1 or File 2 instead of File 3 will not access b correctly. The libraries providing File 1 and File 2 are ABI compatible, but all three libraries are API compatible (assuming that c and the more capable function do_calculate do not count towards that API).

对于动态库(.dll,.so),情况完全不同:它们开始出现在可以同时加载多个(应用程序)程序的系统上(在DOS中不是这种情况,但实际情况是这样)在Windows上).多次在内存中使用相同的库函数实现是浪费的,因此只能加载一次,并且多个应用程序都使用它.对于动态库,所引用功能的代码不包括在可执行文件中,而仅包括对动态库内部功能的引用(对于Windows NE/PE,它指定哪个DLL必须提供哪个功能.对于在Unix .so文件中,仅指定函数名称和一组库.)操作系统包含一个 loader dynamic链接器,它可以解析这些引用,并在程序启动时在内存中还没有加载动态库的情况下加载动态库.

For dynamic libraries (.dll, .so) things are completely different: They started appearing on systems where multiple (application) programs can be loaded at the same time (which is not the case on DOS, but it is the case on Windows). It is wasteful to have the same implementation of a library function in memory multiple times, so it is loaded only once and multiple applications use it. For dynamic libraries, the code of the referenced function is not included in the executable file, but just a reference to the function inside a dynamic library is included (For Windows NE/PE, it is specified which DLL has to provide which function. For Unix .so files, only the function names and a set of libraries are specified.). The operating system contains a loader aka dynamic linker that resolves these references and loads dynamic libraries if they are not already in memory at the time a program is started.

这篇关于目标文件与库文件,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆