gcc支持多种不同的语言,也支持多种不同的CPU架构。
 
在它的实现上,不同语言编译的实现是通过
 
conststruct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 
这个结构体的不同定义来实现的。比如c语言的编译器就通过gcc/c-lang.c指定了lang_hooks这个结构体的一个实现。而C++语言编译器对此结构体的实现则放在gcc/cp/cp-lang.c中,同样在gcc目录下还可以发现gcc/objcp/objcp-lang.c和gcc/treelang/treetree.c这两个文件也提供了lang_hooks的不同实现。由此就可以很容易发现gcc所支持的编程语言。
 
而要生成不同目标CPU的代码,gcc则提供了另一个结构体:
 
struct gcc_target targetm = TARGET_INITIALIZER;
 
对此结构体的不同实现则是放在gcc/config/xxx/目录下的,其中xxx是具体的平台,如i386,bfin等等。
 
当然在后端,除了对gcc_target这个结构体提供不同的实现外,还必须重新定义一系列的宏,这些宏都是放在不同平台的config子目录下的,那么gcc如何知道要包含哪个目录下的头文件呢?
 
答案就在tm.h。以下是bf561交叉编译器下tm.h的内容:
 
#ifndef GCC_TM_H
 
#define GCC_TM_H
 
#ifdef IN_GCC
 
# include"options.h"
 
# include"config/bfin/bfin.h"
 
# include"config/dbxelf.h"
 
# include"config/elfos.h"
 
# include"config/bfin/elf.h"
 
# include"defaults.h"
 
#endif
 
#ifdefined IN_GCC && !defined GENERATOR_FILE && !defined USED_FOR_TARGET
 
# include"insn-constants.h"
 
# include"insn-flags.h"
 
#endif
 
#endif/* GCC_TM_H */
 
tm.h并不是gcc源码包的一部分,而是动态生成的,在gcc/gcc目录下的Makefile有这样的部分:
 
 
tm.h: cs-tm.h ; @true
 
…
 
cs-tm.h: Makefile
 
TARGET_CPU_DEFAULT="$(target_cpu_default)" /
 
HEADERS="$(tm_include_list)" DEFINES="$(tm_defines)" /
 
$(SHELL) $(srcdir)/mkconfig.sh tm.h
 
 
这说明tm.h的生成要靠mkconfig.sh将tm_include_list这个变量中列出的文件。
 
再看看tm_include_list的定义:
 
tm_include_list=options.h config/bfin/bfin.h config/dbxelf.h config/elfos.h config/bfin/elf.h defaults.h
 
这个变量也是在Makefile中定义的,但是Makefile是由gcc/configure动态生成的,所以再看看gcc/configure中的相关部分:
 
tm_file_list="options.h"
 
tm_include_list="options.h"
 
for f in $tm_file; do
 
 case $f in
 
    defaults.h )
 
       tm_file_list="${tm_file_list} /$(srcdir)/$f"
 
       tm_include_list="${tm_include_list} $f"
 
       ;;
 
    * )
 
       tm_file_list="${tm_file_list} /$(srcdir)/config/$f"
 
       tm_include_list="${tm_include_list} config/$f"
 
       ;;
 
 esac
 
done
 
离目标越来越近了,顺藤摸瓜,看看在config.gcc中对$tm_file的定义:
 
tm_file=${cpu_type}/${cpu_type}.h
 
…
 
case ${target} in
 
# Support site-specific machine types.
 
…
 
bfin*-elf*)
 
     tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h"
 
        tmake_file=bfin/t-bfin-elf
 
        use_collect2=no
 
        ;;
 
bfin*-uclinux*)
 
     tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h bfin/uclinux.h"
 
        tmake_file=bfin/t-bfin-uclinux
 
        use_collect2=no
 
        ;;
 
bfin*-linux-uclibc*)
 
     tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h linux.h bfin/linux.h"
 
        tmake_file="t-slibgcc-elf-ver bfin/t-bfin-linux"
 
        use_collect2=no
 
        ;;
 
bfin*-*)
 
     tm_file="${tm_file} dbxelf.h elfos.h bfin/elf.h"
 
        tmake_file=bfin/t-bfin
 
        use_collect2=no
 
        ;;
 
…
 
呵呵,最后看看cpu_type的定义:
 
cpu_type=`echo ${target} | sed 's/-.*$//'`
 
…
 
case ${target} in
 
…
 
bfin*-*)
 
     cpu_type=bfin
 
     ;;
 
…
 
至此,终于真相大白!