Welcome 微信登录

首页 / 操作系统 / Linux / mini6410 U-boot Makefile 注释

首先来看顶层目录 Makefile 文件VERSION = 1PATCHLEVEL = 1SUBLEVEL = 6EXTRAVERSION =U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)VERSION_FILE = $(obj)include/version_autogenerated.h#uboot 版本号 1.1.6HOSTARCH := $(shell uname -m | /sed -e s/i.86/i386/ /     -e s/sun4u/sparc64/ /    -e s/arm.*/arm/ /    -e s/sa110/arm/ /    -e s/powerpc/ppc/ /    -e s/macppc/ppc/)#HOSTARCH :=i386#sed 用法 uname -m 输出 i686  sed 将i686 替换为 i386HOSTOS := $(shell uname -s | tr "[:upper:]" "[:lower:]" | /    sed -e "s//(cygwin/).*/cygwin/")# tr "[:upper:]" "[:lower:]"  把大写改为小写  即 Linux 改为 linux#HOSTOS := linuxexport HOSTARCH HOSTOS# HOSTARCH := i386# HOSTOS := linux########################################################################### U-boot build supports producing a object files to the separate external# directory. Two use cases are supported:## 1) Add O= to the make command line# "make O=/tmp/build all"## 2) Set environement variable BUILD_DIR to point to the desired location# "export BUILD_DIR=/tmp/build"# "make"## The second approach can also be used with a MAKEALL script# "export BUILD_DIR=/tmp/build"# "./MAKEALL"## Command line "O=" setting overrides BUILD_DIR environent variable.## When none of the above methods is used the local build is performed and# the object files are placed in the source directory.#ifdef Oifeq ("$(origin O)", "command line")#origin函数用于查询变量的出处,此处期望他在命令行中定义BUILD_DIR := $(O)endifendififneq ($(BUILD_DIR),)saved-output := $(BUILD_DIR)#如果BUILD_DIR 不为空 # Attempt to create a output directory.$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})# Verify if it was successful.BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))endif # ifneq ($(BUILD_DIR),)# BUILD_DIR 是否存在OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))#****当BUILD_DIR存在时则赋给OBJTREE,否则OBJTREE=CURDIR(它代表当前工作目录,应该是个环境变量)SRCTREE := $(CURDIR)TOPDIR := $(SRCTREE)LNDIR := $(OBJTREE)export TOPDIR SRCTREE OBJTREEMKCONFIG := $(SRCTREE)/mkconfigexport MKCONFIG#MKCONFIG := mkconfig#****这个脚本文件很重要  ifneq ($(OBJTREE),$(SRCTREE))REMOTE_BUILD := 1export REMOTE_BUILDendif#****建立外部目录的部分就结束了# $(obj) and (src) are defined in config.mk but here in main Makefile# we also need them before config.mk is included which is the case for# some targets like unconfig, clean, clobber, distclean, etc.ifneq ($(OBJTREE),$(SRCTREE))obj := $(OBJTREE)/src := $(SRCTREE)/elseobj :=src :=endifexport obj src##################################################################################################################################################ifeq ($(OBJTREE)/include/config.mk,$(wildcard $(OBJTREE)/include/config.mk))# load ARCH, BOARD, and CPU configurationinclude $(OBJTREE)/include/config.mkexport ARCH CPU BOARD VENDOR SOC#/include/config.mk 内容 在make *_config 时产生## Create include file for Make#echo "ARCH   = $2" >  config.mkecho "CPU    = $3" >> config.mkecho "BOARD  = $4" >> config.mk[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk#ARCH   = arm#CPU    = s3c64xx#BOARD  = mini6410#VENDOR = samsung#SOC    = s3c6410ifeq ($(ARCH),arm)CROSS_COMPILE = arm-linux-endifCROSS_COMPILE = arm-linux-export CROSS_COMPILE#指定交叉编译工具前缀# load other configurationinclude $(TOPDIR)/config.mk****重要的配置脚本总结:
     $(SRCTREE)/mkconfig
    $(TOPDIR)/config.mk
  $(obj)include/config.mk
