由于链接顺序引起的符号定位未找到问题
最近在将我们的工程切换到CMake工具构建,遇到了一个由于链接顺序引起的问题,当时没看出来原因,被困扰了几个小时,特此记录一下。
编译报错类似下面这样,提示在libsum.a库中sum函数找不到add的定义。
/usr/bin/ld: libsum.a(sum.o): in function `sum':
sum.c:(.text+0x1d): undefined reference to `add'
collect2: error: ld returned 1 exit status
怎么会没找到呢?我明明链接了libadd.a呀,难道库有问题。
通过nm命令查看libadd.a中的符号,如下。
add.o:
0000000000000000 T add
有add啊,但是符号值怎么是全0?没有写实现吗?
于是去看源文件,发现其实是有实现的。
那么问题出在哪里呢?
这时候一个声音响起,“会不会是链接顺序不对?”,真可谓一语惊醒梦中人。
马上把libsum.a和libadd.a的链接顺序对换,问题果然解决了。
(其实,当时没想起来这个原因,也是因为在切换CMake之前,这个链接顺序也能通过编译。很奇怪,还需要再深入看看。)
通过报错,基本就可以看出来了,在libsum.a中使用了libadd.a中的符号,那么链接时需要将libsum.a放前面,libadd.a放后面。
这个是由编译器决定的,对于gcc来说,libsum.a放前面,libadd.a放后面,当找不到libsum.a中的符号时,它会在后面的链接库中继续查找。
大家可以自己试试,这里提供源文件和编译命令。
add.h
#ifndef __ADD_H__
#define __ADD_H__
int add(int a, int b);
#endif
add.c
#include "add.h"
int add(int a, int b) {
return a + b;
}
sum.h
#ifndef __SUM_H__
#define __SUM_H__
int sum(int a, int b);
#endif
sum.c
#include "add.h"
#include "sum.h"
int sum(int a, int b) {
return add(a, b);
}
main.c
#include "sum.h"
#include <stdio.h>
int main()
{
int res = sum(2, 3);
printf("the sum of 2 and 3 = %d\n", res);
return 0;
}
- 首先生成add静态库
gcc -c add.c -o add.o
ar -rc libadd.a add.o
- 然后生成sum静态库
gcc -c sum.c -o sum.o
ar -rc libsum.a sum.o
- 编译main.c(链接顺序不对)
gcc main.c libadd.a libsum.a -o main