342 lines
9.7 KiB
Makefile
342 lines
9.7 KiB
Makefile
#
|
|
# 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
|
|
GDB := $(GCCPREFIX)gdb
|
|
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 += -fno-pie
|
|
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
|
|
include lib/Makefrag
|
|
include user/Makefrag
|
|
include fs/Makefrag
|
|
|
|
|
|
CPUS ?= 1
|
|
|
|
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 += -smp $(CPUS)
|
|
QEMUOPTS += -drive file=$(OBJDIR)/fs/fs.img,index=1,media=disk,format=raw
|
|
IMAGES += $(OBJDIR)/fs/fs.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=\<myapi.key $(WEBSUB)/upload \
|
|
> /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
|
|
|
|
# For test runs
|
|
|
|
prep-%:
|
|
$(V)$(MAKE) "INIT_CFLAGS=${INIT_CFLAGS} -DTEST=`case $* in *_*) echo $*;; *) echo user_$*;; esac`" $(IMAGES)
|
|
|
|
run-%-nox-gdb: prep-% pre-qemu
|
|
$(QEMU) -nographic $(QEMUOPTS) -S
|
|
|
|
run-%-gdb: prep-% pre-qemu
|
|
$(QEMU) $(QEMUOPTS) -S
|
|
|
|
run-%-nox: prep-% pre-qemu
|
|
$(QEMU) -nographic $(QEMUOPTS)
|
|
|
|
run-%: prep-% pre-qemu
|
|
$(QEMU) $(QEMUOPTS)
|
|
|
|
# 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
|