解释一个 Makefile 文件

学习一门技术的目的就是要把它拿来使用,因此,对技术的研究不存在最高境界,只存在实不实用。Makefile的知识也杂七杂入挺多的,真讨厌GNU那帮人一天在那里没事发明新东西,虽然说都有用,但我们学起来就太麻烦啦。因此,不求把Makefile知识学完,只求能满足实际需求。而最实际的需求就是,把下面的Makefile内容看懂吧

IDENT=-D_DEBUG -D_LIBC -DMIPS -DCONS_BAUD="B115200" -DRADEON7000 -DVGA_BASE="0xb0000000" 
ENDIAN=EL

.SUFFIXES:    .S .c .cpp .o 

CROSS_COMPILE     =mipsisa32-elf-

#
# Include the make variables (CC, etc...)
#

AS        = $(CROSS_COMPILE)as
LD        = $(CROSS_COMPILE)ld
CC        = $(CROSS_COMPILE)gcc
GPP        = $(CROSS_COMPILE)g++
CPP        = $(CC) -E
AR        = $(CROSS_COMPILE)ar
NM        = $(CROSS_COMPILE)nm
STRIP        = $(CROSS_COMPILE)strip
OBJCOPY        = $(CROSS_COMPILE)objcopy
OBJDUMP        = $(CROSS_COMPILE)objdump
RANLIB        = $(CROSS_COMPILE)ranlib
SIZE        = $(CROSS_COMPILE)size

OPT?=    -O2

# source tree is located via $S relative to the compilation directory
ifndef S
S:=.
endif

# Defines

TARGET= ${S}/init/
MACHINE=mips
MACHINE_ARCH=mips
COMPILEDIR=./include/mips/include
OBJDIR=${COMPILEDIR}
PMONDIR=${S}

INCLUDES=    -I. -I${S}/include -I${S}/lib -I${S}\
        -I${TARGET} -I${COMPILEDIR} -nostdinc 

CPPFLAGS=    ${INCLUDES} ${IDENT} -D_KERNEL -D_CNOS_\
        -${ENDIAN} -mno-abicalls -mips3 -mcpu=r4000 \
        -fno-rtti  -fomit-frame-pointer -nostdinc -nostdlib \
        -fno-exceptions -fcheck-new

CWARNFLAGS=    -Wall -Wstrict-prototypes \
        -Wno-uninitialized -Wno-format -Wno-main \
        -Wnon-virtual-dtor -Wno-parentheses \
        -Wno-pmf-conversions -Wno-pointer-arith  -Wno-unused-function \
        -Wundef 

CFLAGS=        ${DEBUG} ${CWARNFLAGS} ${OPT} -G 0
AFLAGS=        -D_LOCORE -G 0
LFLAGS=        -${ENDIAN} -N -G 0 -T$(S)/ldscript/ld.script -e start
STRIPFLAGS=    -g -S --strip-debug

HOSTCC?=    ${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS=    ${CFLAGS}

# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP}
# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix,
# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file
# is marked as config-dependent.

USRLAND_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
USRLAND_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<

NORMAL_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<
NORMAL_GPP= ${GPP} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<

DRIVER_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
DRIVER_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<

NORMAL_S=    ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
NORMAL_S_C=    ${AS}  ${COPTS} ${PARAM} $< -o $@

####################################################################################
##
##
##
OBJS= init.o \
    Hal.o \
    Serial.o \
    Cnos.o \
    Mm.o \
    Fs.o \
    interrupt.o \
    mips.o \
    KrnlDebug.o \
    desktop.o \
    surface.o \
    taskbar.o \
    window.o \
    button.o \
    Test.o 
####################################################################################
##      LIB
##

LIBS= string.o unicodefont16.a

####################################################################################
#
#      dirvers
#
DIRVERS = ATIR7000.o i8042.o pci.o ohci.o

####################################################################################
# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP}
#    ${SYSTEM_LD_HEAD}
#    ${SYSTEM_LD}
#    ${SYSTEM_LD_TAIL}

SYSTEM_OBJ=    start.o  ${OBJS} ${LIBS} ${DIRVERS}    

SYSTEM_DEP=    Makefile ${SYSTEM_OBJ}
SYSTEM_LD_HEAD=    rm -f $@
SYSTEM_LD=    @echo ${LD} ${LFLAGS} -o $@ '$${SYSTEM_OBJ}'; \
        ${LD} ${LFLAGS} -o $@ ${SYSTEM_OBJ} 
SYSTEM_LD_TAIL=    @${SIZE} $@; chmod 755 $@ ; \
        ${OBJCOPY} -O binary $@ $@.bin

DEBUG?=
ifeq (${DEBUG}, "-g")
LFLAGS+=    -X
SYSTEM_LD_TAIL+=; \
        echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \
        echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
else
LFLAGS+=    -S
endif

#####################################################################################
all: cnos Makefile

cnos: ${SYSTEM_DEP}
    ${SYSTEM_LD_HEAD}
    ${SYSTEM_LD}
    ${SYSTEM_LD_TAIL}

clean::
    rm -f tags *.[io] [a-z]*.s \
        cnos cnos.bin cnos.txt cnos_elf.txt
dump:
    $(OBJDUMP) -DS cnos >cnos.txt

tags:
    @echo "see $S/kern/Makefile for tags"

####################################################################################
#   %.S
####################################################################################
start.o: $S/init/start.S Makefile
    ${NORMAL_S}
mips.o:    $S/kern/ke/mips.S
    ${NORMAL_S}

####################################################################################
#   %.CPP
####################################################################################
init.o: $S/init/init.cpp
    ${NORMAL_GPP}

Hal.o:     $S/hal/Hal.cpp
    ${NORMAL_GPP}

Serial.o:    $S/hal/Serial.cpp
    ${NORMAL_GPP}

Cnos.o:        $S/kern/ke/Cnos.cpp
    ${NORMAL_GPP}

Mm.o:        $S/mm/Mm.cpp
    ${NORMAL_GPP}

Fs.o:        $S/fs/Fs.cpp
    ${NORMAL_GPP}

interrupt.o:    $S/kern/ke/interrupt.cpp
    ${NORMAL_GPP}

Test.o:        $S/test/Test.cpp
    ${NORMAL_GPP}

KrnlDebug.o: $S/kern/kd/KrnlDebug.cpp
    ${NORMAL_GPP}

desktop.o: $S/subsystems/gdi/desktop.cpp
    ${NORMAL_GPP}

surface.o: $S/subsystems/gdi/surface.cpp
    ${NORMAL_GPP}

taskbar.o: $S/subsystems/gdi/taskbar.cpp
    ${NORMAL_GPP}

window.o: $S/subsystems/gdi/window.cpp
    ${NORMAL_GPP}

button.o: $S/subsystems/gdi/button.cpp
    ${NORMAL_GPP}

####################################################################################
#
#  lib file
#
####################################################################################
string.o:        $S/lib/string.cpp
    ${NORMAL_GPP}

unicodefont16.a:    $S/media/font/unicodefont16.cpp
        ${GPP} ${CFLAGS} ${CPPFLAGS} ${PROF} -o unicodefont16.a -c $<

####################################################################################
#
#  driver file
#
####################################################################################
ATIR7000.o:        $S/dev/video/atir7000/ATIR7000.cpp
    ${NORMAL_GPP}
i8042.o:        $(S)/dev/input/i8042/i8042.cpp
    ${NORMAL_GPP}
pci.o:            $(S)/dev/bus/pci/pci.cpp
    ${NORMAL_GPP}
ohci.o:            $(S)/dev/bus/usb/ohci.cpp
    ${NORMAL_GPP}

这个Makefile不算复杂(还算是人写给人看的,没有使用GNU提供的autoconf, automake工具,它们产生的文件太恐怖了,不是给人看的~~)下面来一行一行讲解。

IDENT=-D_DEBUG -D_LIBC -DMIPS -DCONS_BAUD="B115200" -DRADEON7000 -DVGA_BASE="0xb0000000" 
ENDIAN=EL

定义了两个字符串 IDENT 和 ENDIAN,IDENT的内容代表的意义后面再讲解;
.SUFFIXES:    .S .c .cpp .o

这句定义make工具隐含规则准备操作的文件的后缀名;
CROSS_COMPILE     =mipsisa32-elf-

定义一个字符串变量 CROSS_COMPILE,一般在交叉编译环境中会经常看到这样的定义;
#
# Include the make variables (CC, etc...)
#

AS        = $(CROSS_COMPILE)as
LD        = $(CROSS_COMPILE)ld
CC        = $(CROSS_COMPILE)gcc
GPP        = $(CROSS_COMPILE)g++
CPP        = $(CC) -E
AR        = $(CROSS_COMPILE)ar
NM        = $(CROSS_COMPILE)nm
STRIP        = $(CROSS_COMPILE)strip
OBJCOPY        = $(CROSS_COMPILE)objcopy
OBJDUMP        = $(CROSS_COMPILE)objdump
RANLIB        = $(CROSS_COMPILE)ranlib
SIZE        = $(CROSS_COMPILE)size

这一段定义了一套编译工具变量,这里引用了前面定义的变量 CROSS_COMPILE(可以看到定义变量的好处了,以后修改可以很方便);
OPT?=    -O2

这句定义优化级别,加个?号表示如果此变量以前被定义过,就不再赋值了,否则要赋值;
# source tree is located via $S relative to the compilation directory
ifndef S
S:=.
endif

这里也用到了类似C语言的条件编译命令,这里是想定义一个变量,用来指示当前的编译根目录。:=也是赋值号, . 号表示当前目录;
# Defines

TARGET= ${S}/init/
MACHINE=mips
MACHINE_ARCH=mips
COMPILEDIR=./include/mips/include
OBJDIR=${COMPILEDIR}
PMONDIR=${S}

继续定义一些方便编译操作的变量。${} 和 $() 功能都是引用字符串变量的值。
INCLUDES=    -I. -I${S}/include -I${S}/lib -I${S}\
        -I${TARGET} -I${COMPILEDIR} -nostdinc

这一句定义编译时要包含的头文件的路径,实际上是定义的搜索路径。-I 是gcc定义的要找一个路径的语法前缀。-nostdinc 表示不要把系统提供的头文件路径给包含进来,这样就防止了系统头文件对我们自己开发的系统头文件的干扰;
CPPFLAGS=    ${INCLUDES} ${IDENT} -D_KERNEL -D_CNOS_\
        -${ENDIAN} -mno-abicalls -mips3 -mcpu=r4000 \
        -fno-rtti  -fomit-frame-pointer -nostdinc -nostdlib \
        -fno-exceptions -fcheck-new

这里定义一些gcc编译时的参数,用到了前面定义的一些字符串变量。现在还不懂 -D_KERNEL -D_CNOS_ 是啥意思;
CWARNFLAGS=    -Wall -Wstrict-prototypes \
        -Wno-uninitialized -Wno-format -Wno-main \
        -Wnon-virtual-dtor -Wno-parentheses \
        -Wno-pmf-conversions -Wno-pointer-arith  -Wno-unused-function \
        -Wundef

这里设置gcc编译时的警告级别,参数的意义要看gcc手册才能清楚;
CFLAGS=        ${DEBUG} ${CWARNFLAGS} ${OPT} -G 0
AFLAGS=        -D_LOCORE -G 0
LFLAGS=        -${ENDIAN} -N -G 0 -T$(S)/ldscript/ld.script -e start
STRIPFLAGS=    -g -S --strip-debug

这里定义标准的几个编译时环境变量,用到了前面的定义;
HOSTCC?=    ${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS=    ${CFLAGS}

(???)这一块功能不知道是干什么用的;
# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP}
# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix,
# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file
# is marked as config-dependent.

USRLAND_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
USRLAND_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<

NORMAL_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<
NORMAL_GPP= ${GPP} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<

DRIVER_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
DRIVER_C_C=    ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $<

NORMAL_S=    ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
NORMAL_S_C=    ${AS}  ${COPTS} ${PARAM} $< -o $@

(???)难~~~这一段好像是定义不同的编译规则的,分几种不同的目的。
####################################################################################
##
##
##
OBJS= init.o \
    Hal.o \
    Serial.o \
    Cnos.o \
    Mm.o \
    Fs.o \
    interrupt.o \
    mips.o \
    KrnlDebug.o \
    desktop.o \
    surface.o \
    taskbar.o \
    window.o \
    button.o \
    Test.o

普通文件目标定义
####################################################################################
##      LIB
##

LIBS= string.o unicodefont16.a

库文件目标(包括中文字库)
####################################################################################
#
#      dirvers
#
DIRVERS = ATIR7000.o i8042.o pci.o ohci.o

驱动程序目标
####################################################################################
# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP}
#    ${SYSTEM_LD_HEAD}
#    ${SYSTEM_LD}
#    ${SYSTEM_LD_TAIL}

SYSTEM_OBJ=    start.o  ${OBJS} ${LIBS} ${DIRVERS}

SYSTEM_DEP=    Makefile ${SYSTEM_OBJ}
SYSTEM_LD_HEAD=    rm -f $@
SYSTEM_LD=    @echo ${LD} ${LFLAGS} -o $@ '$${SYSTEM_OBJ}'; \
        ${LD} ${LFLAGS} -o $@ ${SYSTEM_OBJ} 
SYSTEM_LD_TAIL=    @${SIZE} $@; chmod 755 $@ ; \
        ${OBJCOPY} -O binary $@ $@.bin

DEBUG?=
ifeq (${DEBUG}, "-g")
LFLAGS+=    -X
SYSTEM_LD_TAIL+=; \
        echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \
        echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
else
LFLAGS+=    -S
endif

晕死,看不懂是做什么用的;

前面都在定义编译时的规则,后面才是真正的文件编译区。

#####################################################################################
all: cnos Makefile

cnos: ${SYSTEM_DEP}
    ${SYSTEM_LD_HEAD}
    ${SYSTEM_LD}
    ${SYSTEM_LD_TAIL}

clean::
    rm -f tags *.[io] [a-z]*.s \
        cnos cnos.bin cnos.txt cnos_elf.txt
dump:
    $(OBJDUMP) -DS cnos >cnos.txt

tags:
    @echo "see $S/kern/Makefile for tags"

这一段总算是比较规则的了,要生成一个 cnos 二进制文件;
####################################################################################
#   %.S
####################################################################################
start.o: $S/init/start.S Makefile
    ${NORMAL_S}
mips.o:    $S/kern/ke/mips.S
    ${NORMAL_S}

这是接下来的依赖关系,这里是两个汇编文件,正常编译;
####################################################################################
#   %.CPP
####################################################################################
init.o: $S/init/init.cpp
    ${NORMAL_GPP}

Hal.o:     $S/hal/Hal.cpp
    ${NORMAL_GPP}

Serial.o:    $S/hal/Serial.cpp
    ${NORMAL_GPP}

Cnos.o:        $S/kern/ke/Cnos.cpp
    ${NORMAL_GPP}

Mm.o:        $S/mm/Mm.cpp
    ${NORMAL_GPP}

Fs.o:        $S/fs/Fs.cpp
    ${NORMAL_GPP}

interrupt.o:    $S/kern/ke/interrupt.cpp
    ${NORMAL_GPP}

Test.o:        $S/test/Test.cpp
    ${NORMAL_GPP}

KrnlDebug.o: $S/kern/kd/KrnlDebug.cpp
    ${NORMAL_GPP}

desktop.o: $S/subsystems/gdi/desktop.cpp
    ${NORMAL_GPP}

surface.o: $S/subsystems/gdi/surface.cpp
    ${NORMAL_GPP}

taskbar.o: $S/subsystems/gdi/taskbar.cpp
    ${NORMAL_GPP}

window.o: $S/subsystems/gdi/window.cpp
    ${NORMAL_GPP}

button.o: $S/subsystems/gdi/button.cpp
    ${NORMAL_GPP}

系统的主体C++代码文件的编译;
####################################################################################
#
#  lib file
#
####################################################################################
string.o:        $S/lib/string.cpp
    ${NORMAL_GPP}

unicodefont16.a:    $S/media/font/unicodefont16.cpp
        ${GPP} ${CFLAGS} ${CPPFLAGS} ${PROF} -o unicodefont16.a -c $<

库文件的编译;
####################################################################################
#
#  driver file
#
####################################################################################
ATIR7000.o:        $S/dev/video/atir7000/ATIR7000.cpp
    ${NORMAL_GPP}
i8042.o:        $(S)/dev/input/i8042/i8042.cpp
    ${NORMAL_GPP}
pci.o:            $(S)/dev/bus/pci/pci.cpp
    ${NORMAL_GPP}
ohci.o:            $(S)/dev/bus/usb/ohci.cpp
    ${NORMAL_GPP}

驱动文件的编译。
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License