注意前面两个是在源文件目录,而后两个在目标文件目录,当然他们也可能一样########################################################################## U-Boot objects....order is important (i.e. start must be first)OBJS  = cpu/$(CPU)/start.oOBJS := $(addprefix $(obj),$(OBJS))#addprefix加前缀函数LIBS  = lib_generic/libgeneric.aLIBS += board/$(BOARDDIR)/lib$(BOARD).aLIBS += cpu/$(CPU)/lib$(CPU).aifdef SOCLIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).aendifLIBS += lib_$(ARCH)/lib$(ARCH).aLIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a /fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.aLIBS += net/libnet.aLIBS += disk/libdisk.aLIBS += rtc/librtc.aLIBS += dtt/libdtt.aLIBS += drivers/libdrivers.aLIBS += drivers/nand/libnand.aLIBS += drivers/nand_legacy/libnand_legacy.a# add to support onenand. by scsuhLIBS += drivers/onenand/libonenand.aLIBS += drivers/sk98lin/libsk98lin.aLIBS += post/libpost.a post/cpu/libcpu.aLIBS += common/libcommon.aLIBS += $(BOARDLIBS)LIBS := $(addprefix $(obj),$(LIBS))****LIBS,包含了后缀为.a的文件,这种文件是在进到到各个目录执行make产生的库文件,链接时需要这些文件。链接的文件涉及到了 lib_generic目录,cpu目录,lib_arm目录(以arm为例子),fs目录,net目录,disk目录,drivers目录。从上面这段代码就可以清楚的知道,整个u-boot究竟需要什么文件,由哪些文件组成。
.PHONY : $(LIBS)****声明伪目标,在后面的编译中用# Add GCC libPLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc#dirname 去掉最后一层目录#CC = $(CROSS_COMPILE)gcc = arm-linux-gccCFLAGS 编译选项,也是在顶层目录的config.mk中定义# The "tools" are needed early, so put this first# Don"t include stuff already done in $(LIBS)SUBDIRS = tools /  examples /  post /  post/cpu.PHONY : $(SUBDIRS)#伪目标SUBDIRS: 执行tools ,examples ,post,post/cpu 子目录下面的make文件ifeq ($(CONFIG_NAND_U_BOOT),y)NAND_SPL = nand_splU_BOOT_NAND = $(obj)u-boot-nand.binendif__OBJS := $(subst $(obj),,$(OBJS))#去掉前缀,__OBJS=cpu/arm920t/start.o__LIBS := $(subst $(obj),,$(LIBS))#去掉前缀,__LIBS=$(LIBS)+$(LIBBOARD)#########################################################################ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)all: $(ALL)****当输入命令 make all,讲寻找到此次的伪目标all,all依赖于 $(ALL),ALL由4部分组成。那么接下去就分别对这4部分进行递归的处理。$(obj)u-boot.hex: $(obj)u-boot$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@#arm-linux-objcopy被用来复制一个目标文件的内容到另一个文件中,#可用于不同源文件的之间的格式转换 #OBJCOPY = $(CROSS_COMPILE)objcopy$(obj)u-boot.srec: $(obj)u-boot$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@$(obj)u-boot.bin: $(obj)u-boot$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@$(OBJDUMP) -d $< > $<.dis(1)目标文件u-boot.bin依赖于 $(obj)u-boot目标;$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)(1.1.1)depend:执行的操作为:进入到$(SUBDIRS),生成各个子目录的.depend文件。通过调用各个子目录的make _depend。depend dep:for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done(1.1.2)$(SUBDIRS);执行操作为:对各个子目录执行makefile文件。$(SUBDIRS):$(MAKE) -C $@ all(1.1.3) $(OBJS);执行:             $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))                   如果cpu为arm920t,编译文件cpu/arm920t。(1.1.4) $(LIBS) ;依赖$(SUBDIRS).执行操作为:            $(MAKE) -C $(dir $(subst $(obj),,$@)),            dir为GNU内嵌函数为取目录操作,比如$(dir a/b/c) 结果为            a/b/;subst 也是GNU内嵌函数$(subst from,to,text)表示在text            中把form 字符串替换为字符串to。subst资料上面是这样讲的。但是            在此处,我认为是:$(subst text, to, from)。总之,这样理解            吧:在LIBS包含的n个路径下面执行make$(obj)u-boot.img: $(obj)u-boot.bin./tools/mkimage -A $(ARCH) -T firmware -C none /-a $(TEXT_BASE) -e 0 /-n $(shell sed -n -e "s/.*U_BOOT_VERSION//p" $(VERSION_FILE) | /sed -e "s/"[  ]*$$/ for $(BOARD) board"/") /-d $< $@$(obj)u-boot.dis: $(obj)u-boot$(OBJDUMP) -d $< > $@$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed  -n -e "s/.*/(__u_boot_cmd_.*/)/-u/1/p"|sort|uniq`;/cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) /--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) /-Map u-boot.map -o u-boot#LNDIR := $(OBJTREE)#LD = $(CROSS_COMPILE)ld$(OBJS):$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))$(LIBS):$(MAKE) -C $(dir $(subst $(obj),,$@))$(SUBDIRS):$(MAKE) -C $@ all$(NAND_SPL): version$(MAKE) -C nand_spl/board/$(BOARDDIR) all$(U_BOOT_NAND): $(NAND_SPL) $(obj)u-boot.bincat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.binversion:@echo -n "#define U_BOOT_VERSION /"U-Boot " > $(VERSION_FILE); /echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); /echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion / $(TOPDIR)) >> $(VERSION_FILE); /echo "/"" >> $(VERSION_FILE)gdbtools:$(MAKE) -C tools/gdb all || exit 1updater:$(MAKE) -C tools/updater all || exit 1env:$(MAKE) -C tools/env all || exit 1depend dep:for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; donetags ctags:ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include /lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) /fs/cramfs fs/fat fs/fdos fs/jffs2 /net disk rtc dtt drivers drivers/sk98lin common //( -name CVS -prune /) -o /( -name "*.[ch]" -print /)`etags:etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include /lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) /fs/cramfs fs/fat fs/fdos fs/jffs2 /net disk rtc dtt drivers drivers/sk98lin common //( -name CVS -prune /) -o /( -name "*.[ch]" -print /)`$(obj)System.map: $(obj)u-boot@$(NM) $< | /grep -v "/(compiled/)/|/(/.o$$/)/|/( [aUw] /)/|/(/./.ng$$/)/|/(LASH[RL]DI/)" | /sort > $(obj)System.map#########################################################################elseall $(obj)u-boot.hex $(obj)u-boot.srec $(obj)u-boot.bin /$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot /$(SUBDIRS) version gdbtools updater env depend /dep tags ctags etags $(obj)System.map:@echo "System not configured - see README" >&2@ exit 1endif.PHONY : CHANGELOGCHANGELOG:git log --no-merges U-Boot-1_1_5.. | /unexpand -a | sed -e "s//s/s*$$//" > $@#########################################################################unconfig:@rm -f $(obj)include/config.h $(obj)include/config.mk /$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp#========================================================================mini6410_nand_config-ram128 :  unconfig@$(MKCONFIG) mini6410 arm s3c64xx mini6410 samsung s3c6410 NAND ram128unconfig:@rm -f $(obj)include/config.h $(obj)include/config.mk /$(obj)board/*/config.tmp $(obj)board/*/*/config.tmpMKCONFIG := $(SRCTREE)/mkconfig在执行make之前,我们先执行了make *_config例如我们执行 mini6410_nand_config-ram128 配置mini6410开发板 实际执行:@$(MKCONFIG) mini6410 arm s3c64xx mini6410 samsung s3c6410 NAND ram128$(MKCONFIG) 实际就是uboot顶层目录下的 mkconfig脚本文件,内容如下所示:#!/bin/sh -e# Script to create header files and links to configure# U-Boot for a specific board.## Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC]## (C) 2002-2006 DENX Software Engineering, Wolfgang Denk <wd@denx.de>#APPEND=no # Default: Create new config fileBOARD_NAME="" # Name to print in make outputwhile [ $# -gt 0 ] ; docase "$1" in--) shift ; break ;;-a) shift ; APPEND=yes ;;-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;*)  break ;;esacdone[ "${BOARD_NAME}" ] || BOARD_NAME="$1"[ $# -lt 4 ] && exit 1[ $# -gt 8 ] && exit 1echo "Configuring for ${BOARD_NAME} board which boot from $7 $8..."## Create link to architecture specific headers#if [ "$SRCTREE" != "$OBJTREE" ] ; thenmkdir -p ${OBJTREE}/includemkdir -p ${OBJTREE}/include2cd ${OBJTREE}/include2rm -f asmln -s ${SRCTREE}/include/asm-$2 asmLNPREFIX="../../include2/asm/"cd ../includerm -rf asm-$2rm -f asmmkdir asm-$2ln -s asm-$2 asmelsecd ./includerm -f asmln -s asm-$2 asm  //建立从asm-arm 到 asm的链接firm -f asm-$2/archif [ -z "$6" -o "$6" = "NULL" ] ; thenln -s ${LNPREFIX}arch-$3 asm-$2/archelseln -s ${LNPREFIX}arch-$6 asm-$2/archfi@$(MKCONFIG)$1、mini6410 $2、arm $3、s3c64xx $4、mini6410 $5、samsung $6、s3c6410 $7、NAND $8、ram128# create link for s3c64xx SoCif [ "$3" = "s3c64xx" ] ; thenrm -f regs.hln -s $6.h regs.hrm -f asm-$2/archln -s arch-$3 asm-$2/archfiif [ "$2" = "arm" ] ; thenrm -f asm-$2/procln -s ${LNPREFIX}proc-armv asm-$2/procfi## Create include file for Make#echo "ARCH   = $2" >  config.mkecho "CPU    = $3" >> config.mkecho "BOARD  = $4" >> config.mk[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk## Create board specific header file#if [ "$APPEND" = "yes" ] # Append to existing config filethenecho >> config.helse> config.h # Create new config filefiecho "/* Automatically generated - do not edit */" >>config.hcase $7 inSD)echo "#define FRIENDLYARM_BOOT_MEDIA_SD"   >> config.h;;NAND)echo "#define FRIENDLYARM_BOOT_MEDIA_NAND" >> config.h;;*);;esaccase $8 inram128)echo "#define FRIENDLYARM_BOOT_RAM128" >> config.h;;ram256)echo "#define FRIENDLYARM_BOOT_RAM256" >> config.h;;*);;esacecho "#include <configs/$1.h>" >>config.hexit 0下面分析 config.mk 这个文件的作用等于 kernel 中的 .config ?## (C) Copyright 2000-2006# Wolfgang Denk, DENX Software Engineering, wd@denx.de.## See file CREDITS for list of people who contributed to this# project.## This program is free software; you can redistribute it and/or# modify it under the terms of the GNU General Public License as# published by the Free Software Foundation; either version 2 of# the License, or (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston,# MA 02111-1307 USA##########################################################################ifneq ($(OBJTREE),$(SRCTREE))ifeq ($(CURDIR),$(SRCTREE))dir :=elsedir := $(subst $(SRCTREE)/,,$(CURDIR))endifobj := $(if $(dir),$(OBJTREE)/$(dir)/,$(OBJTREE)/)src := $(if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/)$(shell mkdir -p $(obj))elseobj :=src :=endif# clean the slate ...PLATFORM_RELFLAGS =PLATFORM_CPPFLAGS =PLATFORM_LDFLAGS =## When cross-compiling on NetBSD, we have to define __PPC__ or else we# will pick up a va_list declaration that is incompatible with the# actual argument lists emitted by the compiler.## [Tested on NetBSD/i386 1.5 + cross-powerpc-netbsd-1.3]ifdef ARCHsinclude $(TOPDIR)/$(ARCH)_config.mk # include architecture dependend rulesendififdef CPUsinclude $(TOPDIR)/cpu/$(CPU)/config.mk # include  CPU specific rulesendififdef SOCsinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk # include  SoC specific rulesendififdef VENDORBOARDDIR = $(VENDOR)/$(BOARD)elseBOARDDIR = $(BOARD)endififdef BOARDsinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rulesendif#config.mk 内容#ifndef TEXT_BASE#TEXT_BASE = 0xc7e00000#endif#########################################################################CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; /    else if [ -x /bin/bash ]; then echo /bin/bash; /    else echo sh; fi ; fi)ifeq ($(HOSTOS)-$(HOSTARCH),darwin-ppc)HOSTCC = ccelseHOSTCC = gccendifHOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointerHOSTSTRIP = strip########################################################################### Option checker (courtesy linux kernel) to ensure# only supported compiler options are used#cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null /> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)## Include the make variables (CC, etc...)#AS = $(CROSS_COMPILE)asLD = $(CROSS_COMPILE)ldCC = $(CROSS_COMPILE)gccCPP = $(CC) -EAR = $(CROSS_COMPILE)arNM = $(CROSS_COMPILE)nmSTRIP = $(CROSS_COMPILE)stripOBJCOPY = $(CROSS_COMPILE)objcopyOBJDUMP = $(CROSS_COMPILE)objdumpRANLIB = $(CROSS_COMPILE)RANLIB@定义AR选项ARFLAGS,调试选项DBGFLAGS,优化选项OPTFLAGS
预处理选项CPPFLAGS,C编译器选项CFLAGS,连接选项LDFLAGS
ifneq (,$(findstring s,$(MAKEFLAGS)))ARFLAGS = crelseARFLAGS = crvendifRELFLAGS= $(PLATFORM_RELFLAGS)DBGFLAGS= -g # -DDEBUGOPTFLAGS= -Os #-fomit-frame-pointerifndef LDSCRIPT#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debugifeq ($(CONFIG_NAND_U_BOOT),y)LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.ldselseLDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.ldsendifendifOBJCFLAGS += --gap-fill=0xffgccincdir := $(shell $(CC) -print-file-name=include)CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) /-D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) /ifneq ($(OBJTREE),$(SRCTREE))CPPFLAGS += -I$(OBJTREE)/include2 -I$(OBJTREE)/includeendifCPPFLAGS += -I$(TOPDIR)/includeCPPFLAGS += -fno-builtin -ffreestanding -nostdinc  /-isystem $(gccincdir) -pipe $(PLATFORM_CPPFLAGS)ifdef BUILD_TAGCFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes /-DBUILD_TAG=""$(BUILD_TAG)""elseCFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypesendif# $(CPPFLAGS) sets -g, which causes gcc to pass a suitable -g<format># option to the assembler.AFLAGS_DEBUG :=AFLAGS := $(AFLAGS_DEBUG) -D__ASSEMBLY__ $(CPPFLAGS)LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)# Location of a usable BFD library, where we define "usable" as# "built for ${HOST}, supports ${TARGET}".  Sensible values are# - When cross-compiling: the root of the cross-environment# - Linux/ppc (native): /usr# - NetBSD/ppc (native): you lose ... (must extract these from the#   binutils build directory, plus the native and U-Boot include#   files don"t like each other)## So far, this is used only by tools/gdb/Makefile.ifeq ($(HOSTOS)-$(HOSTARCH),darwin-ppc)BFD_ROOT_DIR = /usr/local/toolselseifeq ($(HOSTARCH),$(ARCH))# nativeBFD_ROOT_DIR = /usrelse#BFD_ROOT_DIR = /LinuxPPC/CDK # Linux/i386#BFD_ROOT_DIR = /usr/pkg/cross # NetBSD/i386BFD_ROOT_DIR = /opt/powerpcendifendififeq ($(PCI_CLOCK),PCI_66M)CFLAGS := $(CFLAGS) -DPCI_66Mendif#########################################################################export CONFIG_SHELL HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE /AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP /MAKEexport TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS AFLAGS#########################################################################ifndef REMOTE_BUILD%.s: %.S$(CPP) $(AFLAGS) -o $@ $<%.o: %.S$(CC) $(AFLAGS) -c -o $@ $<%.o: %.c$(CC) $(CFLAGS) -c -o $@ $<else$(obj)%.s: %.S$(CPP) $(AFLAGS) -o $@ $<$(obj)%.o: %.S$(CC) $(AFLAGS) -c -o $@ $<$(obj)%.o: %.c$(CC) $(CFLAGS) -c -o $@ $<endif#########################################################################