Linux下链接问题小结(undefined reference)

时间:2014-10-24 01:40:11   收藏:0   阅读:11024

一直以来对Linux下编译链接产生的问题没有好好重视起来,出现问题就度娘一下,很多时候的确是在搜索帮助下解决了BUG,但由于对原因不求甚解,没有细细研究,结果总是在遇到在BUG时弄得手忙脚乱得。

甚至有时候为了一个问题查了半天的资料,好不容易解决了,却因为没有记录下来或者没有弄清楚真实原因,结果第二次碰到还是要去重复前次的折腾,很是尴尬无奈。

虽然,同样的错误信息,其产生的原因不一而足,但是,总结一下终归是好的,使不知变知之,只要不在同一件事情上重复同样的错误,发现的问题越多,解决的问题越多,未知的问题也就越少,不是吗?

针对Linux下编译链接的问题,网络上不乏有牛人经典的原创好文,不得不说,现在网络的发达让人们:不足出户,就可以万事不求人。废话少说,言归正传罢:

1, 现在先看一个最简单的例子,那就是我们经常在编程语言入门时最常见的"Hello World!"例子:

<main.cpp>

#include <stdio.h>
int main(int argc, char *agv[])
{
    printf("Hello World\n");
    return 0;
}

编译这个程序我们最简单的方法就是:g++ main.cpp;然后编译器便会对源文件进行编译链接,最后生成默认的a.out执行文件。期间并不会出现任何错误提示。

对比一下当我们使用第3方软件库时,要添加一些必要的编译参数(比如说:-I库头文件;-l库名;-L库路径),才能让编译器正常工作而不出现错误提示。

个中原因就在于:前者是标准库,已经被做成系统软件库的一分子,编译器可以直接在系统上拿过来使用,所以从表面上看会省略掉一些参数和细节。

其实不管是使用系统标准库,还是使用第3方软件生成库,抑或是我们自己软件生成库,编译器在进行编译链接时,除了库名和路径不同外,他们的编译链接原理都是相同相通的。

2,编译和链接

语法上的错误比较基础,我们不做讨论;

"#include <头文件名>" 和 "-I<目录>" :解决的是编译问题,前者是头文件名,后者是头文件所在目录

"-l<库名>" 和 "-L<目录>" :是解决的链接问题, 前者是库名,后者是库名所在目录

下面是main ->main.o -> test.o的例子,

各文件源代码如下:

test.h

//test.h
extern void test();

test.cpp

//test.cpp
#include <stdio.h>
#include <test.h> void test() { printf("Hello World!\n"); }

main.cpp

//main.cpp
#include "test.h"
int main(void) 
{ 
    test();
    return 0;
}

正确编译步骤:

[root@localhost link]# g++ -o main main.cpp test.cpp

现在我们对这个例子做一下变形:

检查编译链接参数,看看有没有把接口所在的库文件包含进来。

2.1  编译选项在链接时缺少库文件(.o/.so/.a)

[root@localhost link]# g++ -o main main.cpp
main.o: In function `main‘:
main.cpp:(.text+0x5): undefined reference to `test()‘
collect2: ld returned 1 exit status
[root@localhost link]# g++ -o main test.cpp
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start‘:
(.text+0x20): undefined reference to `main‘
collect2: ld returned 1 exit status

1, 编译选项中,缺少库文件(.o/.so/.a),
    如: g++ main test.cpp <main.cpp>
           g++ main -l<lib1> -l<lib2>

2,编译选项中,多个依赖库的顺序不对,尤其是对静态库来说,顺序是很讲究的。
    如: main->test->func;那么g++ main main.cpp func.a test.a 将会报出

[root@localhost link]# g++ -o main main.o func.a test.a
test.a(test.o): In function `test()‘:
test.cpp:(.text+0x5): undefined reference to `func()‘
collect2: ld returned 1 exit status

附上静态库生成命令:

g++ -c test.cpp -o test.o
g++ -c func.cpp -o func.o
ar -rcs func.a func.o
ar -rcs test.a test.o

2,函数接口未实现

/tmp/ccE1htXD.o: In function `main‘:
main.cpp:(.text+0x5): undefined reference to `test()‘
collect2: ld returned 1 exit status

A: test.h void test();
  test.cpp: void Test() {} 或 void test(int n) {} 或 int test() {}

3,函数接口实现了,但是

3.1 调用接口命名重编或调用约定不一致引起的接口导出不匹配,比如说跨语言调用接口(如C++调用C生成库的接口)时。
  

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!