From bf64c3313d7569160754cbcec7570991eb6b0b95 Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Fri, 22 Jun 2018 04:09:49 +0300 Subject: [PATCH] Import GNU make build system from esp-idf v3 build system is going to be adopted to apeos --- make/common.mk | 88 ++++++++ make/component_common.mk | 1 + make/component_wrapper.mk | 327 +++++++++++++++++++++++++++ make/project.mk | 549 ++++++++++++++++++++++++++++++++++++++++++++++ make/project_config.mk | 97 ++++++++ 5 files changed, 1062 insertions(+) create mode 100644 make/common.mk create mode 100644 make/component_common.mk create mode 100644 make/component_wrapper.mk create mode 100644 make/project.mk create mode 100644 make/project_config.mk diff --git a/make/common.mk b/make/common.mk new file mode 100644 index 0000000..ccee322 --- /dev/null +++ b/make/common.mk @@ -0,0 +1,88 @@ +# Functionality common to both top-level project makefile (project.mk) +# and component makefiles (component_wrapper.mk) +# + +# Include project config makefile, if it exists. +# +# (Note that we only rebuild this makefile automatically for some +# targets, see project_config.mk for details.) +SDKCONFIG_MAKEFILE ?= $(abspath $(BUILD_DIR_BASE)/include/config/auto.conf) +-include $(SDKCONFIG_MAKEFILE) +export SDKCONFIG_MAKEFILE # sub-makes (like bootloader) will reuse this path + +# BATCH_BUILD flag disables interactive terminal features, defaults to verbose build +ifdef BATCH_BUILD +V ?= 1 +endif + +#Handling of V=1/VERBOSE=1 flag +# +# if V=1, $(summary) does nothing and $(details) will echo extra details +# if V is unset or not 1, $(summary) echoes a summary and $(details) does nothing +VERBOSE ?= +V ?= $(VERBOSE) +ifeq ("$(V)","1") +summary := @true +details := @echo +else +summary := @echo +details := @true + +# disable echoing of commands, directory names +MAKEFLAGS += --silent +endif # $(V)==1 + +ifdef CONFIG_MAKE_WARN_UNDEFINED_VARIABLES +MAKEFLAGS += --warn-undefined-variables +endif + +# General make utilities + +# convenience variable for printing an 80 asterisk wide separator line +SEPARATOR:="*******************************************************************************" + +# macro to remove quotes from an argument, ie $(call dequote,$(CONFIG_BLAH)) +define dequote +$(subst ",,$(1)) +endef +# " comment kept here to keep syntax highlighting happy + + +# macro to keep an absolute path as-is, but resolve a relative path +# against a particular parent directory +# +# $(1) path to resolve +# $(2) directory to resolve non-absolute path against +# +# Path and directory don't have to exist (definition of a "relative +# path" is one that doesn't start with /) +# +# $(2) can contain a trailing forward slash or not, result will not +# double any path slashes. +# +# example $(call resolvepath,$(CONFIG_PATH),$(CONFIG_DIR)) +define resolvepath +$(foreach dir,$(1),$(if $(filter /%,$(dir)),$(dir),$(subst //,/,$(2)/$(dir)))) +endef + + +# macro to include a target only if it's on the list of targets that make +# was invoked with +# +# This allows you to have something like an "order-only phony prerequisite", +# ie a prerequisite that determines an order phony targets have to run in. +# +# Because normal order-only prerequisites don't work with phony targets. +# +# example $(call prereq_if_explicit,erase_flash) +define prereq_if_explicit +$(filter $(1),$(MAKECMDGOALS)) +endef + +# macro to kill duplicate items in a list without messing up the sort order of the list. +# Will only keep the unique items; if there are non-unique items in the list, it will remove +# the later recurring ones so only the first one remains. +# Copied from http://stackoverflow.com/questions/16144115/makefile-remove-duplicate-words-without-sorting +define uniq +$(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) +endef diff --git a/make/component_common.mk b/make/component_common.mk new file mode 100644 index 0000000..187e1ed --- /dev/null +++ b/make/component_common.mk @@ -0,0 +1 @@ +$(warning Deprecated feature: No longer necessary to include component_common.mk from $(COMPONENT_PATH)/component.mk) diff --git a/make/component_wrapper.mk b/make/component_wrapper.mk new file mode 100644 index 0000000..e43e82a --- /dev/null +++ b/make/component_wrapper.mk @@ -0,0 +1,327 @@ +# Component wrapper makefile +# +# This makefile gets called recursively from the project make, once for each component. +# COMPONENT_MAKEFILE is set to point at the component.mk file for the component itself, +# which is included as part of this process (after default variables are defined). +# +# This makefile comprises multiple stages, marked in blocked comments below. +# +# CWD is the build directory of the component. + +ifndef PROJECT_PATH +$(error Make was invoked from $(CURDIR). However please do not run make from the sdk or a component directory; invoke make from the project directory. See the ESP-IDF README for details.) +endif + + +################################################################################ +# 1) Set default variables for the component build (including configuration +# loaded from sdkconfig.) +################################################################################ + +# Find the path to the component +COMPONENT_PATH := $(abspath $(dir $(COMPONENT_MAKEFILE))) +export COMPONENT_PATH + +# COMPONENT_BUILD_DIR is otherwise known as CWD for the build +COMPONENT_BUILD_DIR := $(abspath .) + +# include elements common to both project & component makefiles +# (includes project configuration set via menuconfig) +include $(IDF_PATH)/make/common.mk + +# Some of the following defaults may be overriden by the component's component.mk makefile, +# during the next step: + +# Absolute path of the .a file +COMPONENT_LIBRARY = lib$(COMPONENT_NAME).a + +# Source dirs a component has. Default to root directory of component. +COMPONENT_SRCDIRS = . + +#Names of binary & text files to embed as raw content in the component library +COMPONENT_EMBED_FILES ?= +COMPONENT_EMBED_TXTFILES ?= + +# By default, include only the include/ dir. +COMPONENT_ADD_INCLUDEDIRS = include +COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) + +# Define optional compiling macros +define compile_exclude +COMPONENT_OBJEXCLUDE += $(1) +endef + +define compile_include +COMPONENT_OBJINCLUDE += $(1) +endef + +define compile_only_if +$(eval $(if $(1), $(call compile_include, $(2)), $(call compile_exclude, $(2)))) +endef + +define compile_only_if_not +$(eval $(if $(1), $(call compile_exclude, $(2)), $(call compile_include, $(2)))) +endef + +COMPONENT_ADD_LINKER_DEPS ?= +COMPONENT_DEPENDS ?= +COMPONENT_EXTRA_CLEAN ?= +COMPONENT_EXTRA_INCLUDES ?= +COMPONENT_OBJEXCLUDE ?= +COMPONENT_OBJINCLUDE ?= +COMPONENT_SUBMODULES ?= + +################################################################################ +# 2) Include the component.mk for the specific component (COMPONENT_MAKEFILE) to +# override variables & optionally define custom targets. Also include global +# component makefiles. +################################################################################ + + +# Include any Makefile.componentbuild file letting components add +# configuration at the global component level + +# Save component_path; we pass it to the called Makefile.componentbuild +# as COMPILING_COMPONENT_PATH, and we use it to restore the current +# COMPONENT_PATH later. +COMPILING_COMPONENT_PATH := $(COMPONENT_PATH) + +define includeCompBuildMakefile +$(if $(V),$(info including $(1)/Makefile.componentbuild...)) +COMPONENT_PATH := $(1) +include $(1)/Makefile.componentbuild +endef +$(foreach componentpath,$(COMPONENT_PATHS), \ + $(if $(wildcard $(componentpath)/Makefile.componentbuild), \ + $(eval $(call includeCompBuildMakefile,$(componentpath))))) + +#Restore COMPONENT_PATH to what it was +COMPONENT_PATH := $(COMPILING_COMPONENT_PATH) + + +# Include component.mk for this component. +include $(COMPONENT_MAKEFILE) + + +################################################################################ +# 3) Set variables that depend on values that may changed by component.mk +################################################################################ + +ifndef COMPONENT_CONFIG_ONLY # Skip steps 3-5 if COMPONENT_CONFIG_ONLY is set + +# Object files which need to be linked into the library +# By default we take all .c, .cpp, .cc & .S files in COMPONENT_SRCDIRS. +ifndef COMPONENT_OBJS +# Find all source files in all COMPONENT_SRCDIRS +COMPONENT_OBJS := $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.c,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.c))) +COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cpp))) +COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cc,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cc))) +COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.S,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.S))) +# Make relative by removing COMPONENT_PATH from all found object paths +COMPONENT_OBJS := $(patsubst $(COMPONENT_PATH)/%,%,$(COMPONENT_OBJS)) +else +# Add in components defined by conditional compiling macros +COMPONENT_OBJS += $(COMPONENT_OBJINCLUDE) +endif +# Remove items disabled by optional compilation +COMPONENT_OBJS := $(foreach obj,$(COMPONENT_OBJS),$(if $(filter $(realpath $(obj)),$(realpath $(COMPONENT_OBJEXCLUDE))), ,$(obj))) + +# Remove duplicates +COMPONENT_OBJS := $(call uniq,$(COMPONENT_OBJS)) + + +# Object files with embedded binaries to add to the component library +# Correspond to the files named in COMPONENT_EMBED_FILES & COMPONENT_EMBED_TXTFILES +COMPONENT_EMBED_OBJS ?= $(addsuffix .bin.o,$(notdir $(COMPONENT_EMBED_FILES))) $(addsuffix .txt.o,$(notdir $(COMPONENT_EMBED_TXTFILES))) + +# If we're called to compile something, we'll get passed the COMPONENT_INCLUDES +# variable with all the include dirs from all the components in random order. This +# means we can accidentally grab a header from another component before grabbing our own. +# To make sure that does not happen, re-order the includes so ours come first. +COMPONENT_PRIV_INCLUDEDIRS ?= +OWN_INCLUDES:=$(abspath $(addprefix $(COMPONENT_PATH)/,$(COMPONENT_PRIV_INCLUDEDIRS) $(COMPONENT_ADD_INCLUDEDIRS))) +COMPONENT_INCLUDES := $(OWN_INCLUDES) $(filter-out $(OWN_INCLUDES),$(COMPONENT_INCLUDES)) + + +################################################################################ +# 4) Define a target to generate component_project_vars.mk Makefile which +# contains common per-component settings which are included directly in the +# top-level project make +# +# (Skipped if COMPONENT_CONFIG_ONLY is set.) +################################################################################ + +# macro to generate variable-relative paths inside component_project_vars.mk, whenever possible +# ie put literal $(IDF_PATH), $(PROJECT_PATH) and $(BUILD_DIR_BASE) into the generated +# makefiles where possible. +# +# This means if directories move (breaking absolute paths), don't need to 'make clean' +define MakeVariablePath +$(subst $(IDF_PATH),$$(IDF_PATH),$(subst $(PROJECT_PATH),$$(PROJECT_PATH),$(subst $(BUILD_DIR_BASE),$$(BUILD_DIR_BASE),$(1)))) +endef + +# component_project_vars.mk target for the component. This is used to +# take component.mk variables COMPONENT_ADD_INCLUDEDIRS, +# COMPONENT_ADD_LDFLAGS, COMPONENT_DEPENDS and COMPONENT_SUBMODULES +# and inject those into the project make pass. +# +# The target here has no dependencies, as the parent target in +# project.mk evaluates dependencies before calling down to here. See +# GenerateComponentTargets macro in project.mk. +# +# If you are thinking of editing the output of this target for a +# component-specific feature, please don't! What you want is a +# Makefile.projbuild for your component (see docs/build-system.rst for +# more.) +# +# Note: The :: target here is not a mistake. This target should always be +# executed, as dependencies are checked by the parent project-level make target. +# See https://www.gnu.org/software/make/manual/make.html#index-_003a_003a-rules-_0028double_002dcolon_0029 +component_project_vars.mk:: + $(details) "Building component project variables list $(abspath $@)" + @echo '# Automatically generated build file. Do not edit.' > $@ + @echo 'COMPONENT_INCLUDES += $(call MakeVariablePath,$(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS)))' >> $@ + @echo 'COMPONENT_LDFLAGS += $(call MakeVariablePath,-L$(COMPONENT_BUILD_DIR) $(COMPONENT_ADD_LDFLAGS))' >> $@ + @echo 'COMPONENT_LINKER_DEPS += $(call MakeVariablePath,$(call resolvepath,$(COMPONENT_ADD_LINKER_DEPS),$(COMPONENT_PATH)))' >> $@ + @echo 'COMPONENT_SUBMODULES += $(call MakeVariablePath,$(addprefix $(COMPONENT_PATH)/,$(COMPONENT_SUBMODULES)))' >> $@ + @echo 'COMPONENT_LIBRARIES += $(COMPONENT_NAME)' >> $@ + @echo 'component-$(COMPONENT_NAME)-build: $(addprefix component-,$(addsuffix -build,$(COMPONENT_DEPENDS)))' >> $@ + +################################################################################ +# 5) Where COMPONENT_OWNBUILDTARGET / COMPONENT_OWNCLEANTARGET +# is not set by component.mk, define default build, clean, etc. targets +# +# (Skipped if COMPONENT_CONFIG_ONLY is set.) +################################################################################ + +# Default build behaviour: define a phony build target and a COMPONENT_LIBRARY link target. +ifndef COMPONENT_OWNBUILDTARGET +.PHONY: build +build: $(COMPONENT_LIBRARY) + +# Build the archive. We remove the archive first, otherwise ar will get confused if we update +# an archive when multiple filenames have the same name (src1/test.o and src2/test.o) +$(COMPONENT_LIBRARY): $(COMPONENT_OBJS) $(COMPONENT_EMBED_OBJS) + $(summary) AR $(patsubst $(PWD)/%,%,$(CURDIR))/$@ + rm -f $@ + $(AR) cru $@ $^ +endif + +# If COMPONENT_OWNCLEANTARGET is not set, define a phony clean target +ifndef COMPONENT_OWNCLEANTARGET +CLEAN_FILES := $(COMPONENT_LIBRARY) $(COMPONENT_OBJS) $(COMPONENT_OBJS:.o=.d) $(COMPONENT_OBJEXCLUDE) $(COMPONENT_OBJEXCLUDE:.o=.d) $(COMPONENT_EMBED_OBJS) $(COMPONENT_EXTRA_CLEAN) component_project_vars.mk +.PHONY: clean +clean: + $(summary) RM $(CLEAN_FILES) + rm -f $(CLEAN_FILES) +endif + +DEBUG_FLAGS ?= -ggdb + +# Include all dependency files already generated +-include $(COMPONENT_OBJS:.o=.d) + +# This is a fix for situation where the project or IDF dir moves, and instead +# of rebuilding the target the build fails until make clean is run +# +# It adds an empty dependency rule for the (possibly non-existent) source file itself, +# which prevents it not being found from failing the build +# +# $1 == Source File, $2 == .o file used for .d file name +define AppendSourceToDependencies +echo "$1:" >> $$(patsubst %.o,%.d,$2) +endef + + +# This pattern is generated for each COMPONENT_SRCDIR to compile the files in it. +define GenerateCompileTargets +# $(1) - directory containing source files, relative to $(COMPONENT_PATH) - one of $(COMPONENT_SRCDIRS) +# +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.c $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(COMPONENT_SRCDIRS) + $$(summary) CC $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@ + $$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + $(call AppendSourceToDependencies,$$<,$$@) + +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(COMPONENT_SRCDIRS) + $$(summary) CXX $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@ + $$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + $(call AppendSourceToDependencies,$$<,$$@) + +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cc $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(COMPONENT_SRCDIRS) + $$(summary) CXX $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@ + $$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + $(call AppendSourceToDependencies,$$<,$$@) + +$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(COMPONENT_SRCDIRS) + $$(summary) AS $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@ + $$(CC) $$(CPPFLAGS) $$(DEBUG_FLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + $(call AppendSourceToDependencies,$$<,$$@) + +# CWD is build dir, create the build subdirectory if it doesn't exist +# +# (NB: Each .o file depends on all relative component build dirs $(COMPONENT_SRCDIRS), rather than just $(1), to work +# around a behaviour make 3.81 where the first pattern (randomly) seems to be matched rather than the best fit. ie if +# you have objects a/y.o and a/b/c.o then c.o can be matched with $(1)=a & %=b/c, meaning that subdir 'a/b' needs to be +# created but wouldn't be created if $(1)=a. Make 4.x doesn't have this problem, it seems to preferentially +# choose the better match ie $(1)=a/b and %=c ) +# +$(1): + mkdir -p $(1) +endef + +# Generate all the compile target patterns +$(foreach srcdir,$(COMPONENT_SRCDIRS), $(eval $(call GenerateCompileTargets,$(srcdir)))) + +## Support for embedding binary files into the ELF as symbols + +OBJCOPY_EMBED_ARGS := --input-target binary --output-target elf32-xtensa-le --binary-architecture xtensa --rename-section .data=.rodata.embedded + +# Generate pattern for embedding text or binary files into the app +# $(1) is name of file (as relative path inside component) +# $(2) is txt or bin depending on file contents +# +# txt files are null-terminated before being embedded (otherwise +# identical behaviour.) +# +define GenerateEmbedTarget + +# copy the input file into the build dir (using a subdirectory +# in case the file already exists elsewhere in the build dir) +embed_bin/$$(notdir $(1)): $(call resolvepath,$(1),$(COMPONENT_PATH)) | embed_bin + cp $$< $$@ + +embed_txt/$$(notdir $(1)): $(call resolvepath,$(1),$(COMPONENT_PATH)) | embed_txt + cp $$< $$@ + printf '\0' >> $$@ # null-terminate text files + +# messing about with the embed_X subdirectory then using 'cd' for objcopy is because the +# full path passed to OBJCOPY makes it into the name of the symbols in the .o file +$$(notdir $(1)).$(2).o: embed_$(2)/$$(notdir $(1)) + $(summary) EMBED $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@ + cd embed_$(2); $(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) ../$$@ + +CLEAN_FILES += embed_$(2)/$$(notdir $(1)) +endef + +embed_txt embed_bin: + mkdir -p $@ + +# generate targets to embed binary & text files +$(foreach binfile,$(COMPONENT_EMBED_FILES), $(eval $(call GenerateEmbedTarget,$(binfile),bin))) + +$(foreach txtfile,$(COMPONENT_EMBED_TXTFILES), $(eval $(call GenerateEmbedTarget,$(txtfile),txt))) + +else # COMPONENT_CONFIG_ONLY is set + +build: + $(details) "No build needed for $(COMPONENT_NAME) (COMPONENT_CONFIG_ONLY)" + +clean: + $(summary) RM component_project_vars.mk + rm -f component_project_vars.mk + +component_project_vars.mk:: # no need to add variables via component.mk + @echo '# COMPONENT_CONFIG_ONLY target sets no variables here' > $@ + +endif # COMPONENT_CONFIG_ONLY + diff --git a/make/project.mk b/make/project.mk new file mode 100644 index 0000000..31f72bc --- /dev/null +++ b/make/project.mk @@ -0,0 +1,549 @@ +# +# Main Project Makefile +# This Makefile is included directly from the user project Makefile in order to call the component.mk +# makefiles of all components (in a separate make process) to build all the libraries, then links them +# together into the final file. If so, PWD is the project dir (we assume). +# + +# +# This makefile requires the environment variable IDF_PATH to be set to the top-level esp-idf directory +# where this file is located. +# + +.PHONY: build-components menuconfig defconfig all build clean all_binaries check-submodules size size-components size-files list-components + +MAKECMDGOALS ?= all +all: all_binaries +# see below for recipe of 'all' target +# +# # other components will add dependencies to 'all_binaries'. The +# reason all_binaries is used instead of 'all' is so that the flash +# target can build everything without triggering the per-component "to +# flash..." output targets.) + +help: + @echo "Welcome to Espressif IDF build system. Some useful make targets:" + @echo "" + @echo "make menuconfig - Configure IDF project" + @echo "make defconfig - Set defaults for all new configuration options" + @echo "" + @echo "make all - Build app, bootloader, partition table" + @echo "make flash - Flash app, bootloader, partition table to a chip" + @echo "make clean - Remove all build output" + @echo "make size - Display the static memory footprint of the app" + @echo "make size-components, size-files - Finer-grained memory footprints" + @echo "make erase_flash - Erase entire flash contents" + @echo "make monitor - Run idf_monitor tool to monitor serial output from app" + @echo "make simple_monitor - Monitor serial output on terminal console" + @echo "make list-components - List all components in the project" + @echo "" + @echo "make app - Build just the app" + @echo "make app-flash - Flash just the app" + @echo "make app-clean - Clean just the app" + @echo "make print_flash_cmd - Print the arguments for esptool when flash" + @echo "" + @echo "See also 'make bootloader', 'make bootloader-flash', 'make bootloader-clean', " + @echo "'make partition_table', etc, etc." + +# dependency checks +ifndef MAKE_RESTARTS +ifeq ("$(filter 4.% 3.81 3.82,$(MAKE_VERSION))","") +$(warning esp-idf build system only supports GNU Make versions 3.81 or newer. You may see unexpected results with other Makes.) +endif + +ifdef MSYSTEM +ifneq ("$(MSYSTEM)","MINGW32") +$(warning esp-idf build system only supports MSYS2 in "MINGW32" mode. Consult the ESP-IDF documentation for details.) +endif +endif # MSYSTEM + +endif # MAKE_RESTARTS + +# can't run 'clean' along with any non-clean targets +ifneq ("$(filter clean% %clean,$(MAKECMDGOALS))" ,"") +ifneq ("$(filter-out clean% %clean,$(MAKECMDGOALS))", "") +$(error esp-idf build system doesn't support running 'clean' targets along with any others. Run 'make clean' and then run other targets separately.) +endif +endif + +OS ?= + +# make IDF_PATH a "real" absolute path +# * works around the case where a shell character is embedded in the environment variable value. +# * changes Windows-style C:/blah/ paths to MSYS style /c/blah +ifeq ("$(OS)","Windows_NT") +# On Windows MSYS2, make wildcard function returns empty string for paths of form /xyz +# where /xyz is a directory inside the MSYS root - so we don't use it. +SANITISED_IDF_PATH:=$(realpath $(IDF_PATH)) +else +SANITISED_IDF_PATH:=$(realpath $(wildcard $(IDF_PATH))) +endif + +export IDF_PATH := $(SANITISED_IDF_PATH) + +ifndef IDF_PATH +$(error IDF_PATH variable is not set to a valid directory.) +endif + +ifneq ("$(IDF_PATH)","$(SANITISED_IDF_PATH)") +# implies IDF_PATH was overriden on make command line. +# Due to the way make manages variables, this is hard to account for +# +# if you see this error, do the shell expansion in the shell ie +# make IDF_PATH=~/blah not make IDF_PATH="~/blah" +$(error If IDF_PATH is overriden on command line, it must be an absolute path with no embedded shell special characters) +endif + +ifneq ("$(IDF_PATH)","$(subst :,,$(IDF_PATH))") +$(error IDF_PATH cannot contain colons. If overriding IDF_PATH on Windows, use MSYS Unix-style /c/dir instead of C:/dir) +endif + +# disable built-in make rules, makes debugging saner +MAKEFLAGS_OLD := $(MAKEFLAGS) +MAKEFLAGS +=-rR + +# Default path to the project: we assume the Makefile including this file +# is in the project directory +ifndef PROJECT_PATH +PROJECT_PATH := $(abspath $(dir $(firstword $(MAKEFILE_LIST)))) +export PROJECT_PATH +endif + +# A list of the "common" makefiles, to use as a target dependency +COMMON_MAKEFILES := $(abspath $(IDF_PATH)/make/project.mk $(IDF_PATH)/make/common.mk $(IDF_PATH)/make/component_wrapper.mk $(firstword $(MAKEFILE_LIST))) +export COMMON_MAKEFILES + +# The directory where we put all objects/libraries/binaries. The project Makefile can +# configure this if needed. +ifndef BUILD_DIR_BASE +BUILD_DIR_BASE := $(PROJECT_PATH)/build +endif +export BUILD_DIR_BASE + +# Component directories. These directories are searched for components (either the directory is a component, +# or the directory contains subdirectories which are components.) +# The project Makefile can override these component dirs, or add extras via EXTRA_COMPONENT_DIRS +ifndef COMPONENT_DIRS +EXTRA_COMPONENT_DIRS ?= +COMPONENT_DIRS := $(PROJECT_PATH)/components $(EXTRA_COMPONENT_DIRS) $(IDF_PATH)/components $(PROJECT_PATH)/main +endif +export COMPONENT_DIRS + +ifdef SRCDIRS +$(warning SRCDIRS variable is deprecated. These paths can be added to EXTRA_COMPONENT_DIRS or COMPONENT_DIRS instead.) +COMPONENT_DIRS += $(abspath $(SRCDIRS)) +endif + +# The project Makefile can define a list of components, but if it does not do this we just take all available components +# in the component dirs. A component is COMPONENT_DIRS directory, or immediate subdirectory, +# which contains a component.mk file. +# +# Use the "make list-components" target to debug this step. +ifndef COMPONENTS +# Find all component names. The component names are the same as the +# directories they're in, so /bla/components/mycomponent/component.mk -> mycomponent. +COMPONENTS := $(dir $(foreach cd,$(COMPONENT_DIRS), \ + $(wildcard $(cd)/*/component.mk) $(wildcard $(cd)/component.mk) \ + )) +COMPONENTS := $(sort $(foreach comp,$(COMPONENTS),$(lastword $(subst /, ,$(comp))))) +endif +export COMPONENTS + +# Resolve all of COMPONENTS into absolute paths in COMPONENT_PATHS. +# +# If a component name exists in multiple COMPONENT_DIRS, we take the first match. +# +# NOTE: These paths must be generated WITHOUT a trailing / so we +# can use $(notdir x) to get the component name. +COMPONENT_PATHS := $(foreach comp,$(COMPONENTS),$(firstword $(foreach cd,$(COMPONENT_DIRS),$(wildcard $(dir $(cd))$(comp) $(cd)/$(comp))))) +export COMPONENT_PATHS + +TEST_COMPONENTS ?= +TESTS_ALL ?= + +# If TESTS_ALL set to 1, set TEST_COMPONENTS_LIST to all components. +# Otherwise, use the list supplied in TEST_COMPONENTS. +ifeq ($(TESTS_ALL),1) +TEST_COMPONENTS_LIST := $(COMPONENTS) +else +TEST_COMPONENTS_LIST := $(TEST_COMPONENTS) +endif + +TEST_COMPONENT_PATHS := $(foreach comp,$(TEST_COMPONENTS_LIST),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp)/test)))) +TEST_COMPONENT_NAMES := $(foreach comp,$(TEST_COMPONENT_PATHS),$(lastword $(subst /, ,$(dir $(comp))))_test) + +# Initialise project-wide variables which can be added to by +# each component. +# +# These variables are built up via the component_project_vars.mk +# generated makefiles (one per component). +# +# See docs/build-system.rst for more details. +COMPONENT_INCLUDES := +COMPONENT_LDFLAGS := +COMPONENT_SUBMODULES := +COMPONENT_LIBRARIES := + +# COMPONENT_PROJECT_VARS is the list of component_project_vars.mk generated makefiles +# for each component. +# +# Including $(COMPONENT_PROJECT_VARS) builds the COMPONENT_INCLUDES, +# COMPONENT_LDFLAGS variables and also targets for any inter-component +# dependencies. +# +# See the component_project_vars.mk target in component_wrapper.mk +COMPONENT_PROJECT_VARS := $(addsuffix /component_project_vars.mk,$(notdir $(COMPONENT_PATHS) ) $(TEST_COMPONENT_NAMES)) +COMPONENT_PROJECT_VARS := $(addprefix $(BUILD_DIR_BASE)/,$(COMPONENT_PROJECT_VARS)) +# this line is -include instead of include to prevent a spurious error message on make 3.81 +-include $(COMPONENT_PROJECT_VARS) + +# Also add top-level project include path, for top-level includes +COMPONENT_INCLUDES += $(abspath $(BUILD_DIR_BASE)/include/) + +export COMPONENT_INCLUDES + +# Set variables common to both project & component +include $(IDF_PATH)/make/common.mk + +all: +ifdef CONFIG_SECURE_BOOT_ENABLED + @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)" +ifndef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES + @echo "App built but not signed. Sign app & partition data before flashing, via espsecure.py:" + @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" + @echo "espsecure.py sign_data --keyfile KEYFILE $(PARTITION_TABLE_BIN)" +endif + @echo "To flash app & partition table, run 'make flash' or:" +else + @echo "To flash all build output, run 'make flash' or:" +endif + @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) + + +IDF_VER := $(shell cd ${IDF_PATH} && git describe --always --tags --dirty) + +# Set default LDFLAGS +EXTRA_LDFLAGS ?= +LDFLAGS ?= -nostdlib \ + -u call_user_start_cpu0 \ + $(EXTRA_LDFLAGS) \ + -Wl,--gc-sections \ + -Wl,-static \ + -Wl,--start-group \ + $(COMPONENT_LDFLAGS) \ + -lgcc \ + -lstdc++ \ + -lgcov \ + -Wl,--end-group \ + -Wl,-EL + +# Set default CPPFLAGS, CFLAGS, CXXFLAGS +# These are exported so that components can use them when compiling. +# If you need your component to add CFLAGS/etc for it's own source compilation only, set CFLAGS += in your component's Makefile. +# If you need your component to add CFLAGS/etc globally for all source +# files, set CFLAGS += in your component's Makefile.projbuild +# If you need to set CFLAGS/CPPFLAGS/CXXFLAGS at project level, set them in application Makefile +# before including project.mk. Default flags will be added before the ones provided in application Makefile. + +# CPPFLAGS used by C preprocessor +# If any flags are defined in application Makefile, add them at the end. +CPPFLAGS ?= +EXTRA_CPPFLAGS ?= +CPPFLAGS := -DESP_PLATFORM -D IDF_VER=\"$(IDF_VER)\" -MMD -MP $(CPPFLAGS) $(EXTRA_CPPFLAGS) + +# Warnings-related flags relevant both for C and C++ +COMMON_WARNING_FLAGS = -Wall -Werror=all \ + -Wno-error=unused-function \ + -Wno-error=unused-but-set-variable \ + -Wno-error=unused-variable \ + -Wno-error=deprecated-declarations \ + -Wextra \ + -Wno-unused-parameter -Wno-sign-compare + +# Flags which control code generation and dependency generation, both for C and C++ +COMMON_FLAGS = \ + -ffunction-sections -fdata-sections \ + -fstrict-volatile-bitfields \ + -mlongcalls \ + -nostdlib + +ifndef IS_BOOTLOADER_BUILD +# stack protection (only one option can be selected in menuconfig) +ifdef CONFIG_STACK_CHECK_NORM +COMMON_FLAGS += -fstack-protector +endif +ifdef CONFIG_STACK_CHECK_STRONG +COMMON_FLAGS += -fstack-protector-strong +endif +ifdef CONFIG_STACK_CHECK_ALL +COMMON_FLAGS += -fstack-protector-all +endif +endif + +# Optimization flags are set based on menuconfig choice +ifdef CONFIG_OPTIMIZATION_LEVEL_RELEASE +OPTIMIZATION_FLAGS = -Os +else +OPTIMIZATION_FLAGS = -Og +endif + +ifdef CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED +CPPFLAGS += -DNDEBUG +endif + +# Enable generation of debugging symbols +# (we generate even in Release mode, as this has no impact on final binary size.) +DEBUG_FLAGS ?= -ggdb + +# List of flags to pass to C compiler +# If any flags are defined in application Makefile, add them at the end. +CFLAGS ?= +EXTRA_CFLAGS ?= +CFLAGS := $(strip \ + -std=gnu99 \ + $(OPTIMIZATION_FLAGS) $(DEBUG_FLAGS) \ + $(COMMON_FLAGS) \ + $(COMMON_WARNING_FLAGS) -Wno-old-style-declaration \ + $(CFLAGS) \ + $(EXTRA_CFLAGS)) + +# List of flags to pass to C++ compiler +# If any flags are defined in application Makefile, add them at the end. +CXXFLAGS ?= +EXTRA_CXXFLAGS ?= +CXXFLAGS := $(strip \ + -std=gnu++11 \ + -fno-rtti \ + $(OPTIMIZATION_FLAGS) $(DEBUG_FLAGS) \ + $(COMMON_FLAGS) \ + $(COMMON_WARNING_FLAGS) \ + $(CXXFLAGS) \ + $(EXTRA_CXXFLAGS)) + +ifdef CONFIG_CXX_EXCEPTIONS +CXXFLAGS += -fexceptions +else +CXXFLAGS += -fno-exceptions +endif + +export CFLAGS CPPFLAGS CXXFLAGS + +# Set default values that were not previously defined +CC ?= gcc +LD ?= ld +AR ?= ar +OBJCOPY ?= objcopy +SIZE ?= size + +# Set host compiler and binutils +HOSTCC := $(CC) +HOSTLD := $(LD) +HOSTAR := $(AR) +HOSTOBJCOPY := $(OBJCOPY) +HOSTSIZE := $(SIZE) +export HOSTCC HOSTLD HOSTAR HOSTOBJCOPY SIZE + +# Set target compiler. Defaults to whatever the user has +# configured as prefix + ye olde gcc commands +CC := $(call dequote,$(CONFIG_TOOLPREFIX))gcc +CXX := $(call dequote,$(CONFIG_TOOLPREFIX))c++ +LD := $(call dequote,$(CONFIG_TOOLPREFIX))ld +AR := $(call dequote,$(CONFIG_TOOLPREFIX))ar +OBJCOPY := $(call dequote,$(CONFIG_TOOLPREFIX))objcopy +SIZE := $(call dequote,$(CONFIG_TOOLPREFIX))size +export CC CXX LD AR OBJCOPY SIZE + +PYTHON=$(call dequote,$(CONFIG_PYTHON)) + +# the app is the main executable built by the project +APP_ELF:=$(BUILD_DIR_BASE)/$(PROJECT_NAME).elf +APP_MAP:=$(APP_ELF:.elf=.map) +APP_BIN:=$(APP_ELF:.elf=.bin) + +# Include any Makefile.projbuild file letting components add +# configuration at the project level +define includeProjBuildMakefile +$(if $(V),$(info including $(1)/Makefile.projbuild...)) +COMPONENT_PATH := $(1) +include $(1)/Makefile.projbuild +endef +$(foreach componentpath,$(COMPONENT_PATHS), \ + $(if $(wildcard $(componentpath)/Makefile.projbuild), \ + $(eval $(call includeProjBuildMakefile,$(componentpath))))) + +# once we know component paths, we can include the config generation targets +# +# (bootloader build doesn't need this, config is exported from top-level) +ifndef IS_BOOTLOADER_BUILD +include $(IDF_PATH)/make/project_config.mk +endif + +# ELF depends on the library archive files for COMPONENT_LIBRARIES +# the rules to build these are emitted as part of GenerateComponentTarget below +# +# also depends on additional dependencies (linker scripts & binary libraries) +# stored in COMPONENT_LINKER_DEPS, built via component.mk files' COMPONENT_ADD_LINKER_DEPS variable +COMPONENT_LINKER_DEPS ?= +$(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp)/lib$(libcomp).a) $(COMPONENT_LINKER_DEPS) $(COMPONENT_PROJECT_VARS) + $(summary) LD $(patsubst $(PWD)/%,%,$@) + $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) + +app: $(APP_BIN) +ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image + @echo "App built but not signed. Signing step via espsecure.py:" + @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" + @echo "Then flash app command is:" + @echo $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) +else + @echo "App built. Default flash app command is:" + @echo $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) +endif + +all_binaries: $(APP_BIN) + +$(BUILD_DIR_BASE): + mkdir -p $(BUILD_DIR_BASE) + +# Macro for the recursive sub-make for each component +# $(1) - component directory +# $(2) - component name only +# +# Is recursively expanded by the GenerateComponentTargets macro +define ComponentMake ++$(MAKE) -C $(BUILD_DIR_BASE)/$(2) -f $(IDF_PATH)/make/component_wrapper.mk COMPONENT_MAKEFILE=$(1)/component.mk COMPONENT_NAME=$(2) +endef + +# Generate top-level component-specific targets for each component +# $(1) - path to component dir +# $(2) - name of component +# +define GenerateComponentTargets +.PHONY: component-$(2)-build component-$(2)-clean + +component-$(2)-build: check-submodules $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2) + $(call ComponentMake,$(1),$(2)) build + +component-$(2)-clean: | $(BUILD_DIR_BASE)/$(2) $(BUILD_DIR_BASE)/$(2)/component_project_vars.mk + $(call ComponentMake,$(1),$(2)) clean + +$(BUILD_DIR_BASE)/$(2): + @mkdir -p $(BUILD_DIR_BASE)/$(2) + +# tell make it can build any component's library by invoking the -build target +# (this target exists for all components even ones which don't build libraries, but it's +# only invoked for the targets whose libraries appear in COMPONENT_LIBRARIES and hence the +# APP_ELF dependencies.) +$(BUILD_DIR_BASE)/$(2)/lib$(2).a: component-$(2)-build + $(details) "Target '$$^' responsible for '$$@'" # echo which build target built this file + +# add a target to generate the component_project_vars.mk files that +# are used to inject variables into project make pass (see matching +# component_project_vars.mk target in component_wrapper.mk). +# +# If any component_project_vars.mk file is out of date, the make +# process will call this target to rebuild it and then restart. +# +$(BUILD_DIR_BASE)/$(2)/component_project_vars.mk: $(1)/component.mk $(COMMON_MAKEFILES) $(SDKCONFIG_MAKEFILE) | $(BUILD_DIR_BASE)/$(2) + $(call ComponentMake,$(1),$(2)) component_project_vars.mk +endef + +$(foreach component,$(COMPONENT_PATHS),$(eval $(call GenerateComponentTargets,$(component),$(notdir $(component))))) +$(foreach component,$(TEST_COMPONENT_PATHS),$(eval $(call GenerateComponentTargets,$(component),$(lastword $(subst /, ,$(dir $(component))))_test))) + +app-clean: $(addprefix component-,$(addsuffix -clean,$(notdir $(COMPONENT_PATHS)))) + $(summary) RM $(APP_ELF) + rm -f $(APP_ELF) $(APP_BIN) $(APP_MAP) + +size: $(APP_ELF) + $(PYTHON) $(IDF_PATH)/tools/idf_size.py $(APP_MAP) + +size-files: $(APP_ELF) + $(PYTHON) $(IDF_PATH)/tools/idf_size.py --files $(APP_MAP) + +size-components: $(APP_ELF) + $(PYTHON) $(IDF_PATH)/tools/idf_size.py --archives $(APP_MAP) + +# NB: this ordering is deliberate (app-clean & bootloader-clean before +# _config-clean), so config remains valid during all component clean +# targets +config-clean: app-clean bootloader-clean +clean: app-clean bootloader-clean config-clean + +# phony target to check if any git submodule listed in COMPONENT_SUBMODULES are missing +# or out of date, and exit if so. Components can add paths to this variable. +# +# This only works for components inside IDF_PATH +check-submodules: + +# Dump the git status for the whole working copy once, then grep it for each submodule. This saves a lot of time on Windows. +GIT_STATUS := $(shell cd ${IDF_PATH} && git status --porcelain --ignore-submodules=dirty) + +# Generate a target to check this submodule +# $(1) - submodule directory, relative to IDF_PATH +define GenerateSubmoduleCheckTarget +check-submodules: $(IDF_PATH)/$(1)/.git +$(IDF_PATH)/$(1)/.git: + @echo "WARNING: Missing submodule $(1)..." + [ -e ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) + [ -x $$(which git) ] || ( echo "ERROR: Need to run 'git submodule init $(1)' in esp-idf root directory."; exit 1) + @echo "Attempting 'git submodule update --init $(1)' in esp-idf root directory..." + cd ${IDF_PATH} && git submodule update --init $(1) + +# Parse 'git status' output to check if the submodule commit is different to expected +ifneq ("$(filter $(1),$(GIT_STATUS))","") +$$(info WARNING: esp-idf git submodule $(1) may be out of date. Run 'git submodule update' in IDF_PATH dir to update.) +endif +endef + +# filter/subst in expression ensures all submodule paths begin with $(IDF_PATH), and then strips that prefix +# so the argument is suitable for use with 'git submodule' commands +$(foreach submodule,$(subst $(IDF_PATH)/,,$(filter $(IDF_PATH)/%,$(COMPONENT_SUBMODULES))),$(eval $(call GenerateSubmoduleCheckTarget,$(submodule)))) + + +# PHONY target to list components in the build and their paths +list-components: + $(info $(call dequote,$(SEPARATOR))) + $(info COMPONENT_DIRS (components searched for here)) + $(foreach cd,$(COMPONENT_DIRS),$(info $(cd))) + $(info $(call dequote,$(SEPARATOR))) + $(info COMPONENTS (list of component names)) + $(info $(COMPONENTS)) + $(info $(call dequote,$(SEPARATOR))) + $(info COMPONENT_PATHS (paths to all components):) + $(foreach cp,$(COMPONENT_PATHS),$(info $(cp))) + +# print flash command, so users can dump this to config files and download somewhere without idf +print_flash_cmd: + echo $(ESPTOOL_WRITE_FLASH_OPTIONS) $(ESPTOOL_ALL_FLASH_ARGS) | sed -e 's:'$(PWD)/build/'::g' + +# Check toolchain version using the output of xtensa-esp32-elf-gcc --version command. +# The output normally looks as follows +# xtensa-esp32-elf-gcc (crosstool-NG crosstool-ng-1.22.0-59-ga194053) 4.8.5 +# The part in brackets is extracted into TOOLCHAIN_COMMIT_DESC variable, +# the part after the brackets is extracted into TOOLCHAIN_GCC_VER. +ifdef CONFIG_TOOLPREFIX +ifndef MAKE_RESTARTS +TOOLCHAIN_COMMIT_DESC := $(shell $(CC) --version | sed -E -n 's|.*crosstool-ng-([0-9]+).([0-9]+).([0-9]+)-([0-9]+)-g([0-9a-f]{7}).*|\1.\2.\3-\4-g\5|gp') +TOOLCHAIN_GCC_VER := $(shell $(CC) --version | sed -E -n 's|xtensa-esp32-elf-gcc.*\ \(.*\)\ (.*)|\1|gp') + +# Officially supported version(s) +SUPPORTED_TOOLCHAIN_COMMIT_DESC := 1.22.0-80-g6c4433a +SUPPORTED_TOOLCHAIN_GCC_VERSIONS := 5.2.0 + +ifdef TOOLCHAIN_COMMIT_DESC +ifneq ($(TOOLCHAIN_COMMIT_DESC), $(SUPPORTED_TOOLCHAIN_COMMIT_DESC)) +$(info WARNING: Toolchain version is not supported: $(TOOLCHAIN_COMMIT_DESC)) +$(info Expected to see version: $(SUPPORTED_TOOLCHAIN_COMMIT_DESC)) +$(info Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.) +endif +ifeq (,$(findstring $(TOOLCHAIN_GCC_VER), $(SUPPORTED_TOOLCHAIN_GCC_VERSIONS))) +$(info WARNING: Compiler version is not supported: $(TOOLCHAIN_GCC_VER)) +$(info Expected to see version(s): $(SUPPORTED_TOOLCHAIN_GCC_VERSIONS)) +$(info Please check ESP-IDF setup instructions and update the toolchain, or proceed at your own risk.) +endif +else +$(info WARNING: Failed to find Xtensa toolchain, may need to alter PATH or set one in the configuration menu) +endif # TOOLCHAIN_COMMIT_DESC + +endif #MAKE_RESTARTS +endif #CONFIG_TOOLPREFIX diff --git a/make/project_config.mk b/make/project_config.mk new file mode 100644 index 0000000..0a212cd --- /dev/null +++ b/make/project_config.mk @@ -0,0 +1,97 @@ +# Makefile support for the menuconfig system + +#Find all Kconfig files for all components +COMPONENT_KCONFIGS := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig)) +COMPONENT_KCONFIGS_PROJBUILD := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig.projbuild)) + +#For doing make menuconfig etc +KCONFIG_TOOL_DIR=$(IDF_PATH)/tools/kconfig + +# set SDKCONFIG to the project's sdkconfig, +# unless it's overriden (happens for bootloader) +SDKCONFIG ?= $(PROJECT_PATH)/sdkconfig + +# SDKCONFIG_DEFAULTS is an optional file containing default +# overrides (usually used for esp-idf examples) +SDKCONFIG_DEFAULTS ?= $(PROJECT_PATH)/sdkconfig.defaults + +# reset MAKEFLAGS as the menuconfig makefile uses implicit compile rules +$(KCONFIG_TOOL_DIR)/mconf $(KCONFIG_TOOL_DIR)/conf: $(wildcard $(KCONFIG_TOOL_DIR)/*.c) + MAKEFLAGS="" CC=$(HOSTCC) LD=$(HOSTLD) \ + $(MAKE) -C $(KCONFIG_TOOL_DIR) + +ifeq ("$(wildcard $(SDKCONFIG))","") +ifeq ("$(filter defconfig clean% %clean, $(MAKECMDGOALS))","") +# if no configuration file is present and defconfig or clean +# is not a named target, run defconfig then menuconfig to get the initial config +$(SDKCONFIG): menuconfig +menuconfig: defconfig +else +# otherwise, just run defconfig +$(SDKCONFIG): defconfig +endif +endif + +# macro for the commands to run kconfig tools conf or mconf. +# $1 is the name (& args) of the conf tool to run +define RunConf + mkdir -p $(BUILD_DIR_BASE)/include/config + cd $(BUILD_DIR_BASE); KCONFIG_AUTOHEADER=$(abspath $(BUILD_DIR_BASE)/include/sdkconfig.h) \ + COMPONENT_KCONFIGS="$(COMPONENT_KCONFIGS)" KCONFIG_CONFIG=$(SDKCONFIG) \ + COMPONENT_KCONFIGS_PROJBUILD="$(COMPONENT_KCONFIGS_PROJBUILD)" \ + $(KCONFIG_TOOL_DIR)/$1 $(IDF_PATH)/Kconfig +endef + +ifndef MAKE_RESTARTS +# menuconfig, defconfig and "GENCONFIG" configuration generation only +# ever run on the first make pass, subsequent passes don't run these +# (make often wants to re-run them as the conf tool can regenerate the +# sdkconfig input file as an output file, but this is not what the +# user wants - a single config pass is enough to produce all output +# files.) +# +# To prevent problems missing genconfig, ensure none of these targets +# depend on any prerequisite that may cause a make restart as part of +# the prerequisite's own recipe. + +menuconfig: $(KCONFIG_TOOL_DIR)/mconf + $(summary) MENUCONFIG +ifdef BATCH_BUILD + @echo "Can't run interactive configuration inside non-interactive build process." + @echo "" + @echo "Open a command line terminal and run 'make menuconfig' from there." + @echo "See esp-idf documentation for more details." + @exit 1 +else + $(call RunConf,mconf) +endif + +# defconfig creates a default config, based on SDKCONFIG_DEFAULTS if present +defconfig: $(KCONFIG_TOOL_DIR)/conf + $(summary) DEFCONFIG +ifneq ("$(wildcard $(SDKCONFIG_DEFAULTS))","") + cat $(SDKCONFIG_DEFAULTS) >> $(SDKCONFIG) # append defaults to sdkconfig, will override existing values +endif + $(call RunConf,conf --olddefconfig) + +# if neither defconfig or menuconfig are requested, use the GENCONFIG rule to +# ensure generated config files are up to date +$(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h: $(KCONFIG_TOOL_DIR)/conf $(SDKCONFIG) $(COMPONENT_KCONFIGS) $(COMPONENT_KCONFIGS_PROJBUILD) | $(call prereq_if_explicit,defconfig) $(call prereq_if_explicit,menuconfig) + $(summary) GENCONFIG +ifdef BATCH_BUILD # can't prompt for new config values like on terminal + $(call RunConf,conf --olddefconfig) +endif + $(call RunConf,conf --silentoldconfig) + touch $(SDKCONFIG_MAKEFILE) $(BUILD_DIR_BASE)/include/sdkconfig.h # ensure newer than sdkconfig + +else # "$(MAKE_RESTARTS)" != "" +# on subsequent make passes, skip config generation entirely +defconfig: +menuconfig: +endif + +.PHONY: config-clean defconfig menuconfig +config-clean: + $(summary) RM CONFIG + MAKEFLAGS="" $(MAKE) -C $(KCONFIG_TOOL_DIR) clean + rm -rf $(BUILD_DIR_BASE)/include/config $(BUILD_DIR_BASE)/include/sdkconfig.h -- 2.11.4.GIT