使用chroot搭建Barrelfish应用程序的编译环境
来源:互联网 发布:四柱汉诺塔 python 编辑:程序博客网 时间:2024/06/05 14:48
原文地址
背景
Barrelfish是微软开发的一个开源操作系统。为了研究该系统目前基础设施的完善程度,需要移植一些Linux下的用户空间工具。本文介绍了使用chroot来搭建cross compile环境的过程。
方法比较
为了编译Barrelfish平台上的应用,有两种方法。
使用Hakefile
模仿Barrelfish的其他系统组件,把应用的所有源文件和库依赖都写在Hakefile中,利用Barrelfish的构建系统Hake来生成编译命令。
- 优点
Hake会自动添加必要的编译选项,如果每个C文件都可以编译通过,只要Hakefile中的库依赖填写正确,那么链接过程基本不会出错。
另外,当库的源代码发生变化后,执行make命令就可以自动重新构建应用。
- 缺点
一些较大的工具源码文件比较多,依赖关系错综复杂,有的还需要通过宏定义来对功能进行定制。只有搞清楚所有依赖和需要的宏定义才可以写出正确的Hakefile。
在configure过程中提供所有的编译选项
autoconf是linux下应用的常用构建方式,这类应用编译时分为configure和make两个步骤。在configure步骤时,在CFLAGS环境变量中加入-nostdlib和-nostdinc等参数来定义头文件和库文件的搜索位置,从而实现在make时只使用Barrelfish的头文件和库。
- 优点
不用分析源码间的依赖关系,使用configure可以自动分析系统内可用的库函数和头文件,并生成正确的config.h。一般来说configure步骤通过之后,make步骤是很容易通过的。如果缺少必要的库函数或者头文件,那么configure步骤就会失败并有提示。
- 缺点
与宿主系统的环境混合在一起,
若应用中掺杂了一些自定义的编译步骤,不仅configure步骤有可能无法正确识别环境,生成错误的config.h,也有可能会导致目标文件中链接到宿主系统的代码,使得程序无法再Barrelfish中正确运行。
使用chroot构建编译环境
使用chroot可以切换到一个空的根目录,根目录中的所有文件都是可控的,因此,编译时一定不会被宿主系统污染,也可以通过设置环境变量使得gcc在编译所有程序时,都使用Barrelfish的库和头文件。消除了第二种方法的缺点。
步骤
假设新的根目录位于/my/root目录中。为了方便说明,把该目录导出到环境变量中。
export root=/my/root
挂载必要的文件系统
命令如下mkdir -p $root/sys $root/proc $root/devsudo mount --bind /sys $root/syssudo mount --bind /sys $root/procsudo mount --bind /sys $root/dev
复制必要的程序
此时该根目录中没有任何可用的程序,如果直接使用chroot命令进入目录会有如下错误。> sudo chroot /my/root /bin/bashchroot: failed to run command ‘/bin/bash’: No such file or directory
即使把/bin/bash复制到
/my/myroot/bin
中,依然会有该提示。不过注意,虽然提示相同,但是产生的原因却不同,前者是/bin/bash文件不存在,后者是bash运行所需要的动态链接库文件不存在。因此还需要复制运行时需要的动态链接库。> cp /bin/bash /my/root/bash> ldd /bin/bash linux-vdso.so.1 (0x00007ffd4d7cd000) #对该项的说明见https://en.wikipedia.org/wiki/VDSO libreadline.so.7 => /usr/lib/libreadline.so.7 (0x00007f8d2bbe9000) libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f8d2b9e5000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f8d2b640000) libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f8d2b3d3000) /lib64/ld-linux-x86-64.so.2 (0x00007f8d2be37000)> cp /usr/lib/libreadline.so.7 $root/usr/lib/libreadline.so.7> cp /usr/lib/libdl.so.2 $root/usr/lib/libdl.so.2> cp ... $root/...
依赖复制完后,再次使用chroot命令,就可以成功进入了。但是此时并有任何其他的工具,诸如make,ls,gcc等命令都无法使用,还需使用上面的方法把这些命令复制到
$root
中才可以。
此外,注意复制正确的gcc平台版本,arm,x86等平台是有不同的gcc相对应。如arm版gcc一般名为arm-linux-eabi-gcc。
* 需要注意的是,gcc在运行时还会依赖/usr/lib/gcc/[x86_64, x86, arm]-linux-gnu/目录下的文件,否则在编译c文件时,会提示cc1命令未找到。*复制Barrelfish的头文件和库
假设宿主机上Barrelfish位于$barrelfish
中,chroot后位于/bar(宿主机的$root/bar)
中,那么可以使用如下的命令进行复制。
* 假设编译的是x86_64版本,编译的目录位于$barrelfish/buildx86_64
中 *
以下目录需要被复制# 头文件cp $barrelfish/include $root/bar/. -ruLcp $barrelfish/lib/newlib/newlib/libc/include $root/bar/lib/newlib/newlib/libc -ruLcp $barrelfish/lib/lwip/src/include/ipv4 $root/bar/lib/lwip/src/include -ruLcp $barrelfish/lib/lwip/src/include $root/bar/lib/lwip/src -ruL# 库文件cp $barrelfish/buildx86_64/x86_64/include $root/bar/buildx86_64/x86_64 -ruLcp $barrelfish/buildx86_64/x86_64/lib $root/bar/buildx86_64/x86_64 -ruLcp $barrelfish/buildx86_64/x86_64/errors $root/bar/buildx86_64/x86_64 -ruLcp $barrelfish/buildx86_64/x86_64/usr/drivers/megaraid $root/bar/buildx86_64/x86_64/usr/drivers -ruL
配置chroot后的环境变量
为了让新环境的gcc能找到正确的头文件和库,如libc等,需要设置如下环境变量。# For conveniencebarroot=/barbuild=$barroot/buildx86_64plat=x86_64# ----------------------------------# # -----影响GCC的环境变量-------------# 影响GCC的头文件搜索路径,该环境变量定义的路径优先级 < -I定义的路径 < 默认搜索路径。好处是任何时候调用GCC都起作用,缺点是优先级太低。export C_INCLUDE_PATH="${barroot}/include:${barroot}/include/arch/x86_64:${barroot}/lib/newlib/newlib/libc/include:${barroot}/include/c:${barroot}/include/target/x86_64:${barroot}/lib/lwip/src/include/ipv4:${barroot}/lib/lwip/src/include:${build}/${plat}/include"# 影响库文件搜索路径export LIBRARY_PATH="${build}/${plat}/lib ${build}/${plat}/errors"# ----------------------------------## -----影响configure的环境变量--------export CFLAGS="-std=c99 -static -U__STRICT_ANSI__ -Wstrict-prototypes -Wold-style-definition \ -Wmissing-prototypes -fno-omit-frame-pointer -fno-builtin -nostdinc -nostdlib -U__linux__ \ -Ulinux -Wall -Wshadow -Wmissing-declarations -Wmissing-field-initializers -Wtype-limits \ -Wredundant-decls -m64 -mno-red-zone -fPIE -fno-stack-protector -Wno-unused-but-set-variable \ -Wno-packed-bitfield-compat -Wno-frame-address -D__x86__ -DBARRELFISH -DBF_BINARY_PREFIX=\"\" \ -D_WANT_IO_C99_FORMATS -DCONFIG_LAZY_THC -DCONFIG_SVM -DUSE_KALUGA_DVM -DCONFIG_INTERCONNECT_DRIVER_LMP \ -DCONFIG_INTERCONNECT_DRIVER_UMP -DCONFIG_INTERCONNECT_DRIVER_MULTIHOP \ -DCONFIG_INTERCONNECT_DRIVER_LOCAL -DCONFIG_FLOUNDER_BACKEND_LMP \ -DCONFIG_FLOUNDER_BACKEND_UMP -DCONFIG_FLOUNDER_BACKEND_MULTIHOP \ -DCONFIG_FLOUNDER_BACKEND_LOCAL -Wpointer-arith -Wuninitialized \ -Wsign-compare -Wformat-security -Wno-pointer-sign -Wno-unused-result \ -fno-strict-aliasing -D_FORTIFY_SOURCE=2 \ -I${barroot}/include -I${barroot}/include/arch/x86_64 \ -I${barroot}/lib/newlib/newlib/libc/include -I${barroot}/include/c -I${barroot}/include/target/x86_64 \ -I${barroot}/lib/lwip/src/include/ipv4 -I${barroot}/lib/lwip/src/include -I${build}/${plat}/include"# 还有个环境变量名叫LDFLAGS,该变量在gcc调用命令中的展开位置位于输入文件之前,会导致undefined references错误。export LIBS="-Wl,-z,max-page-size=0x1000 -Wl,--build-id=none ${build}/${plat}/lib/crt0.o \ ${build}/${plat}/lib/crtbegin.o ${build}/${plat}/lib/libssh.a \ ${build}/${plat}/lib/libopenbsdcompat.a \ ${build}/${plat}/lib/libzlib.a ${build}/${plat}/lib/libposixcompat.a \ ${build}/${plat}/lib/libterm_server.a ${build}/${plat}/lib/libvfs.a \ ${build}/${plat}/lib/libahci.a ${build}/${plat}/lib/libmegaraid.a \ ${build}/${plat}/lib/libnfs.a ${build}/${plat}/lib/liblwip.a \ ${build}/${plat}/lib/libnet_if_raw.a ${build}/${plat}/lib/libtimer.a \ ${build}/${plat}/lib/libhashtable.a ${build}/${plat}/lib/libbarrelfish.a \ ${build}/${plat}/lib/libterm_client.a ${build}/${plat}/lib/liboctopus_parser.a \ ${build}/${plat}/errors/errno.o ${build}/${plat}/lib/libnewlib.a \ ${build}/${plat}/lib/libcompiler-rt.a ${build}/${plat}/lib/crtend.o \ ${build}/${plat}/lib/libcollections.a" # ------------------------------------# # 环境变量展开位置# gcc ${CFLAGS} ${程序定义的flags} ${LDFLAGS, 一系列-l命令} ${程序指定的库} -o <output> <inputs...> ${LIBS}
把以上脚本放置在
$root/env.sh
中,每次chroot后,都使用source /env.sh
命令引入。也可在.bashrc文件中加入source命令,启动时自动引入环境变量。
编译程序
本章以编译grep命令为例。
复制文件所用的自动化脚本来自BarrelfishTools仓库的cpbin.sh文件。
➜ barrelfish git:(master) ✗ lsusr lib hake ....➜ barrelfish git:(master) ✗ pwd/home/sunsijie/image/barrelfish➜ barrelfish git:(master) ✗ ls myrootbar bin dev sys ....➜ barrelfish git:(master) ✗ cd myroot➜ myroot git:(master) ✗ wget http://ftp.gnu.org/gnu/grep/grep-2.5.4.tar.bz2➜ myroot git:(master) ✗ tar xf grep-2.5.4.tar.bz2➜ myroot git:(master) ✗ mv grep-2.5.4 grep➜ myroot git:(master) ✗ cd ..➜ barrelfish git:(master) ✗ ./cpbin.sh........many outputsarch-sunsijie cd greparch-sunsijie mkdir buildarch-sunsijie cd buildarch-sunsijie ../configure --host=x86_64 --disable-nls --disable-perl-regexp........many outputs
此时configure步骤应该是成功的,但是编译时还是会有些问题,这是因为由于newlib实现不同于glibc,导致configure时未能正确配置一些宏定义。
- 第一个错误如下。
../../lib/strtoumax.c:55:1: error: redefinition of 'strtoumax' strtoumax (char const *ptr, char **endptr, int base) ^~~~~~~~~ In file included from ../../lib/strtoumax.c:25:0: /bar/lib/newlib/newlib/libc/include/inttypes.h:322:25: note: previous definition of 'strtoumax' was here static inline uintmax_t strtoumax(const char *s, char **endp, int base)
解决方法,把$root/grep/lib/strtoumax.c
文件中引用的头文件inttypes.h删除。
- 第二个错误如下。
bar/buildx86_64/x86_64/lib/libcollections.a ../lib/libgreputils.a(regex.o): In function `regerror': regex.c:(.text+0xa2e4): undefined reference to `__mempcpy'
解决方法,在lib/getopt.c和lib/regex.c文件中的合适位置添加__mempcpy
的实现。代码如下。
static void* __mempcpy(void* dst, void* src, size_t n) { return (void*)((char*)memcpy(dst, src, n) + n); }
- 第三个错误
第三个错误在于没有初始化vfs,不会导致编译错误,但是会导致运行时错误。需要在$root/grep/src/grep.c:1827行
插入代码vfs_init();
之后,make通过。
使用命令
➜ barrelfish git:(master) ✗ cp myroot/grep/build/src/grep buildx86_64/x86_64/sbin/➜ barrelfish git:(master) ✗ echo "module /x86_64/sbin/grep" >> buildx86_64/platforms/x86/menu.lst.x86_64
即可在Barrelfish启动时把grep加载到ramfs中。
命令运行成功的截图如下。
- 使用chroot搭建Barrelfish应用程序的编译环境
- 搭建ubuntu 9.10的chroot开发环境
- /chroot环境搭建
- 使用chroot,做最后的编译
- ubuntu下使用qemu-arm-static进入chroot编译环境
- 制作ARM chroot 编译环境
- bind的chroot使用
- 关于如何使用 chroot, 为程序设置新的执行环境chroot & schroot etc.(文件系统虚拟化)
- 架设CHROOT环境下的安全DNS
- Chroot环境下的MySQL配置
- cygwin的安装使用以及交叉编译环境的搭建
- Linux下Luabind编译和使用环境的搭建
- 如何使用efi toolkit搭建编译efi app的环境
- 交叉编译和交叉调试环境的搭建及使用
- 使用slitaz搭建小巧的交叉编译环境
- 关于libevent的环境搭建和编译使用问题
- linux下的Gradle编译环境搭建与使用
- 使用chroot
- Result API
- UML类图与类的关系详解
- 选择排序
- SpringMVC源码(八)HandlerInterceptor拦截器
- js判断undefined类型,undefined,null, 的区别详细解析
- 使用chroot搭建Barrelfish应用程序的编译环境
- androidstudio之延时跳转
- HDU 1846 Brave Game 【巴什博奕】
- Trafodion Troubleshooting-OutOfOrderScannerNextException
- 【STM32】STM32 MCU系列介绍
- android开发过程中,测试apk进程对设备内存占用的一般方法
- jquery 动态添加的元素,用on事件
- 对arm体系架构和stm32的理解
- JAVA 基础