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
13 DMBS_BUILD_OPTIONAL_VARS
+= CPP_FLAGS ASM_FLAGS CC_FLAGS LD_FLAGS OBJDIR OBJECT_FILES DEBUG_TYPE
14 DMBS_BUILD_OPTIONAL_VARS
+= DEBUG_LEVEL LINKER_RELAXATIONS JUMP_TABLES LTO
15 DMBS_BUILD_PROVIDED_VARS
+=
16 DMBS_BUILD_PROVIDED_MACROS
+=
18 # Import the CORE module of DMBS
19 DMBS_MODULE_PATH
:= $(patsubst %/,%,$(dir $(lastword
$(MAKEFILE_LIST
))))
20 include $(DMBS_MODULE_PATH
)/core.mk
22 # Default values of optionally user-supplied variables
27 CPP_STANDARD ?
= gnu
++11
34 DEBUG_FORMAT ?
= dwarf-2
36 LINKER_RELAXATIONS ?
= Y
40 # Sanity check user supplied values
41 $(foreach MANDATORY_VAR
, $(DMBS_BUILD_MANDATORY_VARS
), $(call ERROR_IF_UNSET
, $(MANDATORY_VAR
)))
42 $(call ERROR_IF_EMPTY
, MCU
)
43 $(call ERROR_IF_EMPTY
, TARGET
)
44 $(call ERROR_IF_EMPTY
, ARCH
)
45 $(call ERROR_IF_EMPTY
, OPTIMIZATION
)
46 $(call ERROR_IF_EMPTY
, C_STANDARD
)
47 $(call ERROR_IF_EMPTY
, CPP_STANDARD
)
48 $(call ERROR_IF_EMPTY
, OBJDIR
)
49 $(call ERROR_IF_EMPTY
, DEBUG_FORMAT
)
50 $(call ERROR_IF_EMPTY
, DEBUG_LEVEL
)
51 $(call ERROR_IF_NONBOOL
, LINKER_RELAXATIONS
)
52 $(call ERROR_IF_NONBOOL
, JUMP_TABLES
)
53 $(call ERROR_IF_NONBOOL
, LTO
)
55 # Determine the utility prefix to use for the selected architecture
57 CROSS
:= $(COMPILER_PATH
)avr
58 else ifeq ($(ARCH
), XMEGA
)
59 CROSS
:= $(COMPILER_PATH
)avr
60 else ifeq ($(ARCH
), UC3
)
61 CROSS
:= $(COMPILER_PATH
)avr32
63 $(error Unsupported architecture
"$(ARCH)")
67 MSG_INFO_MESSAGE
:= ' [INFO] :'
68 MSG_COMPILE_CMD
:= ' [GCC] :'
69 MSG_ASSEMBLE_CMD
:= ' [GAS] :'
70 MSG_NM_CMD
:= ' [NM] :'
71 MSG_REMOVE_CMD
:= ' [RM] :'
72 MSG_LINK_CMD
:= ' [LNK] :'
73 MSG_ARCHIVE_CMD
:= ' [AR] :'
74 MSG_SIZE_CMD
:= ' [SIZE] :'
75 MSG_OBJCPY_CMD
:= ' [OBJCPY] :'
76 MSG_OBJDMP_CMD
:= ' [OBJDMP] :'
78 # Convert input source file list to differentiate them by type
79 C_SOURCE
:= $(filter %.c
, $(SRC
))
80 CPP_SOURCE
:= $(filter %.
cpp, $(SRC
))
81 ASM_SOURCE
:= $(filter %.S
, $(SRC
))
83 # Create a list of unknown source file types, if any are found throw an error
84 UNKNOWN_SOURCE
:= $(filter-out $(C_SOURCE
) $(CPP_SOURCE
) $(ASM_SOURCE
), $(SRC
))
85 ifneq ($(UNKNOWN_SOURCE
),)
86 $(error Unknown input source file formats
: $(UNKNOWN_SOURCE
))
89 # Convert input source filenames into a list of required output object files
90 OBJECT_FILES
+= $(addsuffix .o
, $(basename $(SRC
)))
92 # Check if an output object file directory was specified instead of the input file location
94 # Prefix all the object filenames with the output object file directory path
95 OBJECT_FILES
:= $(addprefix $(patsubst %/,%,$(OBJDIR
))/, $(notdir $(OBJECT_FILES
)))
97 # Check if any object file (without path) appears more than once in the object file list
98 ifneq ($(words $(sort $(OBJECT_FILES
))), $(words $(OBJECT_FILES
)))
99 $(error Cannot build with OBJDIR parameter set
- one or more object file name is not unique
)
102 # Create the output object file directory if it does not exist and add it to the virtual path list
103 $(shell mkdir
-p
$(OBJDIR
) 2> /dev
/null
)
104 VPATH
+= $(dir $(SRC
))
107 # Create a list of dependency files from the list of object files
108 DEPENDENCY_FILES
:= $(OBJECT_FILES
:%.o
=%.d
)
110 # Create a list of common flags to pass to the compiler/linker/assembler
111 BASE_CC_FLAGS
:= -pipe
-g
$(DEBUG_FORMAT
) -g
$(DEBUG_LEVEL
)
112 ifneq ($(findstring $(ARCH
), AVR8 XMEGA
),)
113 BASE_C_FLAGS
+= -fpack-struct
114 BASE_CC_FLAGS
+= -mmcu
=$(MCU
) -fshort-enums
-fno-inline-small-functions
115 else ifneq ($(findstring $(ARCH
), UC3
),)
116 BASE_CC_FLAGS
+= -mpart
=$(MCU
:at32
%=%) -masm-addr-pseudos
118 BASE_CC_FLAGS
+= -Wall
-fno-strict-aliasing
-funsigned-char
-funsigned-bitfields
-ffunction-sections
120 BASE_CC_FLAGS
+= -DARCH
=ARCH_
$(ARCH
) -DDMBS_ARCH_
$(ARCH
)
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
) -fno-exceptions
-fno-threadsafe-statics
135 BASE_ASM_FLAGS
:= -x assembler-with-cpp
137 BASE_C_FLAGS
+= -DF_CPU
=$(F_CPU
)UL
138 BASE_CPP_FLAGS
+= -DF_CPU
=$(F_CPU
)UL
139 BASE_ASM_FLAGS
+= -DF_CPU
=$(F_CPU
)
141 # Create a list of flags to pass to the linker
142 BASE_LD_FLAGS
:= -lm
-Wl
,-Map
=$(TARGET
).map
,--cref
-Wl
,--gc-sections
143 ifeq ($(LINKER_RELAXATIONS
), Y
)
144 BASE_LD_FLAGS
+= -Wl
,--relax
146 ifneq ($(findstring $(ARCH
), AVR8 XMEGA
),)
147 BASE_LD_FLAGS
+= -mmcu
=$(MCU
)
148 else ifneq ($(findstring $(ARCH
), UC3
),)
149 BASE_LD_FLAGS
+= -mpart
=$(MCU
:at32
%=%) --rodata-writable
--direct-data
152 # Enable link time optimization to reduce overall flash size.
153 BASE_CC_FLAGS
+= -flto
-fuse-linker-plugin
154 BASE_LD_FLAGS
+= -flto
-fuse-linker-plugin
157 # Determine flags to pass to the size utility based on its reported features (only invoke if size target required)
158 # and on an architecture where this non-standard patch is available
160 size
: SIZE_MCU_FLAG
:= $(shell $(CROSS
)-size
--help | grep
-- --mcu
> /dev
/null
&& echo
--mcu
=$(MCU
) )
161 size
: SIZE_FORMAT_FLAG
:= $(shell $(CROSS
)-size
--help | grep
-- --format
=.
*avr
> /dev
/null
&& echo
--format
=avr
)
164 # Pre-build informational target, to give compiler and project name information when building
166 @echo
$(MSG_INFO_MESSAGE
) Begin compilation of project
\"$(TARGET
)\"...
168 @
$(CROSS
)-gcc
--version
170 # Post-build informational target, to project name information when building has completed
172 @echo
$(MSG_INFO_MESSAGE
) Finished building project
\"$(TARGET
)\".
174 # Prints size information of a compiled application (FLASH, RAM and EEPROM usages)
176 @echo
$(MSG_SIZE_CMD
) Determining size of
\"$<\"
178 $(CROSS
)-size
$(SIZE_MCU_FLAG
) $(SIZE_FORMAT_FLAG
) $<
180 # Prints size information on the symbols within a compiled application in decimal bytes
181 symbol-sizes
: $(TARGET
).elf
182 @echo
$(MSG_NM_CMD
) Extracting
\"$<\" symbols with decimal byte sizes
183 $(CROSS
)-nm
--size-sort
--demangle
--radix
=d
$<
185 # Cleans intermediary build files, leaving only the compiled application files
187 @echo
$(MSG_REMOVE_CMD
) Removing object files of
\"$(TARGET
)\"
188 rm -f
$(OBJECT_FILES
)
189 @echo
$(MSG_REMOVE_CMD
) Removing dependency files of
\"$(TARGET
)\"
190 rm -f
$(DEPENDENCY_FILES
)
192 # Cleans all build files, leaving only the original source code
194 @echo
$(MSG_REMOVE_CMD
) Removing output files of
\"$(TARGET
)\"
195 rm -f
$(TARGET
).elf
$(TARGET
).hex
$(TARGET
).bin
$(TARGET
).eep
$(TARGET
).map
$(TARGET
).lss
$(TARGET
).sym lib
$(TARGET
).a
197 # Performs a complete build of the user application and prints size information afterwards
198 all: build_begin elf hex bin lss sym size build_end
200 # Helper targets, to build a specific type of output file without having to know the project target name
203 hex
: $(TARGET
).hex
$(TARGET
).eep
208 # Default target to *create* the user application's specified source files; if this rule is executed by
209 # make, the input source file doesn't exist and an error needs to be presented to the user
211 $(error Source file does not exist
: $@
)
213 # Compiles an input C source file and generates an assembly listing for it
214 %.s
: %.c
$(MAKEFILE_LIST
)
215 @echo
$(MSG_COMPILE_CMD
) Generating assembly from C file
\"$(notdir $<)\"
216 $(CROSS
)-gcc
-S
$(BASE_CC_FLAGS
) $(BASE_C_FLAGS
) $(CC_FLAGS
) $(C_FLAGS
) $($(notdir $<)_FLAGS
) $< -o
$@
218 # Compiles an input C++ source file and generates an assembly listing for it
219 %.s
: %.
cpp $(MAKEFILE_LIST
)
220 @echo
$(MSG_COMPILE_CMD
) Generating assembly from C
++ file
\"$(notdir $<)\"
221 $(CROSS
)-gcc
-S
$(BASE_CC_FLAGS
) $(BASE_CPP_FLAGS
) $(CC_FLAGS
) $(CPP_FLAGS
) $($(notdir $<)_FLAGS
) $< -o
$@
223 # Compiles an input C source file and generates a linkable object file for it
224 $(OBJDIR
)/%.o
: %.c
$(MAKEFILE_LIST
)
225 @echo
$(MSG_COMPILE_CMD
) Compiling C file
\"$(notdir $<)\"
226 $(CROSS
)-gcc
-c
$(BASE_CC_FLAGS
) $(BASE_C_FLAGS
) $(CC_FLAGS
) $(C_FLAGS
) $($(notdir $<)_FLAGS
) -MMD
-MP
-MF
$(@
:%.o
=%.d
) $< -o
$@
228 # Compiles an input C++ source file and generates a linkable object file for it
229 $(OBJDIR
)/%.o
: %.
cpp $(MAKEFILE_LIST
)
230 @echo
$(MSG_COMPILE_CMD
) Compiling C
++ file
\"$(notdir $<)\"
231 $(CROSS
)-gcc
-c
$(BASE_CC_FLAGS
) $(BASE_CPP_FLAGS
) $(CC_FLAGS
) $(CPP_FLAGS
) $($(notdir $<)_FLAGS
) -MMD
-MP
-MF
$(@
:%.o
=%.d
) $< -o
$@
233 # Assembles an input ASM source file and generates a linkable object file for it
234 $(OBJDIR
)/%.o
: %.S
$(MAKEFILE_LIST
)
235 @echo
$(MSG_ASSEMBLE_CMD
) Assembling
\"$(notdir $<)\"
236 $(CROSS
)-gcc
-c
$(BASE_CC_FLAGS
) $(BASE_ASM_FLAGS
) $(CC_FLAGS
) $(ASM_FLAGS
) $($(notdir $<)_FLAGS
) -MMD
-MP
-MF
$(@
:%.o
=%.d
) $< -o
$@
238 # Generates a library archive file from the user application, which can be linked into other applications
239 .PRECIOUS
: $(OBJECT_FILES
)
242 @echo
$(MSG_ARCHIVE_CMD
) Archiving object files into
\"$@
\"
243 $(CROSS
)-ar rcs
$@
$(OBJECT_FILES
)
245 # Generates an ELF debug file from the user application, which can be further processed for FLASH and EEPROM data
246 # files, or used for programming and debugging directly
247 .PRECIOUS
: $(OBJECT_FILES
)
249 %.elf
: $(OBJECT_FILES
)
250 @echo
$(MSG_LINK_CMD
) Linking object files into
\"$@
\"
251 $(CROSS
)-gcc
$^
-o
$@
$(BASE_LD_FLAGS
) $(LD_FLAGS
)
253 # Extracts out the loadable FLASH memory data from the project ELF file, and creates an Intel HEX format file of it
255 @echo
$(MSG_OBJCPY_CMD
) Extracting HEX file data from
\"$<\"
256 $(CROSS
)-objcopy
-O ihex
-R .eeprom
-R .fuse
-R .lock
-R .signature
$< $@
258 # Extracts out the loadable FLASH memory data from the project ELF file, and creates an Binary format file of it
260 @echo
$(MSG_OBJCPY_CMD
) Extracting BIN file data from
\"$<\"
261 $(CROSS
)-objcopy
-O binary
-R .eeprom
-R .fuse
-R .lock
-R .signature
$< $@
263 # Extracts out the loadable EEPROM memory data from the project ELF file, and creates an Intel HEX format file of it
265 @echo
$(MSG_OBJCPY_CMD
) Extracting EEP file data from
\"$<\"
266 $(CROSS
)-objcopy
-O ihex
-j .eeprom
--set-section-flags
=.eeprom
="alloc,load" --change-section-lma .eeprom
=0 --no-change-warnings
$< $@ || exit
0
268 # Creates an assembly listing file from an input project ELF file, containing interleaved assembly and source data
270 @echo
$(MSG_OBJDMP_CMD
) Extracting LSS file data from
\"$<\"
271 $(CROSS
)-objdump
-h
-d
-S
-z
$< > $@
273 # Creates a symbol file listing the loadable and discarded symbols from an input project ELF file
275 @echo
$(MSG_NM_CMD
) Extracting SYM file data from
\"$<\"
276 $(CROSS
)-nm
-n
$< > $@
278 # Include build dependency files
279 -include $(DEPENDENCY_FILES
)
281 # Phony build targets for this module
282 .PHONY
: build_begin build_end
$(DMBS_BUILD_TARGETS
)