动态链接如何工作,其用法以及创建dylib的方式和原因

Cur*_*ous 5 c++ linux compiler-construction linker dynamic-linking

我已经阅读了几篇有关堆栈溢出的文章,并了解了有关在线动态链接的信息。这就是我从所有这些读物中学到的东西-

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

但是,这导致我以下问题

  1. 编译C ++程序时。它需要引用C ++库函数和代码(例如,线程库的代码)。编译器如何使可执行文件具有这些引用?这是否不会导致编译器和操作系统之间的循环依赖?由于编译器必须在可执行文件中引用动态库。
  2. How and when would you use a dynamic library? How do you make one? What is the specific compiling command that is used to produce such a file from a standard *.cpp file?
  3. Usually when I install a library, there is a lib/ directory with *.a files and *.dylib (on mac-OSX) files. 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? I am assuming the *.dylib files are dynamic libraries. Which compiler flag would one use to link to these?
  4. What are the -L and -l flags for? What does it mean to specify for example a -lusb flag on the command line?

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

Har*_*rry 7

当编译 C++ 程序时。它需要引用 C++ 库函数和代码(例如库的代码)。

假设我们有一个假设的共享库,名为libdyno.so. 您最终将能够使用objdump或来查看它的内部nm

objdump --syms libdyno.so
Run Code Online (Sandbox Code Playgroud)

您现在可以在系统上使用任何共享库执行此操作。objdump在 MAC 上被称为gobjdump并在包中附带有brew binutils。在 Mac 上试试这个...

gobjdump --syms /usr/lib/libz.dylib
Run Code Online (Sandbox Code Playgroud)

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

g++ -Wall -g -pedantic -ldyno DynoLib_main.cpp -o dyno_main
Run Code Online (Sandbox Code Playgroud)

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

您将如何以及何时使用动态库?你如何制作一个?用于从标准 .cpp 文件生成此类文件的特定编译命令是什么

创建一个名为 DynoLib.cpp 的文件

#include "DynoLib.h"
DynamicLib::DynamicLib() {}
int DynamicLib::square(int a) {
  return a * a;
}
Run Code Online (Sandbox Code Playgroud)

创建一个名为 DynoLib.h 的文件

#ifndef DYNOLIB_H
#define DYNOLIB_H
class DynamicLib {
  public:
  DynamicLib();
  int square(int a); 
};
#endif
Run Code Online (Sandbox Code Playgroud)

将它们编译为共享库,如下所示。这是Linux特定的...

g++ -Wall -g -pedantic -shared -std=c++11 DynoLib.cpp -o libdyno.so
Run Code Online (Sandbox Code Playgroud)

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

objdump --syms libdyno.so
Run Code Online (Sandbox Code Playgroud)

现在创建一个名为 DynoLib_main.cpp 的文件,该文件将与libdyno.so我们刚刚在其中定义的函数链接并使用。

#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;
}
Run Code Online (Sandbox Code Playgroud)

编译如下

g++ -Wall -g -pedantic -L. -ldyno DynoLib_main.cpp -o dyno_main
./dyno_main
Square 2989441
Run Code Online (Sandbox Code Playgroud)

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

nm dyno_runner |grep square
U _ZN10DynamicLib6squareEi
Run Code Online (Sandbox Code Playgroud)

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

我如何知道哪些文件应该像常规 .o 文件一样静态链接,哪些文件应该动态链接?

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

gcc链接选项-L:指定动态库路径的替代方法

或者看看man ld

-L 和 -l 标志有什么用?例如在命令行上指定 -lusb 标志意味着什么?

请参阅上面的链接。这是来自man ld..

-L 搜索目录

将路径 searchdir 添加到 ld 将搜索存档库和 ld 控制脚本的路径列表中。您可以多次使用此选项。目录按照在命令行中指定的顺序进行搜索。在默认目录之前搜索在命令行上指定的目录。所有 -L 选项均适用于所有 -l 选项,无论选项出现的顺序如何。-L 选项不会影响 ld 搜索链接描述文件的方式,除非指定了 -T 选项。

如果您成功到达这里,了解链接器 ie ld 将会大有裨益。它起着重要的作用,并且是大量混乱的根源,因为大多数人开始处理编译器并认为compiler == linker这是不正确的。