用实例程序再聊makefile指定头文件和库出错的那点破事
2016-10-21 22:38
225 查看
在文章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 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_add oh 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没有定义!!!
如上问题的解决方法, 我们早都说过了, 也就不赘述了。
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_add oh 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没有定义!!!
如上问题的解决方法, 我们早都说过了, 也就不赘述了。
相关文章推荐
- makefile指定头文件和库出错的那点破事
- 续:C# 趣味小程序(4)——遍历特定目录及其子目录 (应用实例,压缩指定目录下的所有文件)
- makefile 中指定程序运行时加载的库文件路径
- 再谈makefile指定头文件和库出错的那点破事(折腾了0.5小时)------三个月后发现了真正原因
- 通用的简单Makefile之单文件单程序
- java程序读取资源文件时路径如何指定
- 如何在C#中用程序执行指定的SQL脚本文件,实现自动安装创建数据库.txt
- Java实现文件或文件夹的复制到指定目录实例
- python中的commands模块,执行出错:'{' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
- SpringMVC注记式验证学习笔记——指定验证出错提示信息资源文件及其编码
- .C# 拷贝一个图片到指定文件夹下(IO文件操作实例)
- ASP.NET程序上传文件功能的具体实例代码
- MATLAB在调用C/C++程序成功,使用opencv库时出错,错误显示“找不到指定模块”(问题未解决)
- QT实现图库程序(一)读取指定目录下的所有文件
- Asp.NET(asp)写文件的一个小实例程序。
- 与众不同 windows phone (38) - 8.0 关联启动: 使用外部程序打开一个文件或URI, 关联指定的文件类型或协议
- 【DEBUG笔记】Visual Studio中“无法启动程序,系统找不到指定的文件”的解决办法
- 安装sql2000时提示:“写时无法打开指定的文件。请确保该文件没有使用,然后重新启动安装程序” .
- win32命令行小程序获取指定文件夹或者目录下面的所有文件大小,文件数量,目录数量
- 让程序在指定路径寻找库文件 + 库文件搜索顺序