首先,对于编译器这东西,我一向认为很高深,当然现在还是这么认为,呵,所以呢,一般都是用别人编译好的现成的编译好版本。可是最近因为要在windows下面编译u-boot的原因,因为找不到合适的arm编译器,故只能自己编译一个了。下面就是整个的编译过程,一步步来吧。
在开始之前,还要说明一点,这里所编译的gnu arm gcc
1.
(1)类型:arm-none-eabi-gcc
(2)版本:Binutils-2.22,Newlib-1.20.0,GCC-4.7.1,GDB-7.4.1,insight-6.8.1
嘿嘿,这个版本的问题,我参考了yagarto
(3)下载所要的源文件:
Binutils-2.22:
官网:http://www.gnu.org/software/binutils/
下载地址:http://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2
Newlib-1.20.0:
官网:http://sourceware.org/newlib/
下载地址:http://nchc.dl.sourceforge.net/project/devkitpro/sources/newlib/newlib-1.20.0.tar.gz
也可以通过CVS来获得:
GCC-4.7.1:
GDB-7.4.1:
官网:http://www.gnu.org/software/gdb/
insight-6.8.1:
官网:http://sourceware.org/insight/
下载地址:ftp://sourceware.org/pub/insight/releases/insight-6.8-1.tar.bz2
也可以通过CVS来获得:
cvs -z9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
[enter "anoncvs" as the password]
cvs -z9 -d :pserver:anoncvs@sourceware.org:/cvs/src co -r gdb_6_8-branch insight
官网不变,下载地址这里只是给出参考,感觉随时会变,那时候就google或百度。
2.
编译之前还要做几件事:
(1)
Cygwin下载请到http://www.cygwin.com/
(2)
首先,建一个用来存入编译好的编译器的目录,建义在cygwin安装目录下建一下opt目录,里面建一个arm-gnu-tools目录,比如我的cygwin是装在:d:\cygwin,那么我就建d:\cygwin\opt\arm-gnu-tools,这样你就可以在cygwin下通过
其次,再建一个目录build-arm-tools,然后在建立build-binutils, build-gcc, build-gdb, build-newlib,
E:\build-arm-tools
│
│
│
│
│
│
│
├─build-binutils
├─build-gcc
├─build-gdb
├─build-insight
├─build-newlib
├─binutils-2.22
├─gcc-4.7.1
├─gdb-7.4.1
├─insight-6.8-1
└─newlib-1.20.0
其中build_arm_tools.bat是我们要进行编译要用到的脚本,主要作用是设置一些环境变量,启动cygwin环境,具体内容如下:
@echo off
set PREFIX=/opt/arm-gnu-tools
set BIN_PATH=/opt/arm-gnu-tools/bin
set CYGWIN_DIR=d:\cygwin
set PATH=%CYGWIN_DIR%\bin;%PATH%
set HOME=e:\build-arm-tools\
(3)
这部分内容的话,我是参考了yagarto, GNUARM, WinARM, devkitARM, SysGcc_ARM等,CodeSourcery和Linaro是基于linux库的,所以无可比性,最后觉得yagarto的参数最好的,然后又在它的基础上加了几个,具体的如下:
--prefix=/opt/arm-gnu-tools
--disable-nls
--disable-threads
--enable-languages=c,c++
--enable-interwork
--with-gcc
--with-gnu-ld
--with-gnu-as
--with-dwarf2
--with-float=soft
--disable-shared
--with-newlib
--enable-multilib
--disable-libssp
--disable-libstdcxx-pch
--disable-libmudflap
--disable-libgomp –v
--with-headers=../newlib-1.20.0/newlib/libc/include
--with-pkgversion='semilog_ARM release 01'
--enable-target-optspace
--with-cpu=cpu
--with-arch=armv7
下面就分别对(我知道的)参数说明一下吧:
--target=arm-none-eabi
--prefix=/opt/arm-gnu-tools
编译好生成的编译器存放的地方,比如,编好了,就会在arm-gnu-tools目录下生成所要编译器。
--disable-nls
这个参数真他妈坑爹,网上找到的说法是“这个参数禁止了国际化”,我怎么看也不明白,结果在gcc reference book
--disable-threads
--enable-languages=c,c++
Gcc的编译的语言只支持c和c++,我看到codeSourcery上面还支持Fortran,额~~~我长见识了。
--enable-interwork
这个是支持thumb和arm代码的相互调用。
--with-gnu-ld
--with-gnu-as
--with-dwarf2
上面四个参数是用来表明显示表明,用gcc编c语言,gnu-as编汇编,gnu-ld链接,调试文件格式是dwarf2的。
--with-float=soft
这个是浮点运算用软件来实现,ARM中有的型号其实有还硬件浮点运逄单元的,因为很多库为了兼容,所以都使用软件实现,这样平台依赖没有那么强,便于移植。
--disable-shared
--with-newlib
使用newlib库,Newlib是一个面向嵌入式系统的C运行库。最初是由Cygnus Solutions收集组装的一个源代码集合,取名为newlib,现在由Red Hat维护。我们用它来作为我们的库,而不是linux的glibc
--enable-multilib
大部分系统上都是默认选项,这表明了针对目标的多种库都会被编译,这里是针对ARM。
--disable-libssp
--disable-libstdcxx-pch
--disable-libmudflap
--disable-libgomp
上面的四个参数,就是用来--enable-multilib中的多种库中去掉这些列出来的,具体提这些库是做什么的,还没有去细究。
--with-headers=../newlib-1.20.0/newlib/libc/include
嘿嘿,这人参数一看就明白了,我就不用多说了。
--with-pkgversion='semilog_ARM release 01'
这个也是的,我把它改成我自己的名字了。哈。
--enable-target-optspace
Specifies that the libraries should be optimized for size instead of speed,这里我们不用,默认是用O2优化。
--with-cpu=cpu
--with-arch=armv7
这个参数要说一下,如果你选了—with-cpu=arm7tdmi,那么会特别针对这个arm7tdmi来优化编译器。下面,你懂的,你也可以优化你想要的。这个参数和
好了准备工作基本上完了,下面来编译了。
1.
双击建好的build_arm_tools.bat,
(1)首先编译
在提示$符下分别输入:
$
$
$
$
这一
就是把/opt/arm-gnu-tools/bin,因为编gcc的时候,要用到里面的第一步已生成的程序,
可以建个快捷方式:
$
注意:以后每一步编译完都执行一次。
主要是我是cygwin下面加入到$PATH下没有效果,所以就用上面的方法了。
(2)第一遍编译gcc-4.7.1
这一次只是加入newlib的头文件,没有任何库文件,因为还没有生成
$
$
$
$
$
(3)编译newlib-1.20.0
现在就用新生成的gcc来编译newlib库
$
$
$
$
这次编译的时候是用新生成的newlib库来完成gcc带库的编译。
$
$
$
$
$
$
$
$
(6)编译
$
$
$
$
不过在编译insight-6.8-1的时候可没有那么顺利啊,有一些错误要进行修改。具体的错误及修改如下:
【1】首先遇到的是
HAVE_NO_SEH=1-DEXCEPTION_DISPOSITION=int -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1
-DHAVE_SYS_STAT_H=1-DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE
_STRINGS_H=1 -DHAVE_INTTYPES_H=1-DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DBUILD_t
cl../../../insight-6.8-1/tcl/win/../generic/tclAlloc.c -o tclAlloc.o
In file included from ../../../insight-6.8-1/tcl/win/../generic/../win/tclWinPort.h:72:0,
from../../../insight-6.8-1/tcl/win/../generic/tclPort.h:22,
from../../../insight-6.8-1/tcl/win/../generic/tclAlloc.c:29:
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../include/w32api/winsock2.h:103:2:
warning: #warning "fd_set andassociated macros have been defined in sys/types.
This may cause runtime problemswith W32 sockets"
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../../include/w32api/winsock2.h:632:32:
error: conflicting typesfor ‘select’
/usr/include/sys/select.h:31:5:note: previous declaration of ‘select’ was here
Makefile:423: recipe for target`tclAlloc.o' failed
make[3]: *** [tclAlloc.o] Error 1
make[3]: Leaving directory`/cygdrive/e/build-gcc/build-insight/tcl/win'
Makefile:15: recipe for target`all' failed
make[2]: *** [all] Error 2
make[2]: Leaving directory`/cygdrive/e/build-gcc/build-insight/tcl'
Makefile:6631: recipe for target`all-tcl' failed
make[1]: *** [all-tcl] Error 2
make[1]: Leaving directory`/cygdrive/e/build-gcc/build-insight'
Makefile:705: recipe for target`all' failed
make: *** [all] Error 2
错误的地方我用红色标出来了,是因为cygwin下的/usr/include/w32api/winsock2.h里面的:
WINSOCK_API_LINKAGE int PASCAL select(intnfds,fd_set*,fd_set*,fd_set*,const struct timeval*);
和/usr/include/sys/select.h里面的:
int select __P ((int __n, fd_set *__readfds, fd_set *__writefds, fd_set *__exceptfds, struct timeval*__timeout));
两个函数冲突,因为select.h下在的定义在系统下,且后面还要用到,故注掉winsock2.h里的select函数即可。
【2】接下来会遇到这个错误
tclWinChan.o:In function `Tcl_MakeFileChannel':
/cygdrive/e/build-gcc/build-insight/tcl/win/../../../insight-6.8-1/tcl/win/tclWinChan.c:1052:undefined reference to `_ESP'
/cygdrive/e/build-gcc/build-insight/tcl/win/../../../insight-6.8-1/tcl/win/tclWinChan.c:1052:undefined reference to `_EBP'
/cygdrive/e/build-gcc/build-insight/tcl/win/../../../insight-6.8-1/tcl/win/tclWinChan.c:1067:undefined reference to `_ESP'
/cygdrive/e/build-gcc/build-insight/tcl/win/../../../insight-6.8-1/tcl/win/tclWinChan.c:1067:undefined reference to `_EBP'
打开tclwinChan.c 对应的 1052代码如下,怎么看也不知道错在什么地方。
__asm__ __volatile__ (
"movl %esp, _ESP" "\n\t"
"movl %ebp, _EBP");
上网找ESP,EBP,突然看到 124行
static void *ESP;
static void *EBP;
用的是static 属性,想想可能是因为内嵌汇编无法引用指针引起的,于是去掉static,结果真是可以了,就是这个原因。然后在网上也找到insight6.8的patch,果然就这样改。Patch的网址:
http://moaningmarmot.free.fr/?p=30
Fix upInsight 6.8 to build up on a x86 host and a modern GCC toolchain
arm-elf-*target debugger on a i686 host
Insight6.8 and GDB need a serious code clean up to build without warnings and errorswith GCC 4.x series.
Theproposed patch is a simple workaround so that Insight 6.8 (and previousreleases) builds OK on a x86 host. Note that would also needs to remove the-Werror option switch when gdb is built, as GCC 4.x emits tons of warnings whenGDB is built.
----------------------------------------------------------------------------------------------
diff -urinsight-6.8/tcl/win/tclWinChan.c insight-6.8.new/tcl/win/tclWinChan.c
---insight-6.8/tcl/win/tclWinChan.c 2006-02-02 21:02:09.000000000 +0100
+++insight-6.8.new/tcl/win/tclWinChan.c 2009-03-1622:07:40.711125000 +0100
@@-122,8 +122,8 @@
};
#ifdef HAVE_NO_SEH
-static void *ESP;
-static void *EBP;
+void *ESP;
+void *EBP;
#endif /* HAVE_NO_SEH */
diff -urinsight-6.8/tcl/win/tclWinDde.c insight-6.8.new/tcl/win/tclWinDde.c
---insight-6.8/tcl/win/tclWinDde.c 2003-01-21 20:40:22.000000000 +0100
+++insight-6.8.new/tcl/win/tclWinDde.c 2009-03-16 22:12:30.414250000 +0100
@@-1175,7 +1175,7 @@
}
case DDE_EVAL: {
objc -= (async + 3);
- ((Tcl_Obj **)objv) += (async + 3);
+ objv =((Tcl_Obj **) objv) + (async + 3);
diff -ur insight-6.8/tcl/win/tclWinReg.cinsight-6.8.new/tcl/win/tclWinReg.c
---insight-6.8/tcl/win/tclWinReg.c 2003-02-07 20:52:00.000000000 +0100
+++insight-6.8.new/tcl/win/tclWinReg.c 2009-03-16 22:16:52.820500000 +0100
@@-747,7 +747,9 @@
Tcl_NewStringObj(Tcl_DStringValue(&buf),
Tcl_DStringLength(&buf)));
if (regWinProcs->useWide) {
- while (*((Tcl_UniChar *)p)++ != 0) {}
+ Tcl_UniChar * wp = (Tcl_UniChar *)p;
+ while (*wp++ != 0) {}
+ p = (char*)wp;
} else {
while (*p++ != '\0') {}
}
---------------------------------------------------------------------------------------------
同样,还有另外两个文件要改tclWinDde.c,tclWinReg.c,把红的改成绿的就可以了。
【3】接下来,又是一个与系统定义冲突的错误
Infile included from ../../../insight-6.8-1/tk/win/../generic/tkPort.h:27:0,
from../../../insight-6.8-1/tk/win/../generic/tkInt.h:27,
from../../../insight-6.8-1/tk/win/../generic/tkConsole.c:19:
../../../insight-6.8-1/tk/win/tkWinPort.h:126:8:error: redefinition of ‘struct timezone’
/usr/include/sys/time.h:22:8:note: originally defined here
Makefile:588:recipe for target `tkConsole.o' failed
/usr/include/sys/timer.h和insight-6.8-1/tk/win/tkWinPort.h里面定义了重复的结构体
struct itimerval {
struct timeval it_interval;
struct timeval it_value;
};
注释掉insight-6.8-1/tk/win/tkWinPort.h里面的即可。
【4】下面几个错误主要是因为新版的cygwin 修改了几个路径转换的接口函数所引起的。
../../insight-6.8-1/gdb/remote-fileio.c: In function‘remote_fileio_func_rename’:
../../insight-6.8-1/gdb/remote-fileio.c:1007:5: error:‘cygwin_conv_to_full_posix_path’ is deprecated (declared at/usr/include/sys/cygwin.h:40)
../../insight-6.8-1/gdb/remote-fileio.c:1008:5: error:‘cygwin_conv_to_full_posix_path’ is deprecated (declared at/usr/include/sys/cygwin.h:40)
当然也是因为打开了-Werror,所以编译器把警告也当然错误来处理,不让编译通过。这个编译出错的地方是有提示的,如下:
cc1: warnings being treated as errors
修改有两种方法,第一去掉-Werror选项,第二用cygwin新定义的函数。下面就两种方法,分别介绍,先说使用新函数吧。
首先Cygwin这个升级位于/usr/include/sys/cygwin.h
http://cygwin.com/cygwin-api/func-cygwin-conv-path.html 官网上有用法
/* DEPRECATEDINTERFACES. These are restricted toMAX_PATH length. Don't use in modern applications. */
extern intcygwin_win32_to_posix_path_list (const char *, char *) __attribute__ ((deprecated));
extern intcygwin_win32_to_posix_path_list_buf_size (const char *) __attribute__ ((deprecated));
extern intcygwin_posix_to_win32_path_list (const char *, char *) __attribute__ ((deprecated));
extern intcygwin_posix_to_win32_path_list_buf_size (const char *) __attribute__ ((deprecated));
extern intcygwin_conv_to_win32_path (const char *, char *) __attribute__ ((deprecated));
extern intcygwin_conv_to_full_win32_path (const char *, char *) __attribute__ ((deprecated));
extern intcygwin_conv_to_posix_path (const char *, char *) __attribute__ ((deprecated));
extern intcygwin_conv_to_full_posix_path (const char *, char *) __attribute__ ((deprecated));
/* Use theseinterfaces in favor of the above. */
/* Possible 'what'values in calls to cygwin_conv_path/cygwin_create_path. */
enum
{
CCP_POSIX_TO_WIN_A = 0, /* from is char*, tois char* */
CCP_POSIX_TO_WIN_W, /* from ischar*, to is wchar_t* */
CCP_WIN_A_TO_POSIX, /* from is char*, to is char* */
CCP_WIN_W_TO_POSIX, /* from iswchar_t*, to is char* */
CCP_CONVTYPE_MASK = 3,
/* Or these valuesto the above as needed. */
CCP_ABSOLUTE = 0, /* Request absolute path (default). */
CCP_RELATIVE = 0x100 /* Request to keep path relative. */
};
typedef unsigned int cygwin_conv_path_t;
/* If size is 0,cygwin_conv_path returns the required buffer size in bytes. Otherwise, itreturns 0 on success, or -1 on error and errno is set to one of the belowvalues:
EINVAL what has an invalid value.
EFAULT from or to point into nirvana.
ENAMETOOLONG the resulting path is longer than 32K, or, incase
of what == CCP_POSIX_TO_WIN_A, longer thanMAX_PATH.
ENOSPC size is less than required for theconversion.
*/
extern ssize_t cygwin_conv_path (cygwin_conv_path_t what, constvoid *from,
void *to, size_t size);
/* Same, but handlespath lists separated by colon or semicolon. */
extern ssize_t cygwin_conv_path_list (cygwin_conv_path_t what,const void *from,
void *to, size_t size);
原先的函数后面都加了deprecated 属性,所以才会有警告,又因为把警告当成错误处理,所以出错了。可以看出新版cygwin使用了cygwin_conv_path和cygwin_conv_path_list来代替原来的8个函数,通过cygwin_conv_path_t来进行区分。所以修改也是围绕这个来。
一共要改三个文件,分别如下:
1)insight-6.8-1/gdb/gdbtk/generic/gdbtk.c
const char **lib_path;
Tcl_DString lib_dstring;
int len;
Tcl_DStringInit (&lib_dstring);
#ifdef__CYGWIN__
/* SRC_DIR from configure is a posix path. Tcl really needs a
windows path. */
// src_dir = (char *) alloca(cygwin_posix_to_win32_path_list_buf_size (SRC_DIR));
// cygwin_posix_to_win32_path_list (SRC_DIR,src_dir);
len = cygwin_conv_path_list(CCP_WIN_A_TO_POSIX,SRC_DIR, NULL, 0);
src_dir = (char *) alloca (len);
cygwin_conv_path_list(CCP_WIN_A_TO_POSIX,SRC_DIR, src_dir, len);
#endif
Cygwin32_attach_handle_to_fd("/dev/conin", 0,
GetStdHandle(STD_INPUT_HANDLE),
1,GENERIC_READ);
Cygwin32_attach_handle_to_fd("/dev/conout", 1,
GetStdHandle(STD_OUTPUT_HANDLE),
0,GENERIC_WRITE);
Cygwin32_attach_handle_to_fd("/dev/conout", 2,
GetStdHandle(STD_ERROR_HANDLE),
0,GENERIC_WRITE);
2)insight-6.8-1/gdb/gdbtk/generic/gdbtk-cmds.c
staticint gdb_path_conv (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj*CONST objv[])
{
int len =0;
if (objc != 2)
{
Tcl_WrongNumArgs (interp, 1, objv, NULL);
return TCL_ERROR;
}
#ifdef__CYGWIN__
{
char pathname[256], *ptr;
// cygwin_conv_to_full_win32_path (Tcl_GetStringFromObj (objv[1], NULL),pathname);
len =cygwin_conv_path(CCP_POSIX_TO_WIN_A,Tcl_GetStringFromObj (objv[1], NULL),NULL,0);
cygwin_conv_path(CCP_POSIX_TO_WIN_A,Tcl_GetStringFromObj(objv[1], NULL), pathname, len);
3)insight-6.8-1/gdb/remote-fileio.c
// cygwin_conv_to_full_posix_path (oldpath,oldfullpath);
// cygwin_conv_to_full_posix_path (newpath,newfullpath);
len = cygwin_conv_path(CCP_WIN_A_TO_POSIX,oldpath, NULL, 0);
cygwin_conv_path(CCP_WIN_A_TO_POSIX, oldpath,oldfullpath, len);
len = cygwin_conv_path(CCP_WIN_A_TO_POSIX,newpath, NULL, 0);
cygwin_conv_path(CCP_WIN_A_TO_POSIX, newpath,newfullpath, len);
这几个文件修改方法是,删掉红色部分,增加绿色部分,保留下黑色部分。
第二修改方法和下面的部分一起讲。
【5】下面是几个错误,也是因为打开了-Werror 选项引起的
cc1: warnings being treated as errors
cp-name-parser.y: In function ‘cp_comp_to_string’:
cp-name-parser.y:1980:20: error: comparison between ‘enumdemangle_component_type’ and ‘enum <anonymous>’
cp-name-parser.y:1985:25: error: comparison between ‘enumdemangle_component_type’ and ‘enum <anonymous>’
Makefile:1103: recipe for target `cp-name-parser.o' failed
iteral -Wno-pointer-sign -Wno-unused -Wno-switch -Wno-char-subscripts-Werror ../../insight-6.8-1/gdb/ada-lang.c
cc1: warnings being treated as errors
../../insight-6.8-1/gdb/ada-lang.c: In function‘ada_attribute_name’:
../../insight-6.8-1/gdb/ada-lang.c:7686:9: error: comparison between‘enum exp_opcode’ and ‘enum ada_operator’
../../insight-6.8-1/gdb/ada-lang.c: In function ‘assign_component’:
../../insight-6.8-1/gdb/ada-lang.c:8186:30: error: comparisonbetween ‘enum exp_opcode’ and ‘enum ada_operator’
../../insight-6.8-1/gdb/ada-lang.c: In function ‘aggregate_assign_from_choices’:
../../insight-6.8-1/gdb/ada-lang.c:8341:14: error: comparisonbetween ‘enum exp_opcode’ and ‘enum ada_operator’
../../insight-6.8-1/gdb/ada-lang.c: In function‘ada_evaluate_subexp’:
../../insight-6.8-1/gdb/ada-lang.c:8540:34: error: comparisonbetween ‘enum exp_opcode’ and ‘enum ada_operator’
../../insight-6.8-1/gdb/ada-lang.c:9099:32: error: comparisonbetween ‘enum exp_opcode’ and ‘enum ada_operator’
Makefile:1103: recipe for target `ada-lang.o' failed
1) insight-6.8-1/gdb/cp-name-parser.c和insight-6.8-1/gdb/cp-name-parse.y
这两个文件都要改。
if (result->type == (enum demangle_component_type)GLOBAL_DESTRUCTORS)
{
result = d_left (result);
prefix = "global destructors keyedto ";
}
else if (result->type == (enum demangle_component_type)GLOBAL_CONSTRUCTORS)
{
result = d_left (result);
prefix = "global constructors keyedto ";
}
2)insight-6.8-1/gdb/cp-name-parser.c
Line: 7686 if ((int)n>= OP_ATR_FIRST && (int)n <=(int) OP_ATR_VAL)
Line: 8186 if ((int)exp->elts[*pos].opcode== OP_AGGREGATE)
Line: 8341 if ((int)op == OP_DISCRETE_RANGE)
Line:8540 if ((int)exp->elts[*pos].opcode== OP_AGGREGATE)
Line: 9099 (int)op== OP_ATR_MIN ? BINOP_MIN : BINOP_MAX);
到这里编译 insight-6.8-1的所有错误都改完了。编完之后,就可以在bin目录找到insight了。
下面来说第二种方法,就是如何去掉–Werror编译选项。找到 insight-6.8-1/gdb/makefile.in
在147行的下一行加上:
Line:147: GDB_WERROR_CFLAGS = $(WERROR_CFLAGS)
Line: 148: GDB_WERROR_CFLAGS =
就可以了
到这里,所有的编译都完成了,arm-none-eabi-gcc已生成,并还gdb和insight。
最后,本文写给和我一样的对gcc和linux是菜鸟的同志们,欢迎给出意见~~~~