3 #     Released into the public domain. 
   5 #  dean [at] fourwalledcubicle [dot] com 
   6 #        www.fourwalledcubicle.com 
   9 DMBS_BUILD_MODULES         
+= GCC
 
  10 DMBS_BUILD_TARGETS         
+= size symbol-sizes 
all lib elf bin hex lss 
clean mostlyclean 
  11 DMBS_BUILD_MANDATORY_VARS  
+= TARGET ARCH MCU SRC
 
  12 DMBS_BUILD_OPTIONAL_VARS   
+= COMPILER_PATH OPTIMIZATION C_STANDARD CPP_STANDARD F_CPU C_FLAGS CPP_FLAGS ASM_FLAGS CC_FLAGS LD_FLAGS OBJDIR OBJECT_FILES DEBUG_TYPE DEBUG_LEVEL LINKER_RELAXATIONS JUMP_TABLES
 
  13 DMBS_BUILD_PROVIDED_VARS   
+= 
  14 DMBS_BUILD_PROVIDED_MACROS 
+= 
  16 # Conditionally import the CORE module of DMBS if it is not already imported 
  17 DMBS_MODULE_PATH 
:= $(patsubst %/,%,$(dir $(lastword 
$(MAKEFILE_LIST
)))) 
  18 ifeq ($(findstring CORE
, $(DMBS_BUILD_MODULES
)),) 
  19   include $(DMBS_MODULE_PATH
)/core.mk
 
  22 # Default values of optionally user-supplied variables 
  27 CPP_STANDARD       ?
= gnu
++98 
  34 DEBUG_FORMAT       ?
= dwarf-2
 
  36 LINKER_RELAXATIONS ?
= Y
 
  39 # Sanity check user supplied values 
  40 $(foreach MANDATORY_VAR
, $(DMBS_BUILD_MANDATORY_VARS
), $(call ERROR_IF_UNSET
, $(MANDATORY_VAR
))) 
  41 $(call ERROR_IF_EMPTY
, MCU
) 
  42 $(call ERROR_IF_EMPTY
, TARGET
) 
  43 $(call ERROR_IF_EMPTY
, ARCH
) 
  44 $(call ERROR_IF_EMPTY
, OPTIMIZATION
) 
  45 $(call ERROR_IF_EMPTY
, C_STANDARD
) 
  46 $(call ERROR_IF_EMPTY
, CPP_STANDARD
) 
  47 $(call ERROR_IF_EMPTY
, OBJDIR
) 
  48 $(call ERROR_IF_EMPTY
, DEBUG_FORMAT
) 
  49 $(call ERROR_IF_EMPTY
, DEBUG_LEVEL
) 
  50 $(call ERROR_IF_NONBOOL
, LINKER_RELAXATIONS
) 
  51 $(call ERROR_IF_NONBOOL
, JUMP_TABLES
) 
  53 # Determine the utility prefix to use for the selected architecture 
  55    CROSS        
:= $(COMPILER_PATH
)avr
 
  56 else ifeq ($(ARCH
), XMEGA
) 
  57    CROSS        
:= $(COMPILER_PATH
)avr
 
  58 else ifeq ($(ARCH
), UC3
) 
  59    CROSS        
:= $(COMPILER_PATH
)avr32
 
  61    $(error Unsupported architecture 
"$(ARCH)") 
  65 MSG_INFO_MESSAGE 
:= ' [INFO]    :' 
  66 MSG_COMPILE_CMD  
:= ' [GCC]     :' 
  67 MSG_ASSEMBLE_CMD 
:= ' [GAS]     :' 
  68 MSG_NM_CMD       
:= ' [NM]      :' 
  69 MSG_REMOVE_CMD   
:= ' [RM]      :' 
  70 MSG_LINK_CMD     
:= ' [LNK]     :' 
  71 MSG_ARCHIVE_CMD  
:= ' [AR]      :' 
  72 MSG_SIZE_CMD     
:= ' [SIZE]    :' 
  73 MSG_OBJCPY_CMD   
:= ' [OBJCPY]  :' 
  74 MSG_OBJDMP_CMD   
:= ' [OBJDMP]  :' 
  76 # Convert input source file list to differentiate them by type 
  77 C_SOURCE   
:= $(filter %.c
, $(SRC
)) 
  78 CPP_SOURCE 
:= $(filter %.
cpp, $(SRC
)) 
  79 ASM_SOURCE 
:= $(filter %.S
, $(SRC
)) 
  81 # Create a list of unknown source file types, if any are found throw an error 
  82 UNKNOWN_SOURCE 
:= $(filter-out $(C_SOURCE
) $(CPP_SOURCE
) $(ASM_SOURCE
), $(SRC
)) 
  83 ifneq ($(UNKNOWN_SOURCE
),) 
  84    $(error Unknown input source file formats
: $(UNKNOWN_SOURCE
)) 
  87 # Convert input source filenames into a list of required output object files 
  88 OBJECT_FILES 
+= $(addsuffix .o
, $(basename $(SRC
))) 
  90 # Check if an output object file directory was specified instead of the input file location 
  92    # Prefix all the object filenames with the output object file directory path 
  93    OBJECT_FILES    
:= $(addprefix $(patsubst %/,%,$(OBJDIR
))/, $(notdir $(OBJECT_FILES
))) 
  95    # Check if any object file (without path) appears more than once in the object file list 
  96    ifneq ($(words $(sort $(OBJECT_FILES
))), $(words $(OBJECT_FILES
))) 
  97        $(error Cannot build with OBJDIR parameter set 
- one or more object file name is not unique
) 
 100    # Create the output object file directory if it does not exist and add it to the virtual path list 
 101    $(shell mkdir 
-p 
$(OBJDIR
) 2> /dev
/null
) 
 102    VPATH           
+= $(dir $(SRC
)) 
 105 # Create a list of dependency files from the list of object files 
 106 DEPENDENCY_FILES 
:= $(OBJECT_FILES
:%.o
=%.d
) 
 108 # Create a list of common flags to pass to the compiler/linker/assembler 
 109 BASE_CC_FLAGS    
:= -pipe 
-g
$(DEBUG_FORMAT
) -g
$(DEBUG_LEVEL
) 
 110 ifneq ($(findstring $(ARCH
), AVR8 XMEGA
),) 
 111    BASE_CC_FLAGS 
+= -mmcu
=$(MCU
) -fshort-enums 
-fno-inline-small-functions 
-fpack-struct
 
 112 else ifneq ($(findstring $(ARCH
), UC3
),) 
 113    BASE_CC_FLAGS 
+= -mpart
=$(MCU
:at32
%=%) -masm-addr-pseudos
 
 115 BASE_CC_FLAGS 
+= -Wall 
-fno-strict-aliasing 
-funsigned-char 
-funsigned-bitfields 
-ffunction-sections
 
 117 BASE_CC_FLAGS 
+= -DARCH
=ARCH_
$(ARCH
) 
 119    BASE_CC_FLAGS 
+= -DF_CPU
=$(F_CPU
)UL
 
 121 ifeq ($(LINKER_RELAXATIONS
), Y
) 
 122    BASE_CC_FLAGS 
+= -mrelax
 
 124 ifeq ($(JUMP_TABLES
), N
) 
 125    # This flag is required for bootloaders as GCC will emit invalid jump table 
 126    # assembly code for devices with large amounts of flash; the jump table target 
 127    # is extracted from FLASH without using the correct ELPM instruction, resulting 
 128    # in a pseudo-random jump target. 
 129    BASE_CC_FLAGS 
+= -fno-jump-tables
 
 132 # Additional language specific compiler flags 
 133 BASE_C_FLAGS   
:= -x c 
-O
$(OPTIMIZATION
) -std
=$(C_STANDARD
) -Wstrict-prototypes
 
 134 BASE_CPP_FLAGS 
:= -x c
++ -O
$(OPTIMIZATION
) -std
=$(CPP_STANDARD
) 
 135 BASE_ASM_FLAGS 
:= -x assembler-with-cpp
 
 137 # Create a list of flags to pass to the linker 
 138 BASE_LD_FLAGS 
:= -lm 
-Wl
,-Map
=$(TARGET
).map
,--cref 
-Wl
,--gc-sections
 
 139 ifeq ($(LINKER_RELAXATIONS
), Y
) 
 140    BASE_LD_FLAGS 
+= -Wl
,--relax
 
 142 ifneq ($(findstring $(ARCH
), AVR8 XMEGA
),) 
 143    BASE_LD_FLAGS 
+= -mmcu
=$(MCU
) 
 144 else ifneq ($(findstring $(ARCH
), UC3
),) 
 145    BASE_LD_FLAGS 
+= -mpart
=$(MCU
:at32
%=%) --rodata-writable 
--direct-data
 
 148 # Determine flags to pass to the size utility based on its reported features (only invoke if size target required) 
 149 # and on an architecture where this non-standard patch is available 
 151 size
: SIZE_MCU_FLAG    
:= $(shell $(CROSS
)-size 
--help | grep 
-- --mcu 
> /dev
/null 
&& echo 
--mcu
=$(MCU
) ) 
 152 size
: SIZE_FORMAT_FLAG 
:= $(shell $(CROSS
)-size 
--help | grep 
-- --format
=.
*avr 
> /dev
/null 
&& echo 
--format
=avr 
) 
 155 # Pre-build informational target, to give compiler and project name information when building 
 157         @echo 
$(MSG_INFO_MESSAGE
) Begin compilation of project 
\"$(TARGET
)\"...
 
 159         @
$(CROSS
)-gcc 
--version
 
 161 # Post-build informational target, to project name information when building has completed 
 163         @echo 
$(MSG_INFO_MESSAGE
) Finished building project 
\"$(TARGET
)\".
 
 165 # Prints size information of a compiled application (FLASH, RAM and EEPROM usages) 
 167         @echo 
$(MSG_SIZE_CMD
) Determining size of 
\"$<\" 
 169         $(CROSS
)-size 
$(SIZE_MCU_FLAG
) $(SIZE_FORMAT_FLAG
) $< 
 171 # Prints size information on the symbols within a compiled application in decimal bytes 
 172 symbol-sizes
: $(TARGET
).elf
 
 173         @echo 
$(MSG_NM_CMD
) Extracting 
\"$<\" symbols with decimal byte sizes
 
 174         $(CROSS
)-nm 
--size-sort 
--demangle 
--radix
=d 
$< 
 176 # Cleans intermediary build files, leaving only the compiled application files 
 178         @echo 
$(MSG_REMOVE_CMD
) Removing object files of 
\"$(TARGET
)\" 
 179         rm -f 
$(OBJECT_FILES
) 
 180         @echo 
$(MSG_REMOVE_CMD
) Removing dependency files of 
\"$(TARGET
)\" 
 181         rm -f 
$(DEPENDENCY_FILES
) 
 183 # Cleans all build files, leaving only the original source code 
 185         @echo 
$(MSG_REMOVE_CMD
) Removing output files of 
\"$(TARGET
)\" 
 186         rm -f 
$(TARGET
).elf 
$(TARGET
).hex 
$(TARGET
).bin 
$(TARGET
).eep 
$(TARGET
).map 
$(TARGET
).lss 
$(TARGET
).sym lib
$(TARGET
).a
 
 188 # Performs a complete build of the user application and prints size information afterwards 
 189 all: build_begin elf hex bin lss sym size build_end
 
 191 # Helper targets, to build a specific type of output file without having to know the project target name 
 194 hex
: $(TARGET
).hex 
$(TARGET
).eep
 
 199 # Default target to *create* the user application's specified source files; if this rule is executed by 
 200 # make, the input source file doesn't exist and an error needs to be presented to the user 
 202         $(error Source file does not exist
: $@
) 
 204 # Compiles an input C source file and generates an assembly listing for it 
 205 %.s
: %.c 
$(MAKEFILE_LIST
) 
 206         @echo 
$(MSG_COMPILE_CMD
) Generating assembly from C file 
\"$(notdir $<)\" 
 207         $(CROSS
)-gcc 
-S 
$(BASE_CC_FLAGS
) $(BASE_C_FLAGS
) $(CC_FLAGS
) $(C_FLAGS
) $< -o 
$@
 
 209 # Compiles an input C++ source file and generates an assembly listing for it 
 210 %.s
: %.
cpp $(MAKEFILE_LIST
) 
 211         @echo 
$(MSG_COMPILE_CMD
) Generating assembly from C
++ file 
\"$(notdir $<)\" 
 212         $(CROSS
)-gcc 
-S 
$(BASE_CC_FLAGS
) $(BASE_CPP_FLAGS
) $(CC_FLAGS
) $(CPP_FLAGS
) $< -o 
$@
 
 214 # Compiles an input C source file and generates a linkable object file for it 
 215 $(OBJDIR
)/%.o
: %.c 
$(MAKEFILE_LIST
) 
 216         @echo 
$(MSG_COMPILE_CMD
) Compiling C file 
\"$(notdir $<)\" 
 217         $(CROSS
)-gcc 
-c 
$(BASE_CC_FLAGS
) $(BASE_C_FLAGS
) $(CC_FLAGS
) $(C_FLAGS
) -MMD 
-MP 
-MF 
$(@
:%.o
=%.d
) $< -o 
$@
 
 219 # Compiles an input C++ source file and generates a linkable object file for it 
 220 $(OBJDIR
)/%.o
: %.
cpp $(MAKEFILE_LIST
) 
 221         @echo 
$(MSG_COMPILE_CMD
) Compiling C
++ file 
\"$(notdir $<)\" 
 222         $(CROSS
)-gcc 
-c 
$(BASE_CC_FLAGS
) $(BASE_CPP_FLAGS
) $(CC_FLAGS
) $(CPP_FLAGS
) -MMD 
-MP 
-MF 
$(@
:%.o
=%.d
) $< -o 
$@
 
 224 # Assembles an input ASM source file and generates a linkable object file for it 
 225 $(OBJDIR
)/%.o
: %.S 
$(MAKEFILE_LIST
) 
 226         @echo 
$(MSG_ASSEMBLE_CMD
) Assembling 
\"$(notdir $<)\" 
 227         $(CROSS
)-gcc 
-c 
$(BASE_CC_FLAGS
) $(BASE_ASM_FLAGS
) $(CC_FLAGS
) $(ASM_FLAGS
) -MMD 
-MP 
-MF 
$(@
:%.o
=%.d
) $< -o 
$@
 
 229 # Generates a library archive file from the user application, which can be linked into other applications 
 230 .PRECIOUS  
: $(OBJECT_FILES
) 
 233         @echo 
$(MSG_ARCHIVE_CMD
) Archiving object files into 
\"$@
\" 
 234         $(CROSS
)-ar rcs 
$@ 
$(OBJECT_FILES
) 
 236 # Generates an ELF debug file from the user application, which can be further processed for FLASH and EEPROM data 
 237 # files, or used for programming and debugging directly 
 238 .PRECIOUS  
: $(OBJECT_FILES
) 
 240 %.elf
: $(OBJECT_FILES
) 
 241         @echo 
$(MSG_LINK_CMD
) Linking object files into 
\"$@
\" 
 242         $(CROSS
)-gcc 
$^ 
-o 
$@ 
$(BASE_LD_FLAGS
) $(LD_FLAGS
) 
 244 # Extracts out the loadable FLASH memory data from the project ELF file, and creates an Intel HEX format file of it 
 246         @echo 
$(MSG_OBJCPY_CMD
) Extracting HEX file data from 
\"$<\" 
 247         $(CROSS
)-objcopy 
-O ihex 
-R .eeprom 
-R .fuse 
-R .lock 
-R .signature 
$< $@
 
 249 # Extracts out the loadable FLASH memory data from the project ELF file, and creates an Binary format file of it 
 251         @echo 
$(MSG_OBJCPY_CMD
) Extracting BIN file data from 
\"$<\" 
 252         $(CROSS
)-objcopy 
-O binary 
-R .eeprom 
-R .fuse 
-R .lock 
-R .signature 
$< $@
 
 254 # Extracts out the loadable EEPROM memory data from the project ELF file, and creates an Intel HEX format file of it 
 256         @echo 
$(MSG_OBJCPY_CMD
) Extracting EEP file data from 
\"$<\" 
 257         $(CROSS
)-objcopy 
-O ihex 
-j .eeprom 
--set-section-flags
=.eeprom
="alloc,load" --change-section-lma .eeprom
=0 --no-change-warnings 
$< $@ || exit 
0 
 259 # Creates an assembly listing file from an input project ELF file, containing interleaved assembly and source data 
 261         @echo 
$(MSG_OBJDMP_CMD
) Extracting LSS file data from 
\"$<\" 
 262         $(CROSS
)-objdump 
-h 
-d 
-S 
-z 
$< > $@
 
 264 # Creates a symbol file listing the loadable and discarded symbols from an input project ELF file 
 266         @echo 
$(MSG_NM_CMD
) Extracting SYM file data from 
\"$<\" 
 267         $(CROSS
)-nm 
-n 
$< > $@
 
 269 # Include build dependency files 
 270 -include $(DEPENDENCY_FILES
) 
 272 # Phony build targets for this module 
 273 .PHONY
: build_begin build_end 
$(DMBS_BUILD_TARGETS
)