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
???? ;;
…
至此,終于真相大白!