转载时请注明出处和作者联系方式
作者联系方式:会飞的鱼 <parker30_liu at hotmail dot com>
GNU的Makefile有强大的功能,我们一直都用Makefile控制整个项目的构建过程。在使用Makefile的过程中有些有时用了些技巧,记录在此,以备以后参考。
技巧一:根据Makefile的内容自动生成Makefile的变量。
在我们的工程中有着众多的模块,根据我们的使用和分析,大部分的模块使用同样的优化参数即可,但有些模块需要用另外的优化参数。因此可以在Makefile中设定一个Makefile变量,该变量保存了缺省的优化参数,赋值给每个模块的CFLAGS变量,给少数的几个模块的CFLAGS变量单独赋值。但我们的模块时常会有增加和减少,若手工维护这些变量很容易出错,导致有些模块的优化参数设置不对,影响性能和系统测试的结果。若能依赖Makefile自己根据模块列表自动生成每个模块的CFLAGS变量,并赋值为缺省的优化参数,就省事了。
我查看了GNU的Makefile手册,没有发现可以通过Makefile自身产生变量给自己用的方法。看来只好用文件的方法了,通过一个脚本文件根据模块生成变量及赋值表达式,将其写入一个新的Makefile中,然后在原来这个Makefile中通过include命令包含新的Makefile。
Makefile中的实现如下所示。
GEN_MODULES_FLAGS := ` . ./ genmodflags . sh " $(ALL_MODULES) " > hw_defaultflags . mk`
include hw_defaultflags . mk
include com . mk
hw_defaultflags . mk : hw . mk
@eval $(GEN_MODULES_FLAGS);
脚本文件如下所示。
for MODULE in $ 1 ; do
MODULE = `echo $MODULE | tr [a - z] - [A - Z]_`
echo " ${MODULE}_OPTIM_FLAGS?=$(BRONCHO_DEFAULT_OPTIM_FLAGS) "
done
因为GNU的Makefile具有两遍执行的特性,因此当第一遍执行时若没有hw_defaultflags.mk时,只是会报告错误,但仍然会根据规则产生hw_defaultflags.mk文件。在第二遍执行时将hw_defaultflags.mk包含进来,执行com.mk中的编译过程。
技巧二:使用Makefile的片断文件定制构建过程。
gcc的构建系统可以为多个目标构建gcc编译器,多种体系架构(ARM,X86,ALPHA,POWER,SPARC)和操作系统(linux,unix,BSD,cygwin,ecos,symbian)的目标现在都可以得到支持,具体的目标列表可以查看gcc的相关网站。每个目标的编译器都有一些和其他目标不同的构建过程的设置,如包含目标特定的文件、定义特定的编译条件等,这就需要有一个对各个目标的构建过程进行定制的方法。gcc 的构建系统是通过包含各个具体目标相关的Makefile片断文件的方法来实现的。
gcc的配置目录(gcc/config/)下保存了各个目标系统相关的Makefile片断文件,这些片断文件重新设置了构建过程的变量和独有的构建过程规则。下面是支持intel的iwmmx指令的gcc构建的Makefile片断文件(gcc/config/arm/t-iwmmxt-elf),这里的$(T)crti.o的规则就是该目标独有的构建过程规则。
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _bb_init_func
_call_via_rX _interwork_call_via_rX
_lshrdi3 _ashrdi3 _ashldi3
_negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi
_truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2
_fixsfsi _fixunssfsi _floatdidf _floatdisf _floatundidf _floatundisf
_unwind
MULTILIB_OPTIONS += mcpu = iwmmxt
MULTILIB_DIRNAMES += iwmmxt
MULTILIB_REDUNDANT_DIRS += interwork / thumb / iwmmxt = thumb
EXTRA_MULTILIB_PARTS = crtbegin . o crtend . o crti . o crtn . o
# If EXTRA_MULTILIB_PARTS is not defined above then define EXTRA_PARTS here
# EXTRA_PARTS = crtbegin.o crtend.o crti.o crtn.o
LIBGCC = stmp - multilib
INSTALL_LIBGCC = install - multilib
# Currently there is a bug somewhere in GCC's alias analysis
# or scheduling code that is breaking _fpmul_parts in fp-bit.c.
# Disabling function inlining is a workaround for this problem.
TARGET_LIBGCC2_CFLAGS = - Dinhibit_libc - fno - inline
# Assemble startup files.
$(T)crti . o : $(srcdir) / config / arm / crti . asm $(GCC_PASSES)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES)
- c - o $(T)crti . o -x assembler - with - cpp $(srcdir) / config / arm / crti . asm
$(T)crtn . o : $(srcdir) / config / arm / crtn . asm $(GCC_PASSES)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) - c - o $(T)crtn . o -x assembler - with - cpp $(srcdir) / config / arm / crtn . asm
gcc的configure(路径是gcc/configure)会执行gcc/config.gcc收集目标系统的具体规格信息,在该shell文件中,将目标系统使用的Makefile片断文件名加入到变量tmake_file中。然后gcc的Makefile用include指令将tmake_file中所有的Makefile片断文件包含进来,片断文件的变量设置和构建过程规则将在执行make命令时生效,从而构建出特定目标系统使用的gcc编译器。config.gcc中armlinux目标系统的相关代码如下所示。
tm_file = " dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h "
case ${target} in
arm *- iwmmxt -* )
tmake_file = " ${tmake_file} arm/t-iwmmxt-elf "
tm_file = " ${tm_file} arm/iwmmxt-linux-elf.h "
;;
* )
tmake_file = " ${tmake_file} arm/t-arm-elf "
tm_file = " ${tm_file} arm/linux-elf.h "
;; esac
tmake_file = " ${tmake_file} t-linux arm/t-arm "
case ${target} in
arm *-*- linux - gnueabi)
tm_file = " $tm_file arm/bpabi.h arm/linux-eabi.h "
tmake_file = " $tmake_file arm/t-bpabi arm/t-linux-eabi "
# The BPABI long long divmod functions return a 128-bit value in
# registers r0-r3. Correctly modeling that requires the use of
# TImode.
need_64bit_hwint = yes
# The EABI requires the use of __cxa_atexit.
default_use_cxa_atexit = yes
;;
* )
tmake_file = " $tmake_file arm/t-linux "
;;
esac
tm_file = " $tm_file arm/aout.h arm/arm.h "
;;