Хотелось, чтобы после задания произвольного количества файлов исходного кода их компиляция в объектные файлы происходила без явного создания правил для каждого из них. Также желательно не использовать сторонние средства (внешние скриптовые языки, Perl, Python и проч.), а ограничиться возможностями языка Makefile.
В результате получился следующий файл:
# Выбор типа ядра контроллера MCU = cortex-m4 # Адрес начала внутренней FLASH-памяти контроллера LOADADDRESS = 0x08000000 # Использовать драйверы периферийных устройств, предоставленные ST. # Компиляция для контроллеров серии STM32F373x DEFINES = -DUSE_STDPERIPH_DRIVER -DSTM32F373xC # Путь к каталогу драйверов периферии контроллера и вспомогательных библиотек BASEDIRNAME = /c/STM32Cube/Repository/STM32Cube_FW_L1_V1.6.0/ # Скрипт линковщика, специфичный для контроллера # Возможно, придётся забрать его в каталог проекта, # и внести изменения (размер стека, объём внутренней # FLASH- и RAM-памяти) LDSCRIPT = $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Source/Templates/gcc/linker/STM32F373XC_FLASH.ld # Путь к каталогу кросскомпилятора GCCDIRNAME = /c/gcc-arm-none-eabi-5_3-2016q1-20160330-win32/bin/ # Префикс кросскомпилятора PREFIX = arm-none-eabi- # Файл конфигурации OpenOCD для программирования заданного контроллера OPENOCDBOARD = stm32f3discovery.cfg # Путь к каталогу OpenOCD PROGRAMMERDIR = /c/openocd-0.9.0/ # Путь к исполняемому файлу OpenOCD, для разных платформ у него разные имена PROGRAMMERBIN = $(PROGRAMMERDIR)bin-x64/openocd.exe # Если программируем самодельную плату, то используется один файл конфигурации # Для демонстрационной платы -- другой ifdef OPENOCDINTERFACE OPENOCDCONFIG = -f $(PROGRAMMERDIR)scripts/interface/$(OPENOCDINTERFACE) else ifdef OPENOCDBOARD OPENOCDCONFIG = -f $(PROGRAMMERDIR)scripts/board/$(OPENOCDBOARD) else $(error "Not defined OPENOCDINTERFACE or OPENOCDBOARD") endif # Команды OpenOCD для загрузки файла в контроллер OPENOCDLOAD = "program result.bin $(LOADADDRESS) verify" OPENOCDPROGRAM =\ $(OPENOCDCONFIG)\ -c "init"\ -c "halt"\ -c $(OPENOCDLOAD)\ -c "reset run"\ -c "shutdown" ## To unlock chip use next commands after "halt": # -c "flash protect 0 0 last off"\ # -c "shutdown" # Для компиляции всех типов файлов и линковки используем gcc.exe # Он сам разберётся, что вызывать для переданного файла AS = $(GCCDIRNAME)$(PREFIX)gcc CC = $(GCCDIRNAME)$(PREFIX)gcc CXX = $(GCCDIRNAME)$(PREFIX)gcc LD = $(GCCDIRNAME)$(PREFIX)gcc # Получение листинга из объектного файла OBJDUMP = $(GCCDIRNAME)$(PREFIX)objdump # Преобразование между форматами бинарных файлов OBJCOPY = $(GCCDIRNAME)$(PREFIX)objcopy OFLAGS = -Os CXXSTANDARD = -std=c++11 CSTANDARD = -std=c11 # Каталоги, в которых будут искаться заголовочные файлы INCLUDES = $(shell pwd)/ INCLUDES += $(BASEDIRNAME)Drivers/CMSIS/Include/ INCLUDES += $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Include/ INCLUDES += $(BASEDIRNAME)Drivers/STM32F3xx_HAL_Driver/Inc/ # Флаги, общие для почти всех команд сборки проекта COMMONFLAGS = -mcpu=$(MCU) -mthumb -MD $(INCLUDES:%=-I%) -c # Флаги, специфичные для компиляции ассемблерных файлов ASFLAGS += $(COMMONFLAGS) # Любые файлы, переданные в переменную ASFILES, трактовать, как ассемблерные ASFLAGS += -x assembler-with-cpp # Флаги, специфичные для компиляции файлов C CFLAGS += $(COMMONFLAGS) CFLAGS += $(CSTANDARD) CFLAGS += $(OFLAGS) CFLAGS += $(DEFINES) CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CFLAGS += -Wall CFLAGS += -fno-exceptions -ffunction-sections -fdata-sections -Wextra -Winline -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -pedantic CFLAGS += -ggdb3 # Любые файлы, переданные в переменную CFILES, трактовать как файлы C CFLAGS += -x c # Флаги, специфичные для файлов C++ CXXFLAGS += $(COMMONFLAGS) CXXFLAGS += $(CXXSTANDARD) CXXFLAGS += $(OFLAGS) CXXFLAGS += $(DEFINES) CXXFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CXXFLAGS += -Wall CXXFLAGS += -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -Wextra -Winline -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -pedantic CXXFLAGS += -ggdb3 # Любые файлы, переданные в переменную CXXFILES, трактовать как файлы C++ CXXFLAGS += -x c++ # Флаги, специфичные для линкера LDFLAGS += -Wl,-Map=$(TARGET).map -Wl,--cref LDFLAGS += -Wl,--start-group -lc_nano -lrdimon_nano -lm -Wl,--end-group LDFLAGS += -Wl,--gc-sections # Из переменной COMMONFLAGS забираем элементы с первого по второй LDFLAGS += $(wordlist 1, 2, $(COMMONFLAGS)) OBJCOPYFLAGS = -O binary OBJDUMPFLAGS += -x -S # Объектные и промежуточные файлы сохраняются в этом каталоге, чтобы не засорять проект OBJDIR = ./obj/ -include $(shell mkdir $(OBJDIR) 2> /dev/null) $(wildcard $(OBJDIR)\*) # Из каталога с данным Makefile разбираем ассемблерные файлы, # файлы C и C++ по соответствующим переменным ASFILES = $(wildcard *.s *.S *.asm) CFILES = $(wildcard *.c) CXXFILES = $(wildcard *.cpp) # Добавляем файлы в проект ASFILES += $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Source/Templates/gcc/startup_stm32f373xc.s CFILES += $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Source/Templates/system_stm32f3xx.c CXXFILES += # Объектные файлы будут с именем соответствующих файлов исходников, # с добавлением расширения .o # Таким образом, на сей момент недопустимо наличие в проекте # файлов с одинаковыми именами для каждого из типов (asm, C, C++). # В дальнейшем надеюсь это поправить ASOBJFILES = $(patsubst %,$(OBJDIR)%,$(notdir $(ASFILES:%=%.o))) COBJFILES = $(patsubst %,$(OBJDIR)%,$(notdir $(CFILES:%=%.o))) CXXOBJFILES = $(patsubst %,$(OBJDIR)%,$(notdir $(CXXFILES:%=%.o))) .PHONY : clean all program # Из элементов переменной *FILES для компиляции выбирается файл, # имя и расширение которого совпадают с одним из элементов # переменной *OBJFILES с отброшенным расширением .o # Если в переменной *FILES окажутся файлы с одинаковыми именами # и расширениями, то компиляция пройдёт некорректно. $(ASOBJFILES) : $(ASFILES) @echo "-> compiling $@ as ASM-file" $(AS) $(ASFLAGS) $(filter %$(notdir $(@:%.o=%)),$^) -o $@ $(COBJFILES) : $(CFILES) @echo "-> compiling $@ as C-file" $(CC) $(CFLAGS) $(filter %$(notdir $(@:%.o=%)),$^) -o $@ $(OBJDUMP) $(OBJDUMPFLAGS) $@ > $(@:%.o=%.lst) $(CXXOBJFILES) : $(CXXFILES) @echo "-> compiling $@ as C++-file" $(CXX) $(CXXFLAGS) $(filter %$(notdir $(@:%.o=%)),$^) -o $@ $(OBJDUMP) $(OBJDUMPFLAGS) $@ > $(@:%.o=%.lst) # Сборка axf-файла из полученных объектных файлов result.axf : $(ASOBJFILES) $(COBJFILES) $(CXXOBJFILES) @echo "-> linking" $(LD) -T$(LDSCRIPT) $^ $(LDFLAGS) -o $@ # Преобразование axf-файла в бинарный, и получение ассемблерного листинга all : result.axf @echo "-> copying" $(OBJCOPY) $(OBJCOPYFLAGS) $^ result.bin $(OBJDUMP) $(OBJDUMPFLAGS) $^ > result.lst # Заливка бинарного файла в контроллер program : @echo "-> load firmware to controller" $(PROGRAMMERBIN) $(OPENOCDPROGRAM) # Очистка проекта clean : $(RM) -f *.axf *.map *.lst $(OBJDIR)*.d *.bin $(OBJDIR)*.o $(OBJDIR)*.lst
В дальнейшем планирую избавиться от требования уникальности имён файлов, и добавить возможность переопределения флагов компиляции для каждого файла.