modules := pwd := $(shell pwd) packages := $(pwd)/packages build := $(pwd)/build config := $(pwd)/build INSTALL := $(pwd)/install # Check that we have a correct version of make LOCAL_MAKE_VERSION := $(shell $(MAKE) --version | head -1 | cut -d' ' -f3) include modules/make ifeq "$(LOCAL_MAKE_VERSION)" "$(make_version)" # We are running our own version of make, # proceed with the build. # Currently supported targets are x230, chell and qemu BOARD ?= qemu # If musl-libc is being used in the initrd, set the heads_cc # variable to point to it. musl_dep := musl heads_cc := $(INSTALL)/bin/musl-gcc \ -fdebug-prefix-map=$(pwd)=heads \ -gno-record-gcc-switches \ CROSS := $(pwd)/crossgcc/x86_64-linux-musl/bin/x86_64-musl-linux- #heads_cc := $(HOME)/install/x86_64-linux-musl/x86_64-linux-musl/bin/gcc all: $(BOARD).rom # Disable all built in rules .SUFFIXES: # Bring in all of the module definitions; # these are the external pieces that will be downloaded and built # as part of creating the Heads firmware image. include modules/* # These will be built via their intermediate targets # This increases the build time, so it is commented out for now #all: $(foreach m,$(modules),$m.intermediate) define prefix = $(foreach _, $2, $1$_) endef define bins = $(foreach m,$1,$(call prefix,$(build)/$($m_dir)/,$($m_output))) endef define libs = $(foreach m,$1,$(call prefix,$(build)/$($m_dir)/,$($m_libraries))) endef define outputs = $(foreach m,$1,\ $(call bins,$m)\ $(call libs,$m)\ ) endef # # Generate the targets for a module. # # Special variables like $@ must be written as $$@ to avoid # expansion during the first evaluation. # define define_module = ifneq ("$($1_repo)","") # Checkout the tree instead and touch the canary file so that we know # that the files are all present. No signature hashes are checked in # this case, since we don't have a stable version to compare against. $(build)/$($1_dir)/.canary: git clone "$($1_repo)" "$(build)/$($1_dir)" if [ -r patches/$1.patch ]; then \ ( cd $(build)/$($1_dir) ; patch -p1 ) \ < patches/$1.patch; \ fi touch "$$@" else # Fetch and verify the source tar file $(packages)/$($1_tar): wget -O "$$@" $($1_url) $(packages)/.$1_verify: $(packages)/$($1_tar) echo "$($1_hash) $$^" | sha256sum --check - touch "$$@" # Unpack the tar file and touch the canary so that we know # that the files are all present $(build)/$($1_dir)/.canary: $(packages)/.$1_verify tar -xf "$(packages)/$($1_tar)" -C "$(build)" if [ -r patches/$1-$($1_version).patch ]; then \ ( cd $(build)/$($1_dir) ; patch -p1 ) \ < patches/$1-$($1_version).patch; \ fi touch "$$@" endif ifeq "$($1_config)" "" # There is no official .config file $(build)/$($1_dir)/.config: $(build)/$($1_dir)/.canary touch "$$@" else # Copy the stored config file into the unpacked directory $(build)/$($1_dir)/.config: config/$($1_config) $(build)/$($1_dir)/.canary cp -a "$$<" "$$@" endif # Use the module's configure variable to build itself $(build)/$($1_dir)/.configured: \ $(build)/$($1_dir)/.canary \ $(build)/$($1_dir)/.config cd "$(build)/$($1_dir)" ; $($1_configure) touch "$$@" # Build the target after any dependencies $(call outputs,$1): $1.intermediate # Short hand target for the module #$1: $(call outputs,$1) # Target for all of the outputs, which depend on their dependent modules $1.intermediate: \ $(foreach d,$($1_depends),$(call outputs,$d)) \ $(foreach d,$($1_depends),$d.intermediate) \ $(build)/$($1_dir)/.configured $(MAKE) -C "$(build)/$($1_dir)" $($1_target) $1.clean: -$(RM) "$(build)/$($1_dir)/.configured" -$(MAKE) -C "$(build)/$($1_dir)" clean .INTERMEDIATE: $1.intermediate endef $(foreach _, $(modules), $(eval $(call define_module,$_))) initrd_lib_dir := initrd/lib initrd_bin_dir := initrd/bin # # Install a file into the initrd, if it changed from # the destination file. # define install = cmp --quiet "$1" "$2" || \ cp -a "$1" "$2" endef # # Files that should be copied into the initrd # THis should probably be done in a more scalable manner # define initrd_bin_add = $(initrd_bin_dir)/$(notdir $1): $1 @if [ ! -d "$(initrd_bin_dir)" ]; \ then mkdir -p "$(initrd_bin_dir)"; \ fi $(call install,$$<,$$@) initrd_bins += $(initrd_bin_dir)/$(notdir $1) endef define initrd_lib_add = $(initrd_lib_dir)/$(notdir $1): $1 @if [ ! -d "$(initrd_lib_dir)" ]; \ then mkdir -p "$(initrd_lib_dir)"; \ fi $(call install,$$<,$$@) initrd_libs += $(initrd_lib_dir)/$(notdir $1) endef $(foreach _, $(call bins,kexec), $(eval $(call initrd_bin_add,$_))) $(foreach _, $(call bins,tpmtotp), $(eval $(call initrd_bin_add,$_))) $(foreach _, $(call bins,cryptsetup), $(eval $(call initrd_bin_add,$_))) $(foreach _, $(call bins,gpg), $(eval $(call initrd_bin_add,$_))) $(foreach _, $(call bins,lvm2), $(eval $(call initrd_bin_add,$_))) $(foreach _, $(call libs,tpmtotp), $(eval $(call initrd_lib_add,$_))) $(foreach _, $(call libs,mbedtls), $(eval $(call initrd_lib_add,$_))) $(foreach _, $(call libs,qrencode), $(eval $(call initrd_lib_add,$_))) $(foreach _, $(call libs,lvm2), $(eval $(call initrd_lib_add,$_))) #$(foreach _, $(call outputs,xen), $(eval $(call initrd_bin,$_))) # hack to install busybox into the initrd initrd_bins += initrd/bin/busybox initrd/bin/busybox: $(build)/$(busybox_dir)/busybox cmp --quiet "$@" "$^" || \ $(MAKE) \ -C $(build)/$(busybox_dir) \ CC="$(heads_cc)" \ CONFIG_PREFIX="$(pwd)/initrd" \ -j 8 \ install # hack to build cbmem from coreboot # this must be built *AFTER* musl initrd_bins += initrd/bin/cbmem initrd/bin/cbmem: $(build)/$(coreboot_dir)/util/cbmem/cbmem cmp --quiet "$^" "$@" \ || cp "$^" "$@" $(build)/$(coreboot_dir)/util/cbmem/cbmem: \ $(build)/$(coreboot_dir)/.canary \ musl.intermediate $(MAKE) -C "$(dir $@)" CC="$(heads_cc)" # Update all of the libraries in the initrd based on the executables # that were installed. initrd_lib_install: $(initrd_bins) $(initrd_libs) -find initrd/bin -type f -a ! -name '*.sh' -print0 \ | xargs -0 $(CROSS)strip LD_LIBRARY_PATH="$(INSTALL)/lib" \ ./populate-lib \ $(initrd_lib_dir) \ initrd/bin/* \ initrd/sbin/* \ -$(CROSS)strip $(initrd_lib_dir)/* ; true # # initrd image creation # # The initrd is constructed from various bits and pieces # The cpio-clean program is used ensure that the files # always have the same timestamp and appear in the same order. # # If there is no /dev/console, initrd can't startup. # We have to force it to be included into the cpio image. # Since we are picking up the system's /dev/console, there # is a chance the build will not be reproducible (although # unlikely that their device file has a different major/minor) # # initrd.cpio: $(initrd_bins) $(initrd_libs) initrd_lib_install cd ./initrd ; \ ( \ echo "/dev" ; \ echo "/dev/console"; \ find . \ ) \ | cpio --quiet -H newc -o \ | ../cpio-clean \ > "../$@.tmp" if ! cmp --quiet "$@" "$@.tmp"; then \ mv "$@.tmp" "$@"; \ else \ echo "$@: Unchanged"; \ rm "$@.tmp"; \ fi initrd.intermediate: initrd.cpio # populate the coreboot initrd image from the one we built. # 4.4 doesn't allow this, but building from head does. $(call outputs,linux): initrd.cpio #$(call outputs,coreboot): $(build)/$(coreboot_dir)/initrd.cpio.xz $(build)/$(coreboot_dir)/initrd.cpio.xz: initrd.cpio xz --extreme < "$<" > "$@" # hack for the coreboot to find the linux kernel $(build)/$(coreboot_dir)/bzImage: $(call outputs,linux) cmp --quiet "$@" "$^" || \ cp -a "$^" "$@" $(call outputs,coreboot): $(build)/$(coreboot_dir)/bzImage # The coreboot gcc won't work for us since it doesn't have libc #XGCC := $(build)/$(coreboot_dir)/util/crossgcc/xgcc/ #export CC := $(XGCC)/bin/x86_64-elf-gcc #export LDFLAGS := -L/lib/x86_64-linux-gnu x230.rom: $(build)/$(coreboot_dir)/x230/coreboot.rom dd if="$<" of="$@" bs=1M skip=8 qemu.rom: $(build)/$(coreboot_dir)/qemu/coreboot.rom cp -a "$<" "$@" clean-modules: for dir in busybox-1.25.0 cryptsetup-1.7.3 gnupg-1.4.21 kexec-tools-2.0.12 libuuid-1.0.3 LVM2.2.02.168 mbedtls-2.3.0 popt-1.16 qrencode-3.4.4 tpmtotp-git ; do \ $(MAKE) -C build/$$dir clean; \ rm build/$$dir/.configured; \ done else # Wrong make version detected -- build our local version # and re-invoke the Makefile with it instead. $(info Wrong make detected: $(LOCAL_MAKE_VERSION)) HEADS_MAKE := $(build)/$(make_dir)/make # Once we have a proper Make, we can just pass arguments into it %: $(HEADS_MAKE) LANG=C MAKE=$(HEADS_MAKE) $(HEADS_MAKE) $@ all: # How to download and build the correct version of make $(HEADS_MAKE): $(build)/$(make_dir)/Makefile make -C "`dirname $@`" -j8 $(build)/$(make_dir)/Makefile: $(packages)/$(make_tar) tar xf "$<" -C build/ cd "`dirname $@`" ; ./configure $(packages)/$(make_tar): wget -O "$@" "$(make_url)" if ! echo "$(make_hash) $@" | sha256sum --check -; then \ $(MV) "$@" "$@.failed"; \ false; \ fi endif