Linux 动态链接库
最近由于一个偶然的机会,看到了一个作业里面需要用到动态链接库。回想起以前在PA的课上似乎有过这个知识,但是没有去尝试,所以抄了网上的一个demo。
文件内容
这里有三个文件,foo.h,foo.c和main.c。foo.c是我们想要生成共享库,foo.h提供了共享库中的调用接口,然后main.c调用了共享库进行测试。
//foo.h
#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif // foo_h__
//foo.c:
#include <stdio.h>
void foo(void)
{
puts("Hello, I am a shared library");
}
//main.c:
#include <stdio.h>
#include "foo.h"
int main(void)
{
puts("This is a shared library test...");
foo();
return 0;
}
生成共享库
在gcc编译时使用参数-shared可以生成共享库文件*.so。需要注意的是生成文件的文件名需要使用lib打头,比如生成libfoo.so在链接时就用-lfoo。
gcc -fPIC -shared -o libfoo.so foo.c
动态链接库的使用
通过-lfoo可以将库libfoo链接进程序中。-L.
表示库在当前文件夹下,如果没有的话在链接时就会产生错误。 -Wl,-rpath=.
也表示库在当前目录下,这个是提供给程序运行时的,如果程序运行时在这个目录找不到共享库也会出错。linux默认的共享库放在/usr/lib等文件夹下,如果你把库放到那些文件夹下面就不需要指定-Wl,-rpath
。之后程序就可以编译运行了。这里有一个非常坑的地方,就是-lfoo一定要放在main.c的后面,否则就会报错说函数未定义,感谢懿巨学长发现了这个bug,解决了我一个上午的疑惑。以后要记住把链接的参数写在最后面。
gcc -L. -Wl,-rpath=. -Wall -o test main.c -lfoo
运用
根据上面别人写的例子我写了一个小demo。项目地址
首先介绍一下项目结构, build下存放生成的共享库文件和二进制文件; lib目录放两个共享库,其中world.c依赖hello.c。然后helloworld.c依赖world.c
.
├── build
│ ├── helloworld
│ └── lib
│ ├── libhello.so
│ └── libworld.so
├── helloworld.c
├── lib
│ ├── hello.c
│ ├── hello.h
│ ├── world.c
│ └── world.h
└── Makefile
代码非常简单就是实现打印一行helloworld. 但是这里我们用到了两个共享库。
//hello.c
#include <stdio.h>
void hello()
{
printf("hello ");
}
//world.c
#include "hello.h"
#include <stdio.h>
void world()
{
hello();
printf("world\n");
}
//helloworld.c
#include "lib/world.h"
int main()
{
world();
}
依赖的顺序是helloworld->world->hello。首先编译hello.c生成共享库libhello.so,然后再编译world到libworld.so,最后把helloworld编译出来即可。这里需要注意的是world也需要加-Wl,-rpath
的参数,否则运行时将找不到libhello.so。
# Makefile
helloworld: world helloworld.c
mkdir -p build
gcc -o ./build/helloworld -L./build/lib -Wl,-rpath=./build/lib helloworld.c -lworld
world: hello lib/world.c
mkdir -p build/lib
gcc -shared -o build/lib/libworld.so -L ./build/lib lib/world.c -Wl,-rpath=./build/lib -lhello -fPIC
hello: lib/hello.c
mkdir -p build/lib
gcc -shared -o build/lib/libhello.so lib/hello.c -fPIC
clean:
rm -rf build *.o *.so *.out helloworld