Add cleaner way to conditionally compile files

This commit is contained in:
Jeroen Domburg 2017-04-25 15:36:45 +08:00
parent 2aadbee43c
commit 79ca00af49
3 changed files with 84 additions and 7 deletions

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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

View File

@ -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)