动态链接是如何工作的,它的用法以及你如何以及为什么要制作一个 dylib

How dynamic linking works, its usage and how and why you would make a dylib

我已经阅读了几篇有关堆栈溢出的文章,并在网上阅读了有关动态 linking 的文章。这就是我从所有这些读数中得到的 -

动态linking 是一种优化技术,用于充分利用系统的虚拟内存。一个进程可以与其他进程共享其页面。例如,libc++ 需要与所有 C++ 程序一起 linked,而不是将可执行文件复制到每个进程,它可以通过共享虚拟页面与许多进程动态地 linked。

然而,这让我想到了以下问题

  1. 编译 C++ 程序时。它需要引用 C++ 库函数和代码(例如线程库的代码)。编译器如何使可执行文件具有这些引用?这不会导致编译器和操作系统之间的循环依赖吗?由于编译器必须在可执行文件中引用动态库。
  2. 您将如何以及何时使用动态库?你怎么做一个?用于从标准 *.cpp 文件生成此类文件的特定编译命令是什么?
  3. 通常当我安装库时,有一个 lib/ 目录,其中包含 *.a 个文件和 *.dylib(在 mac-OSX 上)文件。我如何知道哪些要 link 静态编辑,就像我对常规 *.o 文件所做的那样,哪些应该动态 link 编辑?我假设 *.dylib 文件是动态库。 link 将使用哪个编译器标志?
  4. -L-l 标志有什么用?在命令行上指定 -lusb 标志是什么意思?

如果您觉得这个问题一次问了太多事情,请告诉我。我完全可以将这个问题分成多个问题。我只是一起问他们,因为我觉得一个问题的答案会引出另一个问题。

主要区别在于您的应用包含静态链接库。当您构建应用程序时,它们会链接在一起。动态库在 运行 次链接,因此您无需将它们包含在您的应用程序中。如今,动态库被用于通过在每个人的计算机上拥有许多动态库来减小应用程序的大小。

动态库还允许用户更新库而无需重新构建客户端应用程序。如果在您的应用程序中使用的库中发现错误并且它是静态链接的,您将不得不重建您的应用程序并将其重新发布给所有用户。如果在动态链接库中发现错误,您的所有用户只需要更新他们的库,而您的应用程序不需要更新。

When a C++ program is compiled. It needs to have references to the C++ library functions and code (say for example the code for the library).

假设我们有一个名为 libdyno.so 的假设共享库。您最终将能够使用 objdumpnm.

来查看它的内部
objdump --syms libdyno.so

您今天可以在您的系统上使用任何共享库执行此操作。 MAC 上的 objdump 称为 gobjdump 并在 binutils 包中随 brew 一起提供。在 mac...

上试试这个
gobjdump --syms /usr/lib/libz.dylib

您现在可以看到符号包含在共享对象中。当您 link 使用共享对象时,您通常会使用类似

的东西
g++ -Wall -g -pedantic -ldyno DynoLib_main.cpp -o dyno_main

注意该命令中的 -ldyno。这是告诉编译器(实际上是 linker ld)在通常查找它们的任何地方查找名为 libdyno.so 的共享对象文件。一旦找到该对象,它就可以找到所需的符号。没有循环依赖,因为开发人员要求通过指定 -l 标志加载动态库。

How and when would you use a dynamic library? How do you make one? As in what is the specific compiling command that is used to produce such a file from a standard .cpp file

创建一个名为 DynoLib.cpp

的文件
#include "DynoLib.h"
DynamicLib::DynamicLib() {}
int DynamicLib::square(int a) {
  return a * a;
}

创建一个名为 DynoLib.h

的文件
#ifndef DYNOLIB_H
#define DYNOLIB_H
class DynamicLib {
  public:
  DynamicLib();
  int square(int a); 
};
#endif

编译成共享库如下。这是 linux 具体...

g++ -Wall -g -pedantic -shared -std=c++11 DynoLib.cpp -o libdyno.so

您现在可以使用我之前给出的命令检查此对象,即

objdump --syms libdyno.so

现在创建一个名为 DynoLib_main.cpp 的文件,它将用 libdyno.so 编辑 link 并使用我们刚刚在其中定义的函数。

#include "DynoLib.h"    
#include <iostream>     
using namespace std;
int main(void) {
  DynamicLib *lib = new DynamicLib();
  std::cout << "Square " << lib->square(1729) << std::endl;
  return 1;
}

编译如下

g++ -Wall -g -pedantic -L. -ldyno DynoLib_main.cpp -o dyno_main
./dyno_main
Square 2989441

您还可以使用 nm 查看主二进制文件。在下文中,我查看其中是否有字符串 square 的任何内容,即我需要的符号 libdyno.so 以任何方式在我的二进制文件中引用。

nm dyno_runner |grep square
U _ZN10DynamicLib6squareEi

答案是肯定的。大写 U 表示未定义,但这是我们之前在 DynamicLib Class 中创建的 square 方法的符号名称。看起来很奇怪的名字是由于名称修改造成的,这是它自己的主题。

How do I know which ones to link to statically as I would with a regular .o file and which ones are supposed to be dynamically linked with?

你不需要知道。您指定要 link 的内容,然后让编译器(和 linker 等)完成工作。请注意 -l 标志为库命名,-L 告诉它在哪里查找。这里有一篇关于编译器如何找到东西的不错的文章

gcc Linkage option -L: Alternative ways how to specify the path to the dynamic library

或者看看man ld

What are the -L and -l flags for? What does it mean to specify for example a -lusb flag on the command line?

见上文link。这是来自 man ld..

-L searchdir

Add path searchdir to the list of paths that ld will search for archive libraries and ld control scripts. You may use this option any number of times. The directories are searched in the order in which they are specified on the command line. Directories specified on the command line are searched before the default directories. All -L options apply to all -l options, regardless of the order in which the options appear. -L options do not affect how ld searches for a linker script unless -T option is specified.`

如果您设法到达这里,了解 linker ie ld 将带来红利。它起着重要的作用,并且是大量混乱的根源,因为大多数人开始与编译器打交道并认为 compiler == linker 而事实并非如此。