在文章http://blog.csdn.net/stpeace/article/details/50985578中, 我说过makefile指定头文件和库文件出错的那点破事, 今天破事重提, 用实际例子来聊一下.
taoge@localhost Desktop> cat basic_add.c int basic_add(int x, int y) { return x + y; }
taoge@localhost Desktop> cat taoge_add.c int basic_add(int x, int y); int add(int x, int y) { basic_add(x, y); }
taoge@localhost Desktop> cat main.c #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> typedef int (*pFUN)(int, int); // 函数指针类型 int main() { void *pHandle = NULL; char *pError = NULL; pFUN pfun = NULL; pHandle = dlopen("./libtaoge.so", RTLD_NOW); // 打开动态链接库 if (NULL == pHandle) { printf("dlopen:%s\n", dlerror()); return -1; } pfun = dlsym(pHandle, "add"); if ((pError = dlerror()) != NULL) // 这里不要直接用pfun和NULL比较 { printf("dlsym:%s\n", pError); return -2; } printf("sum is : %d\n", (*pfun)(1, 2)); dlclose(pHandle); return 0; }我们分别来看看之前说的三个问题(之前那篇文章说过的):
1. 如果在代码中包含了某头文件test.h, 但在makefle中没有指定头文件路径/或者头文件根本不存在, 会出现编译错误, 会提示缺少test.h.
2. 如果包含了test.h头文件,且指定了头文件路径, 且指定libtest.a库, 但实际此库并不存在(比如没有提前编译出来), 会出现编译错误, 提示缺少 cannot find -ltest
3.如果包含了头文件,且指定了头文件路径, 但makefile没有指定libtest.a库, 编译的时候不会出问题, 但运行的时候会出问题: dlopen ... failed, undefined symbol ...
分别来看一下(因程序比较简单, 我就不用makefile了):
1. 缺少头文件或者没有指定头文件, 肯定不行啊。这个比较好理解, 但我们本文中没有涉及到自己的头文件, 所以就不多说了。
2. 我们来看看:
taoge@localhost Desktop> gcc -c basic_add.c taoge@localhost Desktop> ar rcs libBasicAdd.a basic_add.o taoge@localhost Desktop> rm libBasicAdd.a taoge@localhost Desktop> gcc -shared -fPIC taoge_add.c -o libtaoge.so -L./ -lBasicAdd /usr/lib/gcc/i586-suse-linux/4.1.2/../../../../i586-suse-linux/bin/ld: cannot find -lBasicAdd collect2: ld returned 1 exit status果然如此。
3. 我们俩看看:
taoge@localhost Desktop> gcc -c basic_add.c taoge@localhost Desktop> ar rcs libBasicAdd.a basic_add.o taoge@localhost Desktop> gcc -shared -fPIC taoge_add.c -o libtaoge.so taoge@localhost Desktop> gcc main.c -o a.out -ldl taoge@localhost Desktop> ./a.out dlopen:./libtaoge.so: undefined symbol: basic_addoh my god, 在运行期间出错了, 那有办法在编译期提前发现吗? 有的, 用ldd, nm, readelf, objdump (当然用ldd -r最简单啦!)
taoge@localhost Desktop> ldd -r libtaoge.so undefined symbol: basic_add (./libtaoge.so) linux-gate.so.1 => (0xbfffe000) /lib/libonion.so (0xb7f99000) libc.so.6 => /lib/libc.so.6 (0xb7e4f000) libdl.so.2 => /lib/libdl.so.2 (0xb7e4a000) libpthread.so.0 => /lib/libpthread.so.0 (0xb7e33000) /lib/ld-linux.so.2 (0x80000000) taoge@localhost Desktop> nm -u libtaoge.so U basic_add w __cxa_finalize@@GLIBC_2.1.3 w __gmon_start__ w _Jv_RegisterClasses taoge@localhost Desktop> readelf -a libtaoge.so | grep UND 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 12: 00000000 0 NOTYPE GLOBAL DEFAULT UND basic_add 15: 00000000 231 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (2) 18: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 19: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 55: 00000000 0 NOTYPE GLOBAL DEFAULT UND basic_add 58: 00000000 231 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.1 61: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 62: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ taoge@localhost Desktop> objdump -x libtaoge.so | grep UND 00000000 *UND* 00000000 basic_add 00000000 w F *UND* 000000e7 __cxa_finalize@@GLIBC_2.1.3 00000000 w *UND* 00000000 _Jv_RegisterClasses 00000000 w *UND* 00000000 __gmon_start__可以看到, basic_add没有定义!!!
如上问题的解决方法, 我们早都说过了, 也就不赘述了。