赞
踩
一次使用buildroot进行交叉编译,toolchain选择如下:
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的路径。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。