| # -*- makefile -*- |
| # vim: set filetype=make : |
| # Copyright 2012 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| # |
| # Embedded Controller firmware build system - common targets |
| # |
| |
| BUILD_DIR := $(firstword $(subst /, ,$(out))) |
| |
| # Don't do a build test on the following boards: |
| skip_boards = OWNERS cr50 host |
| boards := $(filter-out $(skip_boards), \ |
| $(notdir $(wildcard board/* ../private*/board/*))) |
| |
| # Create output directories if necessary |
| _common_dir_create := $(foreach d,$(common_dirs) $(common-dirs-y),\ |
| $(shell [ -d $(out)/$(d) ] || mkdir -p $(out)/$(d))) |
| _sharedlib_dir_create := $(foreach d,$(dirs),$(shell \ |
| [ -d $(out)/$(SHOBJLIB)/$(d) ] || mkdir -p $(out)/$(SHOBJLIB)/$(d))) |
| _dir_create := $(foreach d,$(dirs) $(dirs-y),\ |
| $(shell [ -d $(out)/$(BLD)/$(d) ] || mkdir -p $(out)/RO/$(d); \ |
| mkdir -p $(out)/RW/$(d))) |
| |
| # V unset for normal output, V=1 for verbose output, V=0 for silent build |
| # (warnings/errors only). Use echo thus: $(call echo,"stuff to echo") |
| # Note: if cmd_* includes a $(MAKE) invocation, use the '+' prefix |
| # to inherit parallel make execution: "+$(call quiet,...)" |
| ifeq ($(V),0) |
| # V=0 |
| Q := @ |
| echo = echo -n; |
| quiet = echo -n; $(cmd_$(1)) |
| silent = 1>/dev/null |
| silent_err = 2>/dev/null |
| MAKEFLAGS += --no-print-directory |
| else ifeq ($(V),) |
| # V= |
| Q := @ |
| echo = echo $(1); |
| echo-cmd = $(if $(quiet_cmd_$(1)), \ |
| $(quiet_cmd_$(1)), \ |
| $(2) $(patsubst $(out)/%,%,$@)) |
| quiet = @echo ' $(echo-cmd)' ; $(cmd_$(1)) |
| silent = 1>/dev/null |
| silent_err = 2>/dev/null |
| MAKEFLAGS += --no-print-directory |
| else |
| # V=* |
| Q := |
| echo = echo $(1); |
| quiet = $(cmd_$(1)) |
| endif |
| |
| # Provide an option to use a consistent ec_version.h file when |
| # compiling, which is useful to verify that a commit does not modify |
| # the resulting ec.bin |
| export STATIC_VERSION |
| |
| # Commonly used compiler options used in these scripts |
| # |
| # -MT explicitly sets target file name in generated .d files to work around |
| # a ccache issue. |
| |
| # commands to build all targets |
| cmd_exe = $(CXX) $(ro-objs) $(HOST_TEST_LDFLAGS) $(LDFLAGS_EXTRA) -o $@ |
| cmd_c_to_o = $(CC) -std=gnu11 $(C_WARN) $(C_WARN-$(CROSS_COMPILE_CC_NAME)) \ |
| $(CFLAGS) -MMD -MP -MF $@.d -c $< \ |
| -MT $(@D)/$(@F) -o $(@D)/$(@F) |
| cmd_c_to_s = $(CC) -S $(C_WARN) $(CFLAGS) $(C_WARN-$(CROSS_COMPILE_CC_NAME)) \ |
| -fno-lto -MMD -MP -MF $@.d -c $< \ |
| -MT $(@D)/$(@F) -o $(@D)/$(@F) |
| cmd_cxx_to_o = $(CXX) -std=gnu++2a $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $@.d \ |
| -c $< -MT $(@D)/$(@F) -o $(@D)/$(@F) |
| cmd_c_to_host = $(HOSTCC) $(HOST_CFLAGS) -MMD -MF $@.d -MT $@ -o $@ \ |
| $(sort $(foreach c,$($(*F)-objs),util/$(c:%.o=%.c)) $(wildcard $*.c)) $(HOST_LDFLAGS) |
| cmd_cxx_to_host = $(HOSTCXX) -std=gnu++2a $(HOST_CXXFLAGS) \ |
| -MMD -MF $@.d -MT $@ -o $@ \ |
| $(sort $(foreach c,$($(*F)-objs),util/$(c:%.o=%.cc)) $(wildcard $*.cc)) $(HOST_LDFLAGS) |
| cmd_o_to_a = $(AR) rcs $@ $^ |
| cmd_host_test = $(MAKE) BOARD=host PROJECT=$* \ |
| V=$(V) out=build/host/$* TEST_BUILD=y EMU_BUILD=y \ |
| $(if $(TEST_SCRIPT),TEST_SCRIPT=$(TEST_SCRIPT)) $(TEST_FLAG) \ |
| build/host/$*/$*.exe |
| cmd_coverage_test = $(subst build/host,build/coverage,$(cmd_host_test)) |
| cmd_run_host_test = ./util/run_host_test $* $(silent) |
| cmd_run_coverage_test = ./util/run_host_test --coverage $* $(silent) |
| # generate new version.h, compare if it changed and replace if so |
| cmd_version = ./util/getversion.sh > $@.tmp && \ |
| cmp -s $@.tmp $@ && rm -f $@.tmp || mv $@.tmp $@ |
| cmd_mv_from_tmp = mv $(out)/$*.bin.tmp $(out)/$*.bin |
| cmd_copyrw-y = cd $(out) && cp RW/$(PROJECT).RW.flat RW/$(PROJECT).RW.bin |
| |
| cmd_cp_script = cp "$<" "$@" && chmod +x "$@" |
| |
| # If outputing to tty and column command exists, pipe into column. |
| # Otherwise, print in newline format. |
| cmd_pretty_print_cmd = @$(1) \ |
| | { [ -t 1 ] \ |
| && which column 1>/dev/null 2>&1 \ |
| && column || cat ; } |
| cmd_pretty_print_list = $(call cmd_pretty_print_cmd,echo $(1) | tr ' ' '\n') |
| |
| # By default, the "build_boards" and "try_build_boards" targets will build all |
| # of the boards listed in $(boards). However, the invoker can provide a |
| # different list via the BOARDS variable. Providing an empty value for BOARDS |
| # is not allowed. |
| BOARDS ?= $(boards) |
| ifeq ($(BOARDS),) |
| $(error BOARDS must be non-empty) |
| endif |
| |
| FAILED_BOARDS_DIR = .failedboards |
| |
| tests-%: |
| @echo "======= building $* tests" |
| $(MAKE) BOARD=$* V=$(V) tests |
| |
| .PHONY: utils-host |
| ifeq ($(BOARD),host) |
| utils-host: $(host-utils) $(host-utils-cxx) |
| else |
| utils-host: |
| $(error Building utils-host not supported when BOARD is not "host") |
| endif |
| |
| # On board test binaries |
| test-targets=$(foreach t,$(test-list-y),test-$(t)) |
| .PHONY: $(test-targets) |
| |
| ifeq "$(CONFIG_COMMON_RUNTIME)" "y" |
| $(test-targets): test-%: |
| @set -e ; \ |
| $(call echo," BUILD $(out)/$*") \ |
| $(MAKE) BOARD=$(BOARD) PROJECT=$* \ |
| V=$(V) out=$(out)/$* TEST_BUILD=y; \ |
| cp $(out)/$*/$*.bin $(out)/test-$*.bin |
| endif |
| |
| .PHONY: tests |
| tests: $(test-targets) |
| |
| .PHONY: print-tests |
| print-tests: |
| $(call cmd_pretty_print_list, \ |
| $(sort $(test-targets))) |
| |
| # Emulator test executables |
| host-test-targets=$(foreach t,$(test-list-host),host-$(t)) |
| run-test-targets=$(foreach t,$(test-list-host),run-$(t)) |
| .PHONY: $(host-test-targets) $(run-test-targets) |
| |
| $(host-test-targets): host-%: | $(FAILED_BOARDS_DIR) |
| @touch $(FAILED_BOARDS_DIR)/test-$* |
| +$(call quiet,host_test,BUILD ) |
| |
| $(run-test-targets): run-%: host-% |
| $(call quiet,run_host_test,TEST ) |
| @rm -f $(FAILED_BOARDS_DIR)/test-$* |
| |
| host-coverage-targets=$(foreach t,$(test-list-host),host-coverage-$(t)) |
| run-coverage-targets=$(foreach t,$(test-list-host),run-coverage-$(t)) |
| .PHONY: $(host-coverage-targets) $(run-coverage-targets) |
| |
| $(host-coverage-targets): host-coverage-%: | $(FAILED_BOARDS_DIR) |
| @touch $(FAILED_BOARDS_DIR)/test-$* |
| +$(call quiet,coverage_test,BUILD ) |
| |
| $(run-coverage-targets): run-coverage-%: host-coverage-% |
| $(call quiet,run_coverage_test,TEST ) |
| @rm -f $(FAILED_BOARDS_DIR)/test-$* |
| |
| .PHONY: print-host-tests |
| print-host-tests: |
| $(call cmd_pretty_print_list, \ |
| $(sort $(host-test-targets) $(run-test-targets))) |
| |
| $(FAILED_BOARDS_DIR): |
| @mkdir $(FAILED_BOARDS_DIR) |
| |
| cov-test-targets=$(foreach t,$(cov-test-list-host),build/coverage/$(t).info) |
| bldversion=$(shell (./util/getversion.sh ; echo VERSION) | $(CPP) -P -) |
| |
| cmd_lcov=lcov --rc branch_coverage=1 --gcov-tool \ |
| $(HOSTGCOV) -q -o $@ -c -d build/coverage/$* -t $* \ |
| --exclude '*/ec/test/*' --exclude '*/ec/include/tests/*' \ |
| --exclude '*/ec/common/mock/*' \ |
| --ignore-errors unused,unused,inconsistent,inconsistent \ |
| --ignore-errors negative,negative |
| cmd_merge_cov=lcov --rc branch_coverage=1 -o build/coverage/lcov.info \ |
| $(foreach info,$^,-a ${info}) |
| |
| .DELETE_ON_ERROR: build/coverage/%.info |
| build/coverage/%.info: run-coverage-% |
| $(call quiet,lcov,COV ) |
| |
| .PHONY: test-coverage |
| test-coverage: TEST_FLAG=TEST_COVERAGE=y |
| test-coverage: $(cov-test-targets) |
| $(call quiet,merge_cov,MERGE ) |
| |
| $(out)/%.bin: $(out)/%.obj |
| $(call quiet,obj_to_bin,OBJCOPY) |
| $(call quiet,copyrw-y,COPY_RW) |
| $(call quiet,mv_from_tmp,MV ) |
| |
| flat-y := $(out)/RW/$(PROJECT).RW.flat |
| flat-$(CONFIG_FW_INCLUDE_RO) += $(out)/RO/$(PROJECT).RO.flat |
| |
| flat-$(CONFIG_DRAM_BASE) += $(out)/RW/$(PROJECT).RW.flat.dram |
| |
| flat-$(CONFIG_SHAREDLIB) += $(libsharedobjs-y) |
| |
| ifneq ($(TEST_SCRIPT),) |
| $(out)/$(PROJECT).exe: test/$(TEST_SCRIPT) | $(ro-objs) |
| $(call quiet,cp_script,CP ) |
| else |
| $(out)/$(PROJECT).exe: $(ro-objs) |
| $(call quiet,exe,EXE ) |
| endif |
| |
| $(out)/RO/%.o.cmd:%.c |
| $(file > $@,$(subst .o.cmd,.o,$(cmd_c_to_o))) |
| $(out)/RO/%.o:%.c |
| $(call quiet,c_to_o,CC ) |
| $(out)/RW/%.o:%.c |
| $(call quiet,c_to_o,CC ) |
| |
| $(out)/RO/%.s:%.c |
| $(call quiet,c_to_s,CC ) |
| $(out)/RW/%.s:%.c |
| $(call quiet,c_to_s,CC ) |
| |
| $(out)/RO/%.o:%.cc |
| $(call quiet,cxx_to_o,CXX ) |
| $(out)/RW/%.o:%.cc |
| $(call quiet,cxx_to_o,CXX ) |
| |
| $(out)/$(SHOBJLIB)/%.o: override LATE_CFLAGS_DEFINE:=-DSHAREDLIB_IMAGE=$(EMPTY) |
| $(out)/$(SHOBJLIB)/%.o:%.c |
| $(call quiet,c_to_o,CC ) |
| |
| $(out)/RO/%.o:%.S |
| $(call quiet,c_to_o,AS ) |
| $(out)/RW/%.o:%.S |
| $(call quiet,c_to_o,AS ) |
| |
| # Default rules for archives, dependencies need to be fixes in build.mk |
| $(out)/RO/%.a: |
| $(call quiet,o_to_a,AR ) |
| $(out)/RW/%.a: |
| $(call quiet,o_to_a,AR ) |
| |
| # Conditionally force the rebuilding of ec_version.h only if it would be |
| # changed. |
| old_version_hash := $(shell cat $(out)/ec_version.h 2> /dev/null | md5sum -) |
| new_version_hash := $(shell BOARD=$(BOARD) ./util/getversion.sh | md5sum -) |
| |
| ifneq ($(old_version_hash),$(new_version_hash)) |
| .PHONY: $(out)/ec_version.h |
| endif |
| |
| # All of the objects have an order only dependency on the ec_version header. |
| # This ensures that if ec_version.h needs to be built (because it was marked |
| # PHONY above) then it will be rebuilt before any objects. This is important |
| # because some source files will include ec_version.h and fail to compile if |
| # it doesn't already exist. This dependency shouldn't be a normal dependency |
| # because that would cause every object to be rebuilt when ec_version.h |
| # changes, instead of just the ones that actually depend on it. The objects |
| # that truly depend on ec_version.h will have that information encoded in their |
| # .d file. |
| $(ro-objs): | $(out)/ec_version.h |
| $(rw-objs): | $(out)/ec_version.h |
| $(sharedlib-objs): | $(out)/ec_version.h |
| |
| $(out)/ec_version.h: |
| $(call quiet,version,VERSION) |
| |
| $(host-utils): $(out)/%:$(host-srcs) |
| $(call quiet,c_to_host,HOSTCC ) |
| |
| $(host-utils-cxx): $(out)/%:$(host-srcs-cxx) |
| $(call quiet,cxx_to_host,HOSTCXX ) |
| |
| .PHONY: clean |
| clean: |
| -rm -rf $(out) build/Makefile.sdk |
| |
| .PHONY: clobber |
| clobber: |
| -rm -rf build |
| ifneq ($(CCACHE),) |
| $(CCACHE) -C |
| endif |
| |
| .PHONY: help |
| help: |
| @echo "Google Chromium EC build" |
| @echo "" |
| @echo "Common Targets:" |
| @echo " clean [BOARD=] - Clean a single board" |
| @echo " buildall - Build all boards and build/run host unit tests" |
| @echo " buildall_only - Build all boards and host unit tests" |
| @echo " build_boards - Build all boards" |
| @echo " clobber - Clean all boards" |
| @echo " proj-<boardname> - Build a single board (similar to 'all BOARD=boardname')" |
| @echo "" |
| @echo " tests [BOARD=] - Build all on-device unit tests for a specific board" |
| @echo " test-coverage - Build and run all host unit tests for code coverage" |
| @echo "" |
| @echo " print-tests [BOARD=] - Print on-device test targets" |
| @echo " print-host-tests - Print all host unit test targets" |
| @echo "" |
| @echo "Common Variables:" |
| @echo " V=1 - Show make output" |
| @echo " BOARD= - Set the board name to build (Default is $(BOARD))" |
| @echo " STATIC_VERSION=1 - Force a constant version string for reproducable builds" |
| @echo " BUILDCC_PREFIX= - Set the compiler prefix for the system doing " |
| @echo " the build (defaults to 'x86_64-pc-linux-gnu-')." |
| @echo " CROSS_COMPILE= - Set the compiler for the board" |
| @echo " CROSS_COMPILE_arch= - Set the compiler for arch" |
| @echo " The board picks its CROSS_COMPILE_arch if CROSS_COMPILE is not set." |
| @echo " arch may be one of 'arm', 'i386', 'nds32'." |
| @echo " HOST_CROSS_COMPILE= - Set the compiler for the target platform on top of" |
| @echo " the EC. For example, this may be 32-bit x86 linux ('i686-pc-linux-gnu-')," |
| @echo " 64-bit x86 linux ('x86_64-pc-linux-gnu-'), or maybe 64-bit ARM linux" |
| @echo " ('aarch64-cros-linux-gnu-')." |
| @echo "Example:" |
| @echo " make BOARD=reef CROSS_COMPILE_arm='arm-eabi-'" |
| |
| out_cros_ec_commands=build/kernel/include/linux/mfd/cros_ec_commands.h |
| .PHONY: build_cros_ec_commands |
| build_cros_ec_commands: $(out_cros_ec_commands) |
| |
| |
| $(out_cros_ec_commands): include/ec_commands.h util/make_linux_ec_commands_h.sh |
| util/make_linux_ec_commands_h.sh $< $@ |
| |
| # Pull in special rules/targets for third_party software |
| -include third_party/rules.mk |
| |
| .SECONDARY: |
| |
| -include $(deps) |
| |
| .PHONY: get_sdk |
| get_sdk: |
| ifneq ($(BAZEL_SUPPORTED),) |
| declare -A toolchain_dict=($(shell ./util/coreboot_sdk.py)) ; \ |
| rm -rf build/Makefile.sdk ; \ |
| for key in "$${!toolchain_dict[@]}"; do \ |
| echo "export $${key} := $${toolchain_dict[$${key}]}" >> build/Makefile.sdk ; \ |
| done |
| sync |
| endif |