Mitch Frazier published a How To, Turn Make Options into Tool Flags, in The Linux Journal a couple of years ago, that I have found very useful in my Embedded development projects.
Using Mitch's technique I can have several different top level Makefiles to define options, source locations, and target output directories, that then includes a common Makefile called Makefile.mak. This allows me to build several variations of a product from the same set of sources, while keeping their options distinct and outputs separate.
Mitch's original technique is not MISRA friendly, as it relies on using 'ifdef', that is a missing option is considered a disabled option. MISRA does not allow this because the missing option may have been an oversight. Here is my modified MISRA friendly version:
Create a file called MakefileOptions.inc with the following code:
#---------------------- Cut Line ----------------------------------# # Option names that start with a minus sign are disabled by default, # option names without a minus sign are enabled by default. #CONFIG_OPTIONS=\ # OPTION_A \ # -OPTION_B \ # -OPTION_C SET_CONFIG_OPTIONS=$(filter-out -%,$(CONFIG_OPTIONS)) UNSET_CONFIG_OPTIONS=$(patsubst -%,%,$(filter -%,$(CONFIG_OPTIONS))) ALL_CONFIG_OPTIONS=$(SET_CONFIG_OPTIONS) $(UNSET_CONFIG_OPTIONS) #$(info Set: $(SET_CONFIG_OPTIONS)) #$(info Unset: $(UNSET_CONFIG_OPTIONS)) # Turn config options into make variables. $(foreach cfg,$(SET_CONFIG_OPTIONS),$(eval $(cfg)=1)) $(foreach cfg,$(UNSET_CONFIG_OPTIONS),$(eval $(cfg)=)) # Make sure none of the options are set to anything except 1 or blank. # Using "make OPTION=0" doesn't work, since "0" is set, you need "make OPTION=". $(foreach cfg,$(ALL_CONFIG_OPTIONS), \ $(if $(patsubst %1,%,$(value $(cfg))), \ $(error Use "$(cfg)=1" OR "$(cfg)=" not "$(cfg)=$(value $(cfg))"))) # Turn them into tool flags (-D). # if cfg > 0 True: False: TOOL_DEFINES+=$(foreach cfg,$(ALL_CONFIG_OPTIONS),$(if $(value $(cfg)),-D$(cfg)=1,-D$(cfg)=0)) #$(info $(TOOL_DEFINES)) #---------------------- Cut Line ----------------------------------#
A the top of your normal Makefile 'include' the above file like so:
include MakefileOptions.inc
The for a typical project I'll have a project uniquely named makefile, such as 'widget1.mak', that goes along these lines:
#---------------------- Cut Line ----------------------------------#
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
#
TARGET=Widget1
F_CPU=4000000
MCU=atxmega128a1
# Option names that start with a minus sign are disabled by default,
# option names without a minus sign are enabled by default.
# Values on the command line override these:
CONFIG_OPTIONS=\
-ENABLE_CHIRP \
ENABLE_LEDS \
HAVE_RADIO \
USE_CRC_FLASH_CHECK \
-USE_DEBUGGING \
-USE_MOTION_SETTING_SCREEN
# List C source files here. (C dependencies are automatically generated.)
SRC = Accel/accel.c \
MENU_WIDGET1/menu.c \
....
ASRC = HARDWARE_XMega/sp_ReadFuseByte.S HARDWARE_XMega/sp_commoncmd.S ...
EXTRAINCDIRS = MENU_WIDGET1 HARDWARE Accel Alarm Backlight Battery CRC ...
include Makefile.mak
#---------------------- Cut Line ----------------------------------#
Each project variation gets a similar file that is invoked with 'make -f widget1.mak'.
An example C usage:
/*---------------------- Cut Line ----------------------------------*/ #if( USE_CRC_FLASH_CHECK > 0 ) extern uint16_t __data_load_end[1]; /* Defined by the linker script. Set to address of last byte of .text+.data section */ #includestatic __inline__ uint16_t crc_flash_check_has_error( void ); static __inline__ uint16_t crc_flash_check_has_error( void ) { ... } #endif /*---------------------- Cut Line ----------------------------------*/