《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

323 lines
8.3 KiB

12 years ago
  1. PROJ := 7
  2. EMPTY :=
  3. SPACE := $(EMPTY) $(EMPTY)
  4. SLASH := /
  5. V := @
  6. # try to infer the correct GCCPREFX
  7. ifndef GCCPREFIX
  8. GCCPREFIX := $(shell if i386-ucore-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
  9. then echo 'i386-ucore-elf-'; \
  10. elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
  11. then echo ''; \
  12. else echo "***" 1>&2; \
  13. echo "*** Error: Couldn't find an i386-ucore-elf version of GCC/binutils." 1>&2; \
  14. echo "*** Is the directory with i386-ucore-elf-gcc in your PATH?" 1>&2; \
  15. echo "*** If your i386-ucore-elf toolchain is installed with a command" 1>&2; \
  16. echo "*** prefix other than 'i386-ucore-elf-', set your GCCPREFIX" 1>&2; \
  17. echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
  18. echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \
  19. echo "***" 1>&2; exit 1; fi)
  20. endif
  21. # try to infer the correct QEMU
  22. ifndef QEMU
  23. QEMU := $(shell if which qemu > /dev/null; \
  24. then echo 'qemu'; exit; \
  25. elif which i386-ucore-elf-qemu > /dev/null; \
  26. then echo 'i386-ucore-elf-qemu'; exit; \
  27. else \
  28. echo "***" 1>&2; \
  29. echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
  30. echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
  31. echo "***" 1>&2; exit 1; fi)
  32. endif
  33. # eliminate default suffix rules
  34. .SUFFIXES: .c .S .h
  35. # delete target files if there is an error (or make is interrupted)
  36. .DELETE_ON_ERROR:
  37. # define compiler and flags
  38. HOSTCC := gcc
  39. HOSTCFLAGS := -g -Wall -O2
  40. GDB := $(GCCPREFIX)gdb
  41. CC ?= $(GCCPREFIX)gcc
  42. CFLAGS := -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS)
  43. CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
  44. CTYPE := c S
  45. LD := $(GCCPREFIX)ld
  46. LDFLAGS := -m $(shell $(LD) -V | grep elf_i386 2>/dev/null)
  47. LDFLAGS += -nostdlib
  48. OBJCOPY := $(GCCPREFIX)objcopy
  49. OBJDUMP := $(GCCPREFIX)objdump
  50. COPY := cp
  51. MKDIR := mkdir -p
  52. MV := mv
  53. RM := rm -f
  54. AWK := awk
  55. SED := sed
  56. SH := sh
  57. TR := tr
  58. TOUCH := touch -c
  59. OBJDIR := obj
  60. BINDIR := bin
  61. ALLOBJS :=
  62. ALLDEPS :=
  63. TARGETS :=
  64. include tools/function.mk
  65. listf_cc = $(call listf,$(1),$(CTYPE))
  66. USER_PREFIX := __user_
  67. # for cc
  68. add_files_cc = $(call add_files,$(1),$(CC),$(CFLAGS) $(3),$(2),$(4))
  69. create_target_cc = $(call create_target,$(1),$(2),$(3),$(CC),$(CFLAGS))
  70. # for hostcc
  71. add_files_host = $(call add_files,$(1),$(HOSTCC),$(HOSTCFLAGS),$(2),$(3))
  72. create_target_host = $(call create_target,$(1),$(2),$(3),$(HOSTCC),$(HOSTCFLAGS))
  73. cgtype = $(patsubst %.$(2),%.$(3),$(1))
  74. objfile = $(call toobj,$(1))
  75. asmfile = $(call cgtype,$(call toobj,$(1)),o,asm)
  76. outfile = $(call cgtype,$(call toobj,$(1)),o,out)
  77. symfile = $(call cgtype,$(call toobj,$(1)),o,sym)
  78. filename = $(basename $(notdir $(1)))
  79. ubinfile = $(call outfile,$(addprefix $(USER_PREFIX),$(call filename,$(1))))
  80. # for match pattern
  81. match = $(shell echo $(2) | $(AWK) '{for(i=1;i<=NF;i++){if(match("$(1)","^"$$(i)"$$")){exit 1;}}}'; echo $$?)
  82. # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  83. # include kernel/user
  84. INCLUDE += libs/
  85. CFLAGS += $(addprefix -I,$(INCLUDE))
  86. LIBDIR += libs
  87. $(call add_files_cc,$(call listf_cc,$(LIBDIR)),libs,)
  88. # -------------------------------------------------------------------
  89. # user programs
  90. UINCLUDE += user/include/ \
  91. user/libs/
  92. USRCDIR += user
  93. ULIBDIR += user/libs
  94. UCFLAGS += $(addprefix -I,$(UINCLUDE))
  95. USER_BINS :=
  96. $(call add_files_cc,$(call listf_cc,$(ULIBDIR)),ulibs,$(UCFLAGS))
  97. $(call add_files_cc,$(call listf_cc,$(USRCDIR)),uprog,$(UCFLAGS))
  98. UOBJS := $(call read_packet,ulibs libs)
  99. define uprog_ld
  100. __user_bin__ := $$(call ubinfile,$(1))
  101. USER_BINS += $$(__user_bin__)
  102. $$(__user_bin__): tools/user.ld
  103. $$(__user_bin__): $$(UOBJS)
  104. $$(__user_bin__): $(1) | $$$$(dir $$$$@)
  105. $(V)$(LD) $(LDFLAGS) -T tools/user.ld -o $$@ $$(UOBJS) $(1)
  106. @$(OBJDUMP) -S $$@ > $$(call cgtype,$$<,o,asm)
  107. @$(OBJDUMP) -t $$@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$$$/d' > $$(call cgtype,$$<,o,sym)
  108. endef
  109. $(foreach p,$(call read_packet,uprog),$(eval $(call uprog_ld,$(p))))
  110. # -------------------------------------------------------------------
  111. # kernel
  112. KINCLUDE += kern/debug/ \
  113. kern/driver/ \
  114. kern/trap/ \
  115. kern/mm/ \
  116. kern/libs/ \
  117. kern/sync/ \
  118. kern/fs/ \
  119. kern/process \
  120. kern/schedule \
  121. kern/syscall
  122. KSRCDIR += kern/init \
  123. kern/libs \
  124. kern/debug \
  125. kern/driver \
  126. kern/trap \
  127. kern/mm \
  128. kern/sync \
  129. kern/fs \
  130. kern/process \
  131. kern/schedule \
  132. kern/syscall
  133. KCFLAGS += $(addprefix -I,$(KINCLUDE))
  134. $(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))
  135. KOBJS = $(call read_packet,kernel libs)
  136. # create kernel target
  137. kernel = $(call totarget,kernel)
  138. $(kernel): tools/kernel.ld
  139. $(kernel): $(KOBJS) $(USER_BINS)
  140. @echo + ld $@
  141. $(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS) -b binary $(USER_BINS)
  142. @$(OBJDUMP) -S $@ > $(call asmfile,kernel)
  143. @$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel)
  144. $(call create_target,kernel)
  145. # -------------------------------------------------------------------
  146. # create bootblock
  147. bootfiles = $(call listf_cc,boot)
  148. $(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))
  149. bootblock = $(call totarget,bootblock)
  150. $(bootblock): $(call toobj,boot/bootasm.S) $(call toobj,$(bootfiles)) | $(call totarget,sign)
  151. @echo + ld $@
  152. $(V)$(LD) $(LDFLAGS) -N -T tools/boot.ld $^ -o $(call toobj,bootblock)
  153. @$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
  154. @$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
  155. @$(call totarget,sign) $(call outfile,bootblock) $(bootblock)
  156. $(call create_target,bootblock)
  157. # -------------------------------------------------------------------
  158. # create 'sign' tools
  159. $(call add_files_host,tools/sign.c,sign,sign)
  160. $(call create_target_host,sign,sign)
  161. # -------------------------------------------------------------------
  162. # create ucore.img
  163. UCOREIMG := $(call totarget,ucore.img)
  164. $(UCOREIMG): $(kernel) $(bootblock)
  165. $(V)dd if=/dev/zero of=$@ count=10000
  166. $(V)dd if=$(bootblock) of=$@ conv=notrunc
  167. $(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc
  168. $(call create_target,ucore.img)
  169. # -------------------------------------------------------------------
  170. # create swap.img
  171. SWAPIMG := $(call totarget,swap.img)
  172. $(SWAPIMG):
  173. $(V)dd if=/dev/zero of=$@ bs=1M count=128
  174. $(call create_target,swap.img)
  175. # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  176. $(call finish_all)
  177. IGNORE_ALLDEPS = clean \
  178. dist-clean \
  179. grade \
  180. touch \
  181. print-.+ \
  182. run-.+ \
  183. build-.+ \
  184. handin
  185. ifeq ($(call match,$(MAKECMDGOALS),$(IGNORE_ALLDEPS)),0)
  186. -include $(ALLDEPS)
  187. endif
  188. # files for grade script
  189. TARGETS: $(TARGETS)
  190. .DEFAULT_GOAL := TARGETS
  191. QEMUOPTS = -hda $(UCOREIMG) -drive file=$(SWAPIMG),media=disk,cache=writeback
  192. .PHONY: qemu qemu-nox debug debug-nox
  193. qemu: $(UCOREIMG) $(SWAPIMG)
  194. $(V)$(QEMU) -parallel stdio $(QEMUOPTS) -serial null
  195. qemu-nox: $(UCOREIMG) $(SWAPIMG)
  196. $(V)$(QEMU) -serial mon:stdio $(QEMUOPTS) -nographic
  197. TERMINAL := gnome-terminal
  198. debug: $(UCOREIMG) $(SWAPIMG)
  199. $(V)$(QEMU) -S -s -parallel stdio $(QEMUOPTS) -serial null &
  200. $(V)sleep 2
  201. $(V)$(TERMINAL) -e "$(GDB) -q -x tools/gdbinit"
  202. debug-nox: $(UCOREIMG) $(SWAPIMG)
  203. $(V)$(QEMU) -S -s -serial mon:stdio $(QEMUOPTS) -nographic &
  204. $(V)sleep 2
  205. $(V)$(TERMINAL) -e "$(GDB) -q -x tools/gdbinit"
  206. RUN_PREFIX := _binary_$(OBJDIR)_$(USER_PREFIX)
  207. MAKEOPTS := --quiet --no-print-directory
  208. run-%: build-%
  209. $(V)$(QEMU) -parallel stdio $(QEMUOPTS) -serial null
  210. build-%: touch
  211. $(V)$(MAKE) $(MAKEOPTS) "DEFS+=-DTEST=$* -DTESTSTART=$(RUN_PREFIX)$*_out_start -DTESTSIZE=$(RUN_PREFIX)$*_out_size"
  212. .PHONY: grade touch
  213. GRADE_GDB_IN := .gdb.in
  214. GRADE_QEMU_OUT := .qemu.out
  215. HANDIN := lab$(PROJ)-handin.tar.gz
  216. TOUCH_FILES := kern/process/proc.c
  217. MAKEOPTS := --quiet --no-print-directory
  218. grade:
  219. $(V)$(MAKE) $(MAKEOPTS) clean
  220. $(V)$(SH) tools/grade.sh
  221. touch:
  222. $(V)$(foreach f,$(TOUCH_FILES),$(TOUCH) $(f))
  223. print-%:
  224. @echo $($(shell echo $(patsubst print-%,%,$@) | $(TR) [a-z] [A-Z]))
  225. .PHONY: clean dist-clean handin packall
  226. clean:
  227. $(V)$(RM) $(GRADE_GDB_IN) $(GRADE_QEMU_OUT)
  228. -$(RM) -r $(OBJDIR) $(BINDIR)
  229. dist-clean: clean
  230. -$(RM) $(HANDIN)
  231. handin: packall
  232. @echo Please visit http://learn.tsinghua.edu.cn and upload $(HANDIN). Thanks!
  233. packall: clean
  234. @$(RM) -f $(HANDIN)
  235. @tar -czf $(HANDIN) `find . -type f -o -type d | grep -v '^\.*$$' | grep -vF '$(HANDIN)'`