apt源arm gcc交叉编译器注意事项

2017-09-14 10:37:31来源:https://tisyang.github.io/2017/09/notes-about-using-apt-pack作者:碎片人点击

分享


做嵌入式 Linux 开发时候都需要使用交叉编译工具,这些一般是方案厂商提供,但我们通常也可以使用那些打包好的通用交叉编译工具,比如 Debian 上 apt 也有打包好的 arm 交叉编译工具:gcc-arm-linux-gnueabi
和gcc-arm-linux-gnueabihf
,对应 c++ 版本以 g++ 开头,这两类主要区别在于 CPU 对于浮点的处理上,涉及到armel
和armhf
架构的区别,详情参照这里
,你只需要选择对应开发板的架构工具即可。


由于是 Debian 自己维护更新的包,上述的两个交叉编译工具通常都会更新比较频繁,会支持最新的标准和特性,但是我们的开发板上系统通常都不是最新的,所以在使用时需要注意,否则会出现编译后的程序无法在开发板上运行。



最近在将mruby
应用到嵌入式环境时就遇到这个问题。


问题和溯因


将静态链接了mruby
库的测试程序 mirb 放入嵌入式环境上运行时,提示


./mirb: /lib/libc.so.6: version `GLIBC_2.16' not found (required by ./mirb)


嵌入式环境没有 2.16 版本以上的 glibc 库,但是理论上测试程序不需要这么高版本的 glibc 库。在嵌入式命令行上用ldd
(有些嵌入式环境可能没有附带这个工具)查看一下可执行文件信息:


#ldd -v mirb
./mirb: /lib/libc.so.6: version `GLIBC_2.16' not found (required by ./mirb)
libm.so.6 => /lib/libm.so.6 (0x401ed000)
libc.so.6 => /lib/libc.so.6 (0x40293000)
/lib/ld-linux.so.3 (0x401c4000)
Version information:
./mirb:
libm.so.6 (GLIBC_2.4) => /lib/libm.so.6
libc.so.6 (GLIBC_2.7) => /lib/libc.so.6
libc.so.6 (GLIBC_2.16) => not found
libc.so.6 (GLIBC_2.4) => /lib/libc.so.6
/lib/libm.so.6:
ld-linux.so.3 (GLIBC_PRIVATE) => /lib/ld-linux.so.3
libc.so.6 (GLIBC_2.4) => /lib/libc.so.6
/lib/libc.so.6:
ld-linux.so.3 (GLIBC_2.4) => /lib/ld-linux.so.3
ld-linux.so.3 (GLIBC_PRIVATE) => /lib/ld-linux.so.3

可执行程序 mirb 的确引用 2.16 版本的 glibc 库,那就继续查一下引用了 2.16 版本 glibc 库的哪些符号。



在开发主机(不需要在嵌入式主机中)上可以使用 objdump 工具查看可执行程序的符号表(参数-t
):


$ objdump -t mirb | grep 2.16
00000000 F *UND*
00000000timespec_get@@GLIBC_2.16


可以看出是timespec_get
这个函数符号需要 2.16 版本的 glibc 库,那么就得在代码中查一下哪个地方调用了这个函数。



在这里
可以看出mruby
源码的time.c
文件中使用了timespec_get
函数:


tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
#if defined(TIME_UTC)
{
struct timespec ts;
if (timespec_get(&ts, TIME_UTC) == 0) {
mrb_free(mrb, tm);
mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons");
}
tm->sec = ts.tv_sec;
tm->usec = ts.tv_nsec / 1000;
}
#elif defined(NO_GETTIMEOFDAY)


宏定义TIME_UTC
控制着代码是否调用timespec_get
函数。



通过搜索
了解到,TIME_UTC
和timespec_get
都是 C11 标准里定义的。由于在编译mruby
时没有指定编译参数,交叉编译工具使用了默认参数导致 C11 标准也被支持,mruby
库也就使用了最新的 C11 标准,引用了新函数timespec_get
,产生了 glibc 2.16 版本的依赖。


解决方法


在知晓原因后,解决方法就简单了。就是在交叉编译mruby
库时,去指定编译标准(c标准),修改mruby
的编译配置文件build_config.rb


conf.cc do |cc|
cc.command = "arm-linux-gnueabi-gcc"
cc.flags << "-std=gnu99"
end


将编译 c 标准指定为 gnu99(-std=gnu99
),这里也可以使用 c99 标准(-std=c99
)。


然后重新编译测试程序,放到嵌入式环境上运行,OK。


结语

使用编译器尤其是交叉编译器时,最好要指定编译参数,确定编译标准,否则目标平台可能不支持,导致程序无法运行。在向第三方提供开发库而不是源码的情况下, 需要特别注意,尽量使用统一的编译参数标准,推荐 c99 或者 gnu99。



在遇到类似/lib/libc.so.6: version GLIBC_X.XX not found
问题时,可以借助ldd
和objdump
工具来确定依赖的符号源,寻找解决方法。


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台