标签:
lab1 中的Makefile主要是根目录下的GNUMakefile, kern/Makefrag, boot/Makefrag,
后两者通过include直接包含到GNUMakefile中。
1 # 2 # This makefile system follows the structuring conventions 3 # recommended by Peter Miller in his excellent paper: 4 # 5 # Recursive Make Considered Harmful 6 # http://aegis.sourceforge.net/auug97.pdf 7 # 8 OBJDIR := obj 9
# 10-16行, 如果编译时使用make V=1,则会输出详细编译信息,否则输出类似 “CC MAIN”的简单信息
# 很多Makefile都采用这种方式, 包括Linux kernel. 10 # Run ‘make V=1‘ to turn on verbose commands, or ‘make V=0‘ to turn them off. 11 ifeq ($(V),1) 12 override V = 13 endif 14 ifeq ($(V),0) 15 override V = @ 16 endif 17 18 -include conf/lab.mk 19 20 -include conf/env.mk 21 22 LABSETUP ?= ./ 23 24 TOP = . 25 26 # Cross-compiler jos toolchain 27 # 28 # This Makefile will automatically use the cross-compiler toolchain 29 # installed as ‘i386-jos-elf-*‘, if one exists. If the host tools (‘gcc‘, 30 # ‘objdump‘, and so forth) compile for a 32-bit x86 ELF target, that will 31 # be detected as well. If you have the right compiler toolchain installed 32 # using a different name, set GCCPREFIX explicitly in conf/env.mk 33
# 34-48, 通过执行shell objdump 命令得到GCCPREFIX, 即如果 i386-jos-elf-objdump存在
# GCCPREFIX=i386-jos-elf-objdump, 否则GCCPREFIX="" 34 # try to infer the correct GCCPREFIX 35 ifndef GCCPREFIX 36 GCCPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep ‘^elf32-i386$$‘ >/dev/null 2>&1; 37 then echo ‘i386-jos-elf-‘; 38 elif objdump -i 2>&1 | grep ‘elf32-i386‘ >/dev/null 2>&1; 39 then echo ‘‘; 40 else echo "***" 1>&2; 41 echo "*** Error: Couldn‘t find an i386-*-elf version of GCC/binutils." 1>&2; 42 echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; 43 echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; 44 echo "*** prefix other than ‘i386-jos-elf-‘, set your GCCPREFIX" 1>&2; 45 echo "*** environment variable to that prefix and run ‘make‘ again." 1>&2; 46 echo "*** To turn off this error, run ‘gmake GCCPREFIX= ...‘." 1>&2; 47 echo "***" 1>&2; exit 1; fi) 48 endif 49
# 50-64, 和上面类似, 得到QEMU=qemu,或者QEMU=qemu-system-i386 50 # try to infer the correct QEMU 51 ifndef QEMU 52 QEMU := $(shell if which qemu > /dev/null; 53 then echo qemu; exit; 54 elif which qemu-system-i386 > /dev/null; 55 then echo qemu-system-i386; exit; 56 else 57 qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; 58 if test -x $$qemu; then echo $$qemu; exit; fi; fi; 59 echo "***" 1>&2; 60 echo "*** Error: Couldn‘t find a working QEMU executable." 1>&2; 61 echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; 62 echo "*** or have you tried setting the QEMU variable in conf/env.mk?" 1>&2; 63 echo "***" 1>&2; exit 1) 64 endif 65 66 # try to generate a unique GDB port 67 GDBPORT := $(shell expr `id -u` % 5000 + 25000) 68 69 CC := $(GCCPREFIX)gcc -pipe 70 AS := $(GCCPREFIX)as 71 AR := $(GCCPREFIX)ar 72 LD := $(GCCPREFIX)ld 73 OBJCOPY := $(GCCPREFIX)objcopy 74 OBJDUMP := $(GCCPREFIX)objdump 75 NM := $(GCCPREFIX)nm 76 77 # Native commands 78 NCC := gcc $(CC_VER) -pipe
# 79行, -I表示 include 包含路径, -M表示生成以来关系,比如:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
printf("Hello world\n");
return 0;
}
那么调用gcc -M hello.c, 则会得到类似如下输出:
hello.o: hello.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-32.h \
/usr/lib/gcc/i486-linux-gnu/4.3.5/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/i486-linux-gnu/4.3.5/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-MD的意思是将依赖关系保存在相应的.d文件. -Wall表示显示所有warning信息. 79 NATIVE_CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -I$(TOP) -MD -Wall 80 TAR := gtar 81 PERL := perl 82
# 83-91, -O1表示编译器优化级别, 一般有-O0(没有优化)/O1/O2/O3,
# -fno-buildin: 不接受没有 __builtin_ 前缀的函数作为内建函数。
# -W前缀表示Warning, -Werror:把warning当做error.
# -gstabs:生成汇编代码中包含stab格式的调试信息 83 # Compiler flags 84 # -fno-builtin is required to avoid refs to undefined functions in the kernel. 85 # Only optimize to -O1 to discourage inlining, which complicates backtraces. 86 CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -O1 -fno-builtin -I$(TOP) -MD 87 CFLAGS += -fno-omit-frame-pointer 88 CFLAGS += -Wall -Wno-format -Wno-unused -Werror -gstabs -m32 89 # -fno-tree-ch prevented gcc from sometimes reordering read_ebp() before 90 # mon_backtrace()‘s function prologue on gcc version: (Debian 4.7.2-5) 4.7.2 91 CFLAGS += -fno-tree-ch 92 93 # Add -fno-stack-protector if the option exists. 94 CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) 95
# 模拟器类型为i386 96 # Common linker flags 97 LDFLAGS := -m elf_i386 98 99 # Linker flags for JOS user programs 100 ULDFLAGS := -T user/user.ld 101 102 GCC_LIB := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) 103 104 # Lists that the */Makefrag makefile fragments will add to 105 OBJDIRS := 106 107 # Make sure that ‘all‘ is the first target
# 默认目标 108 all: 109 110 # Eliminate default suffix rules 111 .SUFFIXES: 112 113 # Delete target files if there is an error (or make is interrupted) 114 .DELETE_ON_ERROR: 115 116 # make it so that no intermediate .o files are ever deleted 117 .PRECIOUS: %.o $(OBJDIR)/boot/%.o $(OBJDIR)/kern/%.o 118 $(OBJDIR)/lib/%.o $(OBJDIR)/fs/%.o $(OBJDIR)/net/%.o 119 $(OBJDIR)/user/%.o 120 121 KERN_CFLAGS := $(CFLAGS) -DJOS_KERNEL -gstabs 122 USER_CFLAGS := $(CFLAGS) -DJOS_USER -gstabs 123 124 # Update .vars.X if variable X has changed since the last make run. 125 # 126 # Rules that use variable X should depend on $(OBJDIR)/.vars.X. If 127 # the variable‘s value has changed, this will update the vars file and 128 # force a rebuild of the rule that depends on it. 129 $(OBJDIR)/.vars.%: FORCE 130 $(V)echo "$($*)" | cmp -s $@ || echo "$($*)" > $@ 131 .PRECIOUS: $(OBJDIR)/.vars.% 132 .PHONY: FORCE 133 134
# 包含的两个makefile, 后续分析 135 # Include Makefrags for subdirectories 136 include boot/Makefrag 137 include kern/Makefrag 138 139
# QEMU执行参数 140 QEMUOPTS = -hda $(OBJDIR)/kern/kernel.img -serial mon:stdio -gdb tcp::$(GDBPORT) 141 QEMUOPTS += $(shell if $(QEMU) -nographic -help | grep -q ‘^-D ‘; then echo ‘-D qemu.log‘; fi) 142 IMAGES = $(OBJDIR)/kern/kernel.img 143 QEMUOPTS += $(QEMUEXTRA) 144
# sed 将 .gdbinit.teml中1234端口替换为GDBPORT导入.gdbinit中. 145 .gdbinit: .gdbinit.tmpl 146 sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@ 147 148 gdb: 149 gdb -x .gdbinit 150
# 以下为qemu启动命令. 151 pre-qemu: .gdbinit 152 153 qemu: $(IMAGES) pre-qemu 154 $(QEMU) $(QEMUOPTS) 155 156 qemu-nox: $(IMAGES) pre-qemu 157 @echo "***" 158 @echo "*** Use Ctrl-a x to exit qemu" 159 @echo "***" 160 $(QEMU) -nographic $(QEMUOPTS) 161 162 qemu-gdb: $(IMAGES) pre-qemu 163 @echo "***" 164 @echo "*** Now run ‘make gdb‘." 1>&2 165 @echo "***" 166 $(QEMU) $(QEMUOPTS) -S 167 168 qemu-nox-gdb: $(IMAGES) pre-qemu 169 @echo "***" 170 @echo "*** Now run ‘make gdb‘." 1>&2 171 @echo "***" 172 $(QEMU) -nographic $(QEMUOPTS) -S 173 174 print-qemu: 175 @echo $(QEMU) 176 177 print-gdbport: 178 @echo $(GDBPORT) 179
# clean, realclean, distclean依次向上依赖, 删除逐渐彻底,distclean回复成直接git下来时的状态. 180 # For deleting the build 181 clean: 182 rm -rf $(OBJDIR) .gdbinit jos.in qemu.log 183 184 realclean: clean 185 rm -rf lab$(LAB).tar.gz 186 jos.out $(wildcard jos.out.*) 187 qemu.pcap $(wildcard qemu.pcap.*) 188 myapi.key 189 190 distclean: realclean 191 rm -rf conf/gcc.mk 192 193 ifneq ($(V),@) 194 GRADEFLAGS += -v 195 endif 196 197 grade: 198 @echo $(MAKE) clean 199 @$(MAKE) clean || 200 (echo "‘make clean‘ failed. HINT: Do you have another running instance of JOS?" && exit 1) 201 ./grade-lab$(LAB) $(GRADEFLAGS) 202 203 git-handin: handin-check 204 @if test -n "`git config remote.handin.url`"; then 205 echo "Hand in to remote repository using ‘git push handin HEAD‘ ..."; 206 if ! git push -f handin HEAD; then 207 echo ; 208 echo "Hand in failed."; 209 echo "As an alternative, please run ‘make tarball‘"; 210 echo "and visit http://pdos.csail.mit.edu/6.828/submit/"; 211 echo "to upload lab$(LAB)-handin.tar.gz. Thanks!"; 212 false; 213 fi; 214 else 215 echo "Hand-in repository is not configured."; 216 echo "Please run ‘make handin-prep‘ first. Thanks!"; 217 false; 218 fi 219 220 WEBSUB = https://ccutler.scripts.mit.edu/6.828/handin.py 221 222 handin: tarball-pref myapi.key 223 @curl -f -F file=@lab$(LAB)-handin.tar.gz -F key=\<myapi.key $(WEBSUB)/upload 224 > /dev/null || { 225 echo ; 226 echo Submit seems to have failed.; 227 echo Please go to $(WEBSUB)/ and upload the tarball manually.; } 228 229 handin-check: 230 @if ! test -d .git; then 231 echo No .git directory, is this a git repository?; 232 false; 233 fi 234 @if test "$$(git symbolic-ref HEAD)" != refs/heads/lab$(LAB); then 235 git branch; 236 read -p "You are not on the lab$(LAB) branch. Hand-in the current branch? [y/N] " r; 237 test "$$r" = y; 238 fi 239 @if ! git diff-files --quiet || ! git diff-index --quiet --cached HEAD; then 240 git status; 241 echo; 242 echo "You have uncomitted changes. Please commit or stash them."; 243 false; 244 fi 245 @if test -n "`git ls-files -o --exclude-standard`"; then 246 git status; 247 read -p "Untracked files will not be handed in. Continue? [y/N] " r; 248 test "$$r" = y; 249 fi 250 251 tarball: handin-check 252 git archive --format=tar HEAD | gzip > lab$(LAB)-handin.tar.gz 253 254 tarball-pref: handin-check 255 git archive --prefix=lab$(LAB)/ --format=tar HEAD | gzip > lab$(LAB)-handin.tar.gz 256 257 myapi.key: 258 @echo Get an API key for yourself by visiting $(WEBSUB) 259 @read -p "Please enter your API key: " k; 260 if test `echo -n "$$k" |wc -c` = 32 ; then 261 TF=`mktemp -t tmp.XXXXXX`; 262 if test "x$$TF" != "x" ; then 263 echo -n "$$k" > $$TF; 264 mv -f $$TF $@; 265 else 266 echo mktemp failed; 267 false; 268 fi; 269 else 270 echo Bad API key: $$k; 271 echo An API key should be 32 characters long.; 272 false; 273 fi; 274 275 handin-prep: 276 @./handin-prep 277 278 279 # This magic automatically generates makefile dependencies 280 # for header files included from C source files we compile, 281 # and keeps those dependencies up-to-date every time we recompile. 282 # See ‘mergedep.pl‘ for more information. 283 $(OBJDIR)/.deps: $(foreach dir, $(OBJDIRS), $(wildcard $(OBJDIR)/$(dir)/*.d)) 284 @mkdir -p $(@D) 285 @$(PERL) mergedep.pl $@ $^ 286 287 -include $(OBJDIR)/.deps 288 289 always: 290 @: 291 292 .PHONY: all always 293 handin git-handin tarball tarball-pref clean realclean distclean grade handin-prep handin-check
kern/makefrag内容如下:
1 # 2 # Makefile fragment for JOS kernel. 3 # This is NOT a complete makefile; 4 # you must run GNU make in the top-level directory 5 # where the GNUmakefile is located. 6 # 7 8 OBJDIRS += kern 9 10 KERN_LDFLAGS := $(LDFLAGS) -T kern/kernel.ld -nostdlib 11 12 # entry.S must be first, so that it‘s the first code in the text segment!!! 13 # 14 # We also snatch the use of a couple handy source files 15 # from the lib directory, to avoid gratuitous code duplication.
# 需要编译的源文件. 16 KERN_SRCFILES := kern/entry.S 17 kern/entrypgdir.c 18 kern/init.c 19 kern/console.c 20 kern/monitor.c 21 kern/pmap.c 22 kern/env.c 23 kern/kclock.c 24 kern/picirq.c 25 kern/printf.c 26 kern/trap.c 27 kern/trapentry.S 28 kern/sched.c 29 kern/syscall.c 30 kern/kdebug.c 31 lib/printfmt.c 32 lib/readline.c 33 lib/string.c 34 35 # Only build files if they exist.
# wildcard:扩展通配符 36 KERN_SRCFILES := $(wildcard $(KERN_SRCFILES)) 37 38 # Binary program images to embed within the kernel. 39 KERN_BINFILES := 40 41 KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES)) 42 KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES)) 43 KERN_OBJFILES := $(patsubst $(OBJDIR)/lib/%, $(OBJDIR)/kern/%, $(KERN_OBJFILES)) 44 45 KERN_BINFILES := $(patsubst %, $(OBJDIR)/%, $(KERN_BINFILES)) 46 47 # How to build kernel object files
# 48-61,把kern下的.c和.S, lib/下的.c编译成.o 放在kern目录下
# V如果是 @ ,表示这句只执行不显示. 48 $(OBJDIR)/kern/%.o: kern/%.c $(OBJDIR)/.vars.KERN_CFLAGS 49 @echo + cc $< 50 @mkdir -p $(@D) 51 $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< 52 53 $(OBJDIR)/kern/%.o: kern/%.S $(OBJDIR)/.vars.KERN_CFLAGS 54 @echo + as $< 55 @mkdir -p $(@D) 56 $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< 57 58 $(OBJDIR)/kern/%.o: lib/%.c $(OBJDIR)/.vars.KERN_CFLAGS 59 @echo + cc $< 60 @mkdir -p $(@D) 61 $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< 62 63 # Special flags for kern/init 64 $(OBJDIR)/kern/init.o: override KERN_CFLAGS+=$(INIT_CFLAGS) 65 $(OBJDIR)/kern/init.o: $(OBJDIR)/.vars.INIT_CFLAGS 66 67 # How to build the kernel itself
# 71: 把编译产物用ld命令连接成kernel
# 72: 将kernel反汇编
# 73: 到处符号表 68 $(OBJDIR)/kern/kernel: $(KERN_OBJFILES) $(KERN_BINFILES) kern/kernel.ld 69 $(OBJDIR)/.vars.KERN_LDFLAGS 70 @echo + ld $@ 71 $(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(GCC_LIB) -b binary $(KERN_BINFILES) 72 $(V)$(OBJDUMP) -S $@ > $@.asm 73 $(V)$(NM) -n $@ > $@.sym 74 75 # How to build the kernel disk image
# 上面的kernel仅是elf文件, 此处将boot,kernel导成镜像. 76 $(OBJDIR)/kern/kernel.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot 77 @echo + mk $@ 78 $(V)dd if=/dev/zero of=$(OBJDIR)/kern/kernel.img~ count=10000 2>/dev/null 79 $(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/kernel.img~ conv=notrunc 2>/dev/null 80 $(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null 81 $(V)mv $(OBJDIR)/kern/kernel.img~ $(OBJDIR)/kern/kernel.img 82 83 all: $(OBJDIR)/kern/kernel.img 84 85 grub: $(OBJDIR)/jos-grub 86 87 $(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel 88 @echo + oc $@ 89 $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@
1 # 2 # Makefile fragment for the JOS kernel. 3 # This is NOT a complete makefile; 4 # you must run GNU make in the top-level directory 5 # where the GNUmakefile is located. 6 # 7 8 OBJDIRS += boot 9 10 BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o 11 12 $(OBJDIR)/boot/%.o: boot/%.c 13 @echo + cc -Os $< 14 @mkdir -p $(@D) 15 $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $< 16 17 $(OBJDIR)/boot/%.o: boot/%.S 18 @echo + as $< 19 @mkdir -p $(@D) 20 $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< 21 22 $(OBJDIR)/boot/main.o: boot/main.c 23 @echo + cc -Os $< 24 $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c 25
# 将目标文件连接成elf文件.
# -e start: 入口函数为start.
# -Ttext 0x7C00:代码段入口地址为0x7C00. BIOS加电自检后会自动跳到次地址来执行,相当于开机后软件第一条指令地址. 26 $(OBJDIR)/boot/boot: $(BOOT_OBJS) 27 @echo + ld boot/boot 28 $(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o $@.out $^ 29 $(V)$(OBJDUMP) -S $@.out >$@.asm 30 $(V)$(OBJCOPY) -S -O binary -j .text $@.out $@ 31 $(V)perl boot/sign.pl $(OBJDIR)/boot/boot
标签:
原文地址:http://www.cnblogs.com/ym65536/p/4254578.html