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

一直以来对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;
}

正确编译步骤:

[[email protected] link]# g++ -o main main.cpp test.cpp

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

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

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

[[email protected] 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
[[email protected] 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 将会报出

[[email protected] 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生成库的接口)时。
  

时间: 2024-10-06 17:40:27

Linux下链接问题小结(undefined reference)的相关文章

linux + eclipse + cdt 报错undefined reference......好麻烦的,这位大牛给出的方法可行,特此MARK!!!!

http://bbs.csdn.net/topics/390239632 kerosun kerosun 等级: 结帖率:96.92% 楼主 发表于: 2012-10-11 12:00:51 比如有一个tools工程,提供给其他工程通用的工具函数. 我现在的做法就只能是ctrl+c|ctrl+v一旦工具函数发生变化,还需要在用到这些函数的工程中更新,比较麻烦. 看到eclipse工程属性设置中有Project References,但是一直不会用.那位好心人能说说怎样实现我的需求. 更多0分享到

ubuntu下 GCC编译程序出现 undefined reference to `std::ios_base::Init::Init()&#39;问题

网上的解释是:“ you need to add -lstdc++, or use 'g++' rather than 'gcc' as your driver program.”,也就是说如果想要使用g++编译程序的话,那么链接时需要添加“-Istdc++”. 我试了一下 , 在链接时加上"-Istdc++",就没有问题了. 关于g++,让我想起了,在ubuntu下一开始安装完code::blocks的时候,提示需要安装g++.原来code::blocks内置编译器使用的是g++,但

linux下链接出现未定义的应用解决方案

在linux下生成程序时,首先需要编译为.o文件,接着进行链接.在链接的时候容易出现未定义的应用错误,根本原因是找不到函数,但造成该现象有多种可能: 1.源程序中函数名不一致,比方说a.c中为a函数,在b文件调用时却用的时a1,就会造成找不到函数. 2.当链接的o文件不在一个文件夹下时,还需要考虑路径输入不正确,原理与第一条类似. 3链接时.o文件顺序不对,由于函数调用之间存在依赖性,不当的链接顺序也可能导致未定义出现. 4.当利用Makefile进行大型程序编译链接时,与第三种可能原因类似,还

解决qt程序的链接阶段出现 undefined reference 错误

错误的原因是我使用到了 QT Widgets 模块中的东西,但是makefile的链接的参数中没有 widgets.其实官网上提到了这个: http://doc.qt.io/qt-5/qtwidgets-index.html 解决的方法是手动修改你的 .pro 文件,在里面添加下面这句: QT += widgets 如果出现类似的 undefined reference 这种错误应该也是在程序的链接阶段没有找到相应的函数或方法,解决方法也应该类似.

Linux下fastbin利用小结——fd覆盖与任意地址free

linux下的fastbin是ctf中pwn题的重点出题点.去年(2015)中,XCTF就有两站是使用fastbin的利用作为pwn400的压轴题来出现,这也是我刚开始接触fastbin的利用,参考了k0sh1师傅写在freebuf上的一篇文章.我写了几个demo来说明问题. 目录 1.关于fastbin 2.覆盖fd指针实现利用 3.任意地址free实现利用(House of Spirit) 1.关于fastbin 我们一般熟悉的堆都是双链表的chunk,但是对于大小为(16 Bytes~ 8

linux 下链接无线网络

无线网卡配置此页由Linux Wiki用户Chenxing于2008年11月27日 (星期四) 09:28的最后更改. 在1233456的工作基础上.本文介绍在Linux命令行界面中手动配置无线网卡的方法.目前流行的多数发行版都支持用图形界面的network-manager方便地进行配置,而无 需使用本文所介绍的原始方法. 下面介绍使用iwconfig和ifconfig等命令在命令行状态下配置无线网络.前题是无线网卡驱动已经正确安装,并被系统正确识别. 大体思路工作的大体思路如下: 用iwcon

linux下网卡问题小结

Q:备份之后在恢复系统,网卡编号变为eth1而不是eth0 A:修改udev规则文件,删除 /etc/udev/rule.d 目录下的70-persistent-net.rules 文件,然后重新启动 对于一些特殊的应用,例如U盘linux系统,删除该文件之后可以在目录下建立一个同名的文件夹 mkdir 70-persistent-net.rules,这样每次启动之后都不会再生成一个udev规则文件了. Q:单网卡设置多个IP地址 A:需要再在/etc/sysconfig/network-scr

linux下 链接 sqlserver数据库 驱动的安装

1.必需安装freetds 安装pdo_dblib扩展首先需要安装freetds. freeTDS的最新稳定版是0.91,这个可以在官网上下载http://www.freetds.org/ ,也可以在http://download.csdn.net/detail/DLUTXIE/3663528下载 下载freetds wget  ftp://ftp.freetds.org/pub/freetds/stable/freetds-stable.tgz tar zxf freetds-stable.t

Linux下mysql基本操作小结

shell> mysql -uroot -p       //以root用户连接mysql,默认密码为空 注意:mysql的大部分命令都需以";"(分号)结束:对大小写不敏感! mysql> show databases;    //显示数据库列表mysql> use 数据库名          //选中指定的数据库mysql> show tables;           //显示选中数据库中的数据表列表mysql> select * from 表名;