From 79ca00af4965caaa6a00f3abc4eaf2073c7074b0 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 25 Apr 2017 15:36:45 +0800 Subject: [PATCH] Add cleaner way to conditionally compile files --- docs/api-guides/build-system.rst | 55 ++++++++++++++++++++++++++++---- make/common.mk | 8 +++++ make/component_wrapper.mk | 28 +++++++++++++++- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/docs/api-guides/build-system.rst b/docs/api-guides/build-system.rst index aa4a67032..9c16a5507 100644 --- a/docs/api-guides/build-system.rst +++ b/docs/api-guides/build-system.rst @@ -396,7 +396,8 @@ Adding conditional configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The configuration system can be used to conditionally compile some files -depending on the options selected in ``make menuconfig``: +depending on the options selected in ``make menuconfig``. For this, ESP-IDF +has the compile_only_if and compile_only_if_not macros: ``Kconfig``:: @@ -407,14 +408,56 @@ depending on the options selected in ``make menuconfig``: ``component.mk``:: - COMPONENT_OBJS := foo_a.o foo_b.o + $(call compile_only_if,$(CONFIG_FOO_ENABLE_BAR),bar.o) - ifdef CONFIG_FOO_BAR - COMPONENT_OBJS += foo_bar.o foo_bar_interface.o - endif -See the `GNU Make Manual` for conditional syntax that can be used use in makefiles. +As can be seen in the example, the ``compile_only_if`` macro takes a condition and a +list of object files as parameters. If the condition is true (in this case: if the +BAR feature is enabled in menuconfig) the object files (in this case: bar.o) will +always be compiled. The opposite goes as well: if the condition is not true, bar.o +will never be compiled. ``compile_only_if_not`` does the opposite: compile if the +condition is false, not compile if the condition is true. +This can also be used to select or stub out an implementation, as such: + +``Kconfig``:: + + config ENABLE_LCD_OUTPUT + bool "Enable LCD output." + help + Select this if your board has a LCD. + + config ENABLE_LCD_CONSOLE + bool "Output console text to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output debugging output to the lcd + + config ENABLE_LCD_PLOT + bool "Output temperature plots to LCD" + depends on ENABLE_LCD_OUTPUT + help + Select this to output temperature plots + + +``component.mk``:: + + # If LCD is enabled, compile interface to it, otherwise compile dummy interface + $(call compile_only_if,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-real.o lcd-spi.o) + $(call compile_only_if_not,$(CONFIG_ENABLE_LCD_OUTPUT),lcd-dummy.o) + + #We need font if either console or plot is enabled + $(call compile_only_if,$(or $(CONFIG_ENABLE_LCD_CONSOLE),$(CONFIG_ENABLE_LCD_PLOT)), font.o) + +Note the use of the Make 'or' function to include the font file. Other substitution functions, +like 'and' and 'if' will also work here. Variables that do not come from menuconfig can also +be used: ESP-IDF uses the default Make policy of judging a variable which is empty or contains +only whitespace to be false while a variable with any non-whitespace in it is true. + +(Note: Older versions of this document advised conditionally adding object file names to +``COMPONENT_OBJS``. While this still is possible, this will only work when all object +files for a component are named explicitely, and will not clean up deselected object files +in a ``make clean`` pass.) Source Code Generation ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/make/common.mk b/make/common.mk index 24aebb4cc..82652e63d 100644 --- a/make/common.mk +++ b/make/common.mk @@ -73,3 +73,11 @@ endef 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_wrapper.mk b/make/component_wrapper.mk index 87c05479a..30269b601 100644 --- a/make/component_wrapper.mk +++ b/make/component_wrapper.mk @@ -46,6 +46,23 @@ COMPONENT_EMBED_TXTFILES ?= 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 + ################################################################################ # 2) Include the component.mk for the specific component (COMPONENT_MAKEFILE) to @@ -68,7 +85,16 @@ COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o 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 @@ -142,7 +168,7 @@ 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_EMBED_OBJS) $(COMPONENT_EXTRA_CLEAN) component_project_vars.mk +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)