# # This makefile system follows the structuring conventions # recommended by Peter Miller in his excellent paper: # # Recursive Make Considered Harmful # http://aegis.sourceforge.net/auug97.pdf # OBJDIR := obj # Run 'make V=1' to turn on verbose commands, or 'make V=0' to turn them off. ifeq ($(V),1) override V = endif ifeq ($(V),0) override V = @ endif -include conf/lab.mk -include conf/env.mk LABSETUP ?= ./ TOP = . # Cross-compiler jos toolchain # # This Makefile will automatically use the cross-compiler toolchain # installed as 'i386-jos-elf-*', if one exists. If the host tools ('gcc', # 'objdump', and so forth) compile for a 32-bit x86 ELF target, that will # be detected as well. If you have the right compiler toolchain installed # using a different name, set GCCPREFIX explicitly in conf/env.mk # try to infer the correct GCCPREFIX ifndef GCCPREFIX GCCPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \ then echo 'i386-jos-elf-'; \ elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \ then echo ''; \ else echo "***" 1>&2; \ echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \ echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \ echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \ echo "*** prefix other than 'i386-jos-elf-', set your GCCPREFIX" 1>&2; \ echo "*** environment variable to that prefix and run 'make' again." 1>&2; \ echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \ echo "***" 1>&2; exit 1; fi) endif # try to infer the correct QEMU ifndef QEMU QEMU := $(shell if which qemu >/dev/null 2>&1; \ then echo qemu; exit; \ elif which qemu-system-i386 >/dev/null 2>&1; \ then echo qemu-system-i386; exit; \ else \ qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \ if test -x $$qemu; then echo $$qemu; exit; fi; fi; \ echo "***" 1>&2; \ echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \ echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \ echo "*** or have you tried setting the QEMU variable in conf/env.mk?" 1>&2; \ echo "***" 1>&2; exit 1) endif # try to generate a unique GDB port GDBPORT := $(shell expr `id -u` % 5000 + 25000) CC := $(GCCPREFIX)gcc -pipe AS := $(GCCPREFIX)as AR := $(GCCPREFIX)ar LD := $(GCCPREFIX)ld OBJCOPY := $(GCCPREFIX)objcopy OBJDUMP := $(GCCPREFIX)objdump NM := $(GCCPREFIX)nm # Native commands NCC := gcc $(CC_VER) -pipe NATIVE_CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -I$(TOP) -MD -Wall TAR := gtar PERL := perl # Compiler flags # -fno-builtin is required to avoid refs to undefined functions in the kernel. # Only optimize to -O1 to discourage inlining, which complicates backtraces. CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -O1 -fno-builtin -I$(TOP) -MD CFLAGS += -fno-omit-frame-pointer CFLAGS += -std=gnu99 CFLAGS += -static CFLAGS += -Wall -Wno-format -Wno-unused -Werror -gstabs -m32 # -fno-tree-ch prevented gcc from sometimes reordering read_ebp() before # mon_backtrace()'s function prologue on gcc version: (Debian 4.7.2-5) 4.7.2 CFLAGS += -fno-tree-ch # Add -fno-stack-protector if the option exists. CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) # Common linker flags LDFLAGS := -m elf_i386 # Linker flags for JOS user programs ULDFLAGS := -T user/user.ld GCC_LIB := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) # Lists that the */Makefrag makefile fragments will add to OBJDIRS := # Make sure that 'all' is the first target all: # Eliminate default suffix rules .SUFFIXES: # Delete target files if there is an error (or make is interrupted) .DELETE_ON_ERROR: # make it so that no intermediate .o files are ever deleted .PRECIOUS: %.o $(OBJDIR)/boot/%.o $(OBJDIR)/kern/%.o \ $(OBJDIR)/lib/%.o $(OBJDIR)/fs/%.o $(OBJDIR)/net/%.o \ $(OBJDIR)/user/%.o KERN_CFLAGS := $(CFLAGS) -DJOS_KERNEL -gstabs USER_CFLAGS := $(CFLAGS) -DJOS_USER -gstabs # Update .vars.X if variable X has changed since the last make run. # # Rules that use variable X should depend on $(OBJDIR)/.vars.X. If # the variable's value has changed, this will update the vars file and # force a rebuild of the rule that depends on it. $(OBJDIR)/.vars.%: FORCE $(V)echo "$($*)" | cmp -s $@ || echo "$($*)" > $@ .PRECIOUS: $(OBJDIR)/.vars.% .PHONY: FORCE # Include Makefrags for subdirectories include boot/Makefrag include kern/Makefrag QEMUOPTS = -drive file=$(OBJDIR)/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::$(GDBPORT) QEMUOPTS += $(shell if $(QEMU) -nographic -help | grep -q '^-D '; then echo '-D qemu.log'; fi) IMAGES = $(OBJDIR)/kern/kernel.img QEMUOPTS += $(QEMUEXTRA) .gdbinit: .gdbinit.tmpl sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@ gdb: gdb -n -x .gdbinit pre-qemu: .gdbinit qemu: $(IMAGES) pre-qemu $(QEMU) $(QEMUOPTS) qemu-nox: $(IMAGES) pre-qemu @echo "***" @echo "*** Use Ctrl-a x to exit qemu" @echo "***" $(QEMU) -nographic $(QEMUOPTS) qemu-gdb: $(IMAGES) pre-qemu @echo "***" @echo "*** Now run 'make gdb'." 1>&2 @echo "***" $(QEMU) $(QEMUOPTS) -S qemu-nox-gdb: $(IMAGES) pre-qemu @echo "***" @echo "*** Now run 'make gdb'." 1>&2 @echo "***" $(QEMU) -nographic $(QEMUOPTS) -S print-qemu: @echo $(QEMU) print-gdbport: @echo $(GDBPORT) # For deleting the build clean: rm -rf $(OBJDIR) .gdbinit jos.in qemu.log realclean: clean rm -rf lab$(LAB).tar.gz \ jos.out $(wildcard jos.out.*) \ qemu.pcap $(wildcard qemu.pcap.*) \ myapi.key distclean: realclean rm -rf conf/gcc.mk ifneq ($(V),@) GRADEFLAGS += -v endif grade: @echo $(MAKE) clean @$(MAKE) clean || \ (echo "'make clean' failed. HINT: Do you have another running instance of JOS?" && exit 1) ./grade-lab$(LAB) $(GRADEFLAGS) git-handin: handin-check @if test -n "`git config remote.handin.url`"; then \ echo "Hand in to remote repository using 'git push handin HEAD' ..."; \ if ! git push -f handin HEAD; then \ echo ; \ echo "Hand in failed."; \ echo "As an alternative, please run 'make tarball'"; \ echo "and visit http://pdos.csail.mit.edu/6.828/submit/"; \ echo "to upload lab$(LAB)-handin.tar.gz. Thanks!"; \ false; \ fi; \ else \ echo "Hand-in repository is not configured."; \ echo "Please run 'make handin-prep' first. Thanks!"; \ false; \ fi WEBSUB := https://6828.scripts.mit.edu/2018/handin.py handin: tarball-pref myapi.key @SUF=$(LAB); \ test -f .suf && SUF=`cat .suf`; \ curl -f -F file=@lab$$SUF-handin.tar.gz -F key=\ /dev/null || { \ echo ; \ echo Submit seems to have failed.; \ echo Please go to $(WEBSUB)/ and upload the tarball manually.; } handin-check: @if ! test -d .git; then \ echo No .git directory, is this a git repository?; \ false; \ fi @if test "$$(git symbolic-ref HEAD)" != refs/heads/lab$(LAB); then \ git branch; \ read -p "You are not on the lab$(LAB) branch. Hand-in the current branch? [y/N] " r; \ test "$$r" = y; \ fi @if ! git diff-files --quiet || ! git diff-index --quiet --cached HEAD; then \ git status -s; \ echo; \ echo "You have uncomitted changes. Please commit or stash them."; \ false; \ fi @if test -n "`git status -s`"; then \ git status -s; \ read -p "Untracked files will not be handed in. Continue? [y/N] " r; \ test "$$r" = y; \ fi UPSTREAM := $(shell git remote -v | grep "pdos.csail.mit.edu/6.828/2018/jos.git (fetch)" | awk '{split($$0,a," "); print a[1]}') tarball-pref: handin-check @SUF=$(LAB); \ if test $(LAB) -eq 3 -o $(LAB) -eq 4; then \ read -p "Which part would you like to submit? [a, b, c (c for lab 4 only)]" p; \ if test "$$p" != a -a "$$p" != b; then \ if test ! $(LAB) -eq 4 -o ! "$$p" = c; then \ echo "Bad part \"$$p\""; \ exit 1; \ fi; \ fi; \ SUF="$(LAB)$$p"; \ echo $$SUF > .suf; \ else \ rm -f .suf; \ fi; \ git archive --format=tar HEAD > lab$$SUF-handin.tar; \ git diff $(UPSTREAM)/lab$(LAB) > /tmp/lab$$SUF-diff.patch; \ tar -rf lab$$SUF-handin.tar /tmp/lab$$SUF-diff.patch; \ gzip -c lab$$SUF-handin.tar > lab$$SUF-handin.tar.gz; \ rm lab$$SUF-handin.tar; \ rm /tmp/lab$$SUF-diff.patch; \ myapi.key: @echo Get an API key for yourself by visiting $(WEBSUB)/ @read -p "Please enter your API key: " k; \ if test `echo "$$k" |tr -d '\n' |wc -c` = 32 ; then \ TF=`mktemp -t tmp.XXXXXX`; \ if test "x$$TF" != "x" ; then \ echo "$$k" |tr -d '\n' > $$TF; \ mv -f $$TF $@; \ else \ echo mktemp failed; \ false; \ fi; \ else \ echo Bad API key: $$k; \ echo An API key should be 32 characters long.; \ false; \ fi; #handin-prep: # @./handin-prep # This magic automatically generates makefile dependencies # for header files included from C source files we compile, # and keeps those dependencies up-to-date every time we recompile. # See 'mergedep.pl' for more information. $(OBJDIR)/.deps: $(foreach dir, $(OBJDIRS), $(wildcard $(OBJDIR)/$(dir)/*.d)) @mkdir -p $(@D) @$(PERL) mergedep.pl $@ $^ -include $(OBJDIR)/.deps always: @: .PHONY: all always \ handin git-handin tarball tarball-pref clean realclean distclean grade handin-prep handin-check