为什么我们在编译期间需要共享库

时间:2018-02-13 16:07:55

标签: c gcc compilation shared-libraries dynamic-linking

为什么在可执行文件的编译期间我们需要共享库的存在?我的理由是,由于共享库未包含在我的可执行文件中并在运行时加载,因此在编译期间不应该需要它。或者我错过了什么?

#include<stdio.h>
int addNumbers(int, int); //prototype should be enough, no? 
int main(int argc, char* argv[]){
  int sum = addNumbers(1,2);
  printf("sum is %d\n", sum);
  return 0;
}

我当前目录中有libfoo.so,但我将其名称更改为libfar.so,以发现编译时需要共享库,或者它不能编译。

gcc -o main main.c -L. -lfoo提供main.c:(.text+0x28): undefiend reference to 'addNumber'

我认为仅拥有共享库的名称就足够了。不需要共享库本身,因为它在LD_LIBRARY_PATH中找到并在运行时动态加载。除了共享库的名称之外是否还需要其他东西?

2 个答案:

答案 0 :(得分:5)

编译时无需任何操作,因为C有单独编译翻译单元的概念。但是,一旦编译完所有不同的来源,就可以将所有内容链接在一起了。共享库的概念在标准中不存在,但它现在是常见的,所以这里是通用链接器如何进行:

  • 它在所有已编译的模块中查找具有已定义或仅声明的外部链接的标识符
  • 它在库中(静态和动态)查找已使用且未定义的标识符。然后,它将模块与静态库链接起来,并存储动态库中的引用。但至少在类Unix上,它需要访问共享库以获取潜在的必需(已声明和未定义)标识符,以确保它们已经定义,或者可以在其他链接库中找到,无论是静态还是动态

这会生成可执行文件。然后在加载时,动态加载程序知道所需的所有动态模块,并将它们与实际可执行文件一起加载到内存中(如果它们尚未存在)并构建(虚拟)内存映射

答案 1 :(得分:0)

gcc -o main main.c -L. -lfoo

此命令执行(至少)两个步骤:将main.c编译为目标文件,并将所有资源链接到可执行文件main。您看到的错误来自最后一步,即链接器。

链接器负责生成最终的可执行机器代码。它需要共享对象库,因为它需要生成加载它的机器代码并执行其中使用的任何函数。