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 */
#include
static __inline__ uint16_t crc_flash_check_has_error( void );
static __inline__ uint16_t crc_flash_check_has_error( void )
{
...
}
#endif
/*---------------------- Cut Line ----------------------------------*/