buildroot external-toolchain的一次踩坑经历

 buildroot external-toolchain的一次踩坑经历

## 背景介绍

一次使用buildroot进行交叉编译,toolchain选择如下:

  •  External toolchain
  •  Custom toolchain
  •  Pre-installed toolchain
  •  Toolchain Path:/mnt/xxxo/swgcc530-sw6-cross
  •  Toochain prefix : sw_64sw6-sunway-linux-gnu

buildroot会把指定路径下的交叉编译工具拷贝到buildroot的output/host目录下。配置完成后开始编译,编译到某个软件时报错:

```
sw_64sw6-sunway-linux-gnu-g++:error trying to exec 'cc1plus' :execvp: No such file or directory
```


显而易见报错说的是没有命令cc1plus。在buildroot的output/host目录下搜索,果然没有cc1plus。有点奇怪,难道官方提供的交叉编译工具没有cc1plus?于是又在/mnt/xxx/swgcc530-sw6-cross路径下搜索cc1plus,结果搜索到了。难道是拷贝出了问题?于是开始进行验证。

## 问题验证

拷贝一份buildoort,进入新的buildroot目录,执行 *make clean && make* ,重新编译。当跑到“ >>> toolchain-external-custom Copying external toolchain sysroot to staging...”时,发现有如下报错:

```
rsync: send_files failed to open "/usr/sw/swgcc530-sw6-cross/usr/libexec/gcc/sw_64sw6-sunway-linux-gnu/5.3.0/cc1plus" : Permission denied
```


我的工具链路径在/mnt/xxx/swgcc530-sw6-cross,buildroot应该去拷贝我指定路径下的文件,为什么会去拷贝“/usr/sw/swgcc530-sw6-cross”下的文件呢?因为文件/usr/sw/swgcc530-sw6-cross/usr/libexec/gcc/sw_64sw6-sunway-linux-gnu/5.3.0/cc1plus 的所有者是root,所以我去编译时会报Permission denied错。

## 调试

首先,查看buildroot中拷贝交叉工具的相关代码。经查询,拷贝工具的代码位于文件:toolchain/toolchain-external/pkg-toolchain-external.mk

define TOOLCHAIN_EXTERNAL_INSTALL_SYSROOT_LIBS
        $(Q)SYSROOT_DIR="$(call toolchain_find_sysroot,$(TOOLCHAIN_EXTERNAL_CC))" ; \
        ARCH_SYSROOT_DIR="$(call toolchain_find_sysroot_test,$(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS))" ; \
        ARCH_LIB_DIR="$(call toolchain_find_libdir,$(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS))" ; \
        SUPPORT_LIB_DIR="" ; \
        echo "toolchain external cc : $(TOOLCHAIN_EXTERNAL_CC)" ; \
        echo "arch sysroot dir: $${ARCH_SYSROOT_DIR}" ; \
        if test `find $${ARCH_SYSROOT_DIR} -name 'libstdc++.a' | wc -l` -eq 0 ; then \
                LIBSTDCPP_A_LOCATION=$$(LANG=C $(TOOLCHAIN_EXTERNAL_CC) $(TOOLCHAIN_EXTERNAL_CFLAGS) -print-file-name=libstdc++.a) ; \
                if [ -e "$${LIBSTDCPP_A_LOCATION}" ]; then \
                        SUPPORT_LIB_DIR=`readlink -f $${LIBSTDCPP_A_LOCATION} | sed -r -e 's:libstdc\+\+\.a::'` ; \
                fi ; \
        fi ; \
        if [ "$${SYSROOT_DIR}" == "$${ARCH_SYSROOT_DIR}" ] ; then \
                ARCH_SUBDIR="" ; \
        elif [ "`dirname $${ARCH_SYSROOT_DIR}`" = "`dirname $${SYSROOT_DIR}`" ] ; then \
                SYSROOT_DIR_DIRNAME=`dirname $${SYSROOT_DIR}`/ ; \
                ARCH_SUBDIR=`echo $${ARCH_SYSROOT_DIR} | sed -r -e "s:^$${SYSROOT_DIR_DIRNAME}(.*)/$$:\1:"` ; \
        else \
                ARCH_SUBDIR=`echo $${ARCH_SYSROOT_DIR} | sed -r -e "s:^$${SYSROOT_DIR}(.*)/$$:\1:"` ; \
        fi ; \
        $(call MESSAGE,"Copying external toolchain sysroot to staging...") ; \
        $(call copy_toolchain_sysroot,$${SYSROOT_DIR},$${ARCH_SYSROOT_DIR},$${ARCH_SUBDIR},$${ARCH_LIB_DIR},$${SUPPORT_LIB_DIR})
endef


从代码可以看出,首先通过toolchain_find_sysroot获取交叉编译工具的路径,然后通过一些内部处理获取不同目录的路径,最后将四个路径作为参数传入函数copy_toolchain_sysroot,由函数copy_toolchain_sysroot执行拷贝操作。

经查询,函数copy_toolchain_sysroot位于文件 toolchain/helpers.mk。

```
copy_toolchain_sysroot = \
        SYSROOT_DIR="$(strip $1)"; \
        ARCH_SYSROOT_DIR="$(strip $2)"; \
        ARCH_SUBDIR="$(strip $3)"; \
        ARCH_LIB_DIR="$(strip $4)" ; \
        SUPPORT_LIB_DIR="$(strip $5)" ; \
        for i in etc $${ARCH_LIB_DIR} sbin usr usr/$${ARCH_LIB_DIR}; do \
                if [ ! -d $${ARCH_SYSROOT_DIR}/$$i ] ; then \
                        continue ; \
                fi ; \
                if [ "$$i" = "usr" ]; then \
                        rsync -au --chmod=u=rwX,go=rX --exclude 'locale/' \
                                --include '/libexec*/' --exclude '/lib*/' \
                                $${ARCH_SYSROOT_DIR}/$$i/ $(STAGING_DIR)/$$i/ ; \
                else \
                        rsync -au --chmod=u=rwX,go=rX --exclude 'locale/' \
                                $${ARCH_SYSROOT_DIR}/$$i/ $(STAGING_DIR)/$$i/ ; \
                fi ; \
        done ; \
        ........ ##后面的代码没有贴
```


从代码可以看出,cc1plus位于路径/xxx/usr/libexec 下,rsync将路径“ARCH_SYSROOT_DIR” 指定目录下的文件拷贝至路径“STAGING_DIR”相同的目录下。路径“ARCH_SYSROOT_DIR”是传入的第二个参数,路径"STAGING_DIR"通过文件package/Makefile.in可知为:

```
STAGING_SUBDIR = $(GNU_TARGET_NAME)/sysroot
STAGING_DIR    = $(HOST_DIR)/$(STAGING_SUBDIR)
```


即output/host/sw_64sw6-buildroot-linux-gnu/sysroot. 
这时回到文件 toolchain/toolchain-external/pkg-toolchain-external.mk,发现第二个参数的路径为:

```
ARCH_SYSROOT_DIR="$(call toolchain_find_sysroot,$(TOOLCHAIN_EXTERNAL_CC)
```


该变量是将参数"TOOLCHAIN_EXTERNAL_CC"传入函数toolchain_find_sysroot,由函数toolchain_find_sysroot去获取toolchain的绝对路径。TOOLCHAIN_EXTERNAL_CC 为指定路径的external-toolchain下的gcc。

函数toolchain_find_sysroot位于相同文件下:

```
define toolchain_find_sysroot
$$(printf $(call toolchain_find_libc_a,$(1)) | sed -r -e 's:(usr/)?lib(32|64)?([^/]*)?/([^/]*/)?libc\.a::')
endef

define toolchain_find_libdir
$$(printf $(call toolchain_find_libc_a,$(1)) | sed -r -e 's:.*/(usr/)?(lib(32|64)?([^/]*)?(/[^/]*)?)/libc.a:\2:')
endef

# Returns the location of the libc.a file for the given compiler + flags
define toolchain_find_libc_a
$$(readlink -f $$(LANG=C $(1) -print-file-name=libc.a))
endef

```


看代码可知,路径的获取方式为:
1. 首先获取指定gcc连接时用到的库libc.a的绝对路径;
2. 获取该库指向的真实路径;
3. 通过sed过滤该路径中的"/usr/lib(32|64)/libc.a"字符,获取工具链的一级路径。

找到了路径的获取方式,手动执行命令"/mnt/xxx/swgcc530-sw6-cross/bin/sw_64sw6-sunway-linux-gnu-gcc -print-file-name=libc.a",发现输出如下:"/usr/sw/swgcc530-sw6-cross/usr/lib/libc.a" .看来找到原因了,竟然是sw-gcc的锅。sw-gcc 用到的库的路径竟然是/usr/sw/swgcc530-sw6-cross/,而不是sw-gcc所在的路径。

## 总结


在buildroot使用external-toolchain并指定toolchain的路径时,首先执行下xx-gcc -print-file-name=library,查看下gcc所查找的路径,确定和预想的路径是否一致,如果不一致,就需要改变toolchain的路径。

 


 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值