为什么我们在编译期间需要共享库
为什么在可执行文件的编译期间我们需要共享库的存在? 我的理由是,由于共享库未包含在我的可执行文件中并且在运行时加载,因此在编译期间不应该需要它。 或者我错过了什么?
#include 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
gcc -o main main.c -L. -lfoo
给main.c:(.text+0x28): undefiend reference to 'addNumber'
我认为只有共享库的名称才足够。 不需要共享库本身,因为它位于LD_LIBRARY_PATH中并在运行时动态加载。 除了共享库的名称之外还需要其他东西吗?
在编译时不需要任何东西,因为C有一个单独编译翻译单元的概念。 但是,一旦编译完所有不同的来源,就可以将所有内容链接在一起了。 共享库的概念在标准中不存在,但它现在是常见的,所以这是公共链接器如何进行:
- 它在所有已编译的模块中查找具有已定义或仅声明的外部链接的标识符
- 它在库(静态和动态)中查找已使用且未定义的标识符。 然后,它将模块与静态库链接起来,并存储动态库中的引用。 但至少在Unix喜欢的情况下,它需要访问共享库以获取潜在的必需(已声明和未定义)标识符,以确保它们已经定义或可以在其他链接库中找到,无论是静态还是动态
这会生成可执行文件。 然后在加载时,动态加载器知道所需的所有动态模块,并将它们与实际可执行文件一起加载到内存中(如果它们尚未存在)并构建(虚拟)内存映射
gcc -o main main.c -L. -lfoo
此命令执行(至少)两个步骤:将main.c
编译为目标文件,并将所有资源链接到可执行main
文件中。 您看到的错误来自最后一步,即链接器。
链接器负责生成最终的可执行机器代码。 它需要共享对象库,因为它需要生成加载它的机器代码并执行其中使用的任何函数。