构建自己的arm-linux toolchain:
生成工具链目录结构:
/usr/armtools
`----arm-linux 目标平台相关内容
| `----bin gcc内部使用的编译/连接工具
| `----lib gcc的内部库/c++ 库
| | `----ldscripts ld的连接脚本
| `----target-root 目标平台根目录
| `----etc 目标平台配置(ld.so.cache)
| `----lib 目标平台glibc库
| `----usr
| `----include glibc头文档
`----bin + arm-linux-gcc,arm-linux-ld,...
`----include
`----c++ c++ 标准头文档
`----lib
| `----gcc gcc内部库核心cc1,collect2
| `----...
`----libexec
| `----gcc gcc内部使用的辅助工具
| `----...
`----man man for gcc/glib/binutils
`----info info for gcc/glib/binutils
`----share Locale等
该目录结构由binutils, gcc, glibc的目录复合而成,可变性很差, 稍有差错就可能导致工具链无法使用。 目录的结构由以下几个配置参数决定:
--prefix=chain/root 工具链根目录, 缺省为/usr/local
虽然gcc/binutils支持multi-lib方式,能够使用/usr/local作为工具链根目录而不和本地gcc发生冲突, 但glibc并不支持这一特性。因此一般使用prefix把根目录指定到某一特定目录,比如/usr/armtools。
但对于glibc,此目录同时也是glibc的库文档工作的时候(在target上运行应用程式的时候)寻找文档所用路径,因此应该配置为缺省的/usr,而使用install_root来指定安装路径。
--with-sysroot 目标板根目录。gcc将由此开始按照标准linux目录结构寻找编译所需的头文档和库。binutils现在对此参数支持还不是很好,假如不配合make时使用LIB_PATH,ld会无法为so文档找到其所需的其他so文档。
LIB_PATH 辅助指定库所在路径
install_root 指定glibc安装路径。倘若不指定此参数,prefix=/usr的情况make install会导致系统本地glibc库被覆盖。
1 Binutils:
GNU二进制文档处理工具,核心工具为ld和as。构造arm-linux-gcc时需要用到arm-linux-ld
和arm-linux-as来生成g++的arm-elf库,构造glibc时同样需要用到。
binutils是toolchain的基础,假如配置不正确,会给后来的编译带来诸多问题。
./configure --prefix=/usr/armtools --target=arm-linux --with-sysroot=/usr/armtools/arm-linux/target-root
make LIB_PATH=/usr/armtools/arm-linux/target-root/lib tooldir=/usr/armtools
make install
/usr/armtools
|----arm-linux 供GCC/Binutils内部使用
| |----bin 内部命令 ld,as...
| `----lib 内部库
| `----ldscripts ld的连接脚本。假如用到的so库中使用了其他so库,则搜索路径在这里指定
|----bin 供用户使用的命令 arm-linux-*
|----info info
|----lib 用户使用的库
`----man man
`----man1 binutils manual
make需要autoconf, automake, m4, flex, yacc, gettext支持。
假如make时出现:/bin/bash: no command not found一类的错误时,需要更新gettext,或configure时加上 --disable-nls 关闭本地化语言支持。
arm-linux-ld将会/usr/armtools/arm-linux/lib中寻找连接时使用的.so文档。假如很难找到,则在glibc编译完成后,gcc无法编译动态链接的文档,提示:
warning: ld-linux.so.2, needed by /libc.so.6, not found
唯有同时指定--with-sysroot 和 LIB_PATH可解决此问题。
binutils2.15 同 gcc3.4.3 + glibc2.3.2面向ARM时冲突。该冲突尚未解决(2005.3.1)
2 Kernel Source
Linux 内核源代码的头文档是编译glibc必需的。 获取Linux初始源代码并针对架构打上补丁,以Xscale为例:
获取:
linux-2.4.19.tar.gz 初始源代码
patch-2.4.19-rmk7.bz2 针对ARM的补丁
diff-2.4.19-rmk7-pxa2.gz 针对Xscale的补丁
打补丁:
tar -xzf linux-2.4.19.tar.gz
cd linux-2.4.19/
bzcat ../patch-2.4.19-rmk7.bz2 | patch -p1
zcat ../diff-2.4.19-rmk7-pxa2.gz | patch -p1
配置内核并配置头文档依赖:
make ARCH=arm menuconfig
选择Processor Type 为 PXA210/250,
选择适当的研发平台
保存退出
make dep
复制header:
mkdir /usr/armtools/arm-linux/usr
mkdir /usr/armtools/arm-linux/usr/include
cp -rD linux-2.4.19/include/arm-asm/ /usr/armtools/arm-linux/target-root/usr/include/
cp -rD linux-2.4.19/include/linux/ /usr/armtools/arm-linux/target-root/usr/include/
在/toolschain/rootdir/arm-linux下建立了include目录
make dep 会需要arm-linux-gcc存在...
3 GCC-Core
GCC本身的编译分为两个部分. 首先是建立运行在Host平台上的一系列交叉编译工具arm-linux-gcc/g++/java..., 另一个是编译特定语言写成的应用程式时所需要的静态库(.a)和动态库(.so)文档. 例如c++的libstdc++.*和java的libjava.*. c本身的库文档glibc(libc.*)需要单独编译。
由于g++和java等编译器使用glibc,因此,在完全没有编译环境的情况下,只能够先编译gcc-core(gcc),然后利用生成的gcc编译glibc, 最后生成其他语言的编译器。
获取:
gcc-core-3.4.3.tar.bz2 GNU C Core &Compiler
编译时按照编译需要,最好将源代码和生成的OBJ分开放置:
tar -xjf gcc-core-3.4.3.tar.bz2
mkdir gccobj
cd gccobj
由于现在没有glibc, 需要修改编译条件,使编译过程中不使用glibc:
vi gcc-3.4.3/gcc/config/arm/t-linux
将
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC
改为
TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
配置并编译:
export PATH=$/toolchain/rootdir/bin:$PATH
../gcc-3.4.3/configure --prefix=/usr/armtools --target=arm-linux --with-sysroot=/usr/armtools/arm-linux/target-root --enable-languages=c --disable-threads -disable-shared
make
make install
配置参数说明:
--prefix gcc安装的根目录,缺省为/usr/local
--target 目标平台
--without-headers 不使用头文档。gcc编译的时候会引用目标平台的linux和libc头文档。
指定此选项避免出现"stdio.h: file not found"一类的错误
--enable-languages=c 只生成c编译器
--disable-threads gcc使用线程来提高编译速度,但现在还没有Target的glibc
--disable-shared 生成Target平台的so文档需要glibc,现在还没有
4 Glibc
假如需要编译在target上运行的用户空间程式,则glibc是必需的。
获取:
glibc-2.3.2.tar.gz
glibc-linuxthreads-2.3.2.tar.bz2
配置编译目录:
tar -xzf glibc-2.3.2.tar.gz
cd glibc-2.3.2
tar -xjf ../glibc-linuxthreads-2.3.2.tar.bz2
cd ..
mkdir glibcobj
配置并编译:
cd glibcobj
BUILD_CC=gcc CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux-ranlib ../glibc-2.3.2/configure --build=i386-linux --host=arm-linux --prefix=/usr --enable-add-ons --with-headers=/usr/armtools/arm-linux/target-root/usr/include/
make
make install install_root=/usr/armtools/arm-linux/target-root
修改Glibc为ARM编译的ld脚本bug:
去掉.../target-root/usr/lib中*.so文档中的***BUG.....***一行
*** configure: error: cannot compute sizeof (long double)
假如不指定--build,configure会以为在进行本地编译,从而运行测试程式,导致配置不成功。这应该是glibc2.3.2的bug
*** "crti.S:96: Error: can’t resolve : `_GLOBAL_OFFSET_TABLE_’ {*UND* section} ..."
gcc3.4.x bug, 编译生成 initfini.s时假如采用了-O2参数,则编译结果不正确
@@@csu/Makefile@@@
CFLAGS-initfini.s = -g0 -fPIC -fno-inline-functions
+ -fno-unit-at-a-time
@@@linuxthreads/Makefile@@@
linuxthreads/Makefile:
CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions
+ -fno-unit-at-a-time
*** "sigaction.c:100: error: asm-specifier for variable `_a1’ conflicts with asm clobber lists"
glibc for arm bug
@@@sysdeps/unix/sysv/linux/arm/sysdep.h@@@
asm volatile ("swi %1 @ syscall " #name \
: "=r" (_a1) \
: "i" (SYS_ify(name)) ASM_ARGS_##nr \
- : "a1", "memory"); \
+ : "memory"); \
_sys_result = _a1; \
} \
(int) _sys_result; })
**** sscanf.c:31: warning: conflicting types for built-in function ’sscanf’
glibc bug,
@@@stdio-common/sscanf.c@@@
int
- sscanf(s,format)
- const char *s;
- const char *format;
+ sscanf(const char *s,const char *format,...)
{
**** : Assembler messages:> :2: Error: garbage following instruction -- >
`ldr lr,[sp],#4 ldr ip,=__libc_multiple_threads’
编译linuxthreads出现此问题,原因是宏定义不正确
@@@linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h@@@
# define PSEUDO(name, syscall_name, args) \
.section ".text"; \
PSEUDO_PROLOGUE; \
- ENTRY (name) \
+ ENTRY (name); \
SINGLE_THREAD_P_INT; \
bne .Lpseudo_cancel; \
DO_CALL (syscall_name, args);
**** ld:/home/jeff/bglibc/libc.so.lds:114: syntax error
libc.so.lds:
(114) KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
/usr/local/lib/gcc-lib/i386-linux/3.2.2/libgcc.a(unwind-dw2-fde-glibc.o): In
function `size_of_encoded_value’:/home/jeff/gcc-3.2.2/gcc/unwind-pe.h:76:
undefined reference to `abort’
生成libc.so.lds时,编译的警告信息破坏了libc.so.lds的格式。在确认警告无须理会后,修改Makerules吃掉警告:
@@@Makerules:
$(build-shlib-helper) \
-o
[email=$@.new]$@.new[/email]
$(csu-objpfx)abi-note.o -Wl,--verbose \
$(LDLIBS-$(@F:lib%.so=%).so) 2>&1 | \
sed -e ’/^=========/,/^=========/!d;/^=========/d’ \
+ -es/.*undefined\ reference.*// -es/\\/.*In\ function.*// \
-e ’s/^.*\.hash[ ]*:.*$$/ .note.ABI-tag : {
*(.note.ABI-tag) } &/’ \
$(LDSEDCMD-$(@F:lib%.so=%).so) >
[email=$@.lds]$@.lds[/email]
rm -f
[email=$@.new]$@.new[/email]
**** libc.so.6: undefined reference to `mcount_internal’
glibc在arm上的bug,mcount_internal被定义为static函数
@@@glibc-2.3.2/sysdeps/arm/machine-gmon.h@@@
weak_alias (_mcount, mcount)
#endif
-static void mcount_internal (u_long frompc, u_long selfpc);
#define _MCOUNT_DECL(frompc, selfpc) \
-static void mcount_internal (u_long frompc, u_long selfpc)
+void mcount_internal (u_long frompc, u_long selfpc)
5 GCC Shared & g++
在glibc建立好之后,利用glibc重新编译gcc,补充之前限制的特性,并编译g++。应确认toolchain已能够正常编译普通c程式后,才开始进行重编译
配置
mkdir gccobj.full
cd gccobj.full
../gcc-3.4.3/configure --target=arm-linux --prefix=/usr/armtools --with-sysroot=/usr/armtools/arm-linux/target-root --with-local-prefix=/usr/armtools/arm-linux/target-root --disable-nls --enable-threads=posix --enable-lanuages="c,c++" --enable-c99 --enable-long-long
make
make install