共享库是目标文件的集合,但是这些目标文件是由编译程序按照特殊方式生成的。对象模块的每个地址(变量引用和函数调用)都是相对地址,不是绝对地址。因此允许在运行程序的时候,可以动态加载和执行共享模块。
构造共享库最基本的一步是编译库中的对象模块。例如,下面的两个源文件名为first.c和second.c:
/* first.c */ #include <stdio.h>
void first() { printf("The first hello from a shared library\n"); }
/* second.c */ #include <stdio.h>
int second() { printf("The second hello from a shared library\n"); }
使用下列命令可将这两个源文件编译成一个目标文件:
$ gcc -c -fpic first.c second.c
选项-c明确指出编译程序要生成.o目标文件。而选项-fpic是的输出的对象模块式按照可重定位地址(relocatable addressing)方式生成的。缩写pic代表位置独立代码(position independent code)。
下面的gcc命令使用目标文件构造共享库hello.so:
$ gcc -shared first.o second.o -o hello.so
选项-o为输出文件命令,而后缀.so告诉GCC该目标文件是要连接到共享库的。通常,连接程序要为主函数main()定位,并用它作为程序的入口,但输出模块没有这样的入口,选项-shared对防止出错信息是必要的。
编译程序将后缀为.c的文件看作是C语言源代码程序,并且知道如何将它编译成目标文件。因此,可以将前面的两个命令合成一个命令,用下面的命令可以将模块直接编译并保存为共享库:
$ gcc -fpic -shared first.c second.c -o hello.so
下面试文件main.c中的程序,是主函数,它调用了共享库中的两个函数:
/* main.c */ void first(void); void second(void);
int main(int argc, char **argv) { first(); second();
return 0; }
可以使用下列命令将该程序编译并链接到共享库:
$ gcc main.c hello.so -o hello
程序hello已经可以运行了,但要运行程序必须也要能够定位共享库hello.so,因为库中的函数必须在运行的时候载入。
需要注意的是,当前工作目录可能不在共享库的查找路径中,因此需要使用如下的命令行设定环境变量LD_LIBRARY_PATH:
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
运行结果:
$ ./hello The first hello from a shared library The second hello from a shared library
|