I want to develop for AArch32 bare-metal target (arm-none-eabi).
By default each release installs to its own directory instead of upgrading the previous one. This way several releases can coexist and you can select which one you use for a specific project. One downside to this is that the directory and filename convention is heavy. For practical use, you need to configure an IDE or encapsulate those paths and names in Makefile variables.
### Build environment selection GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" BINPFX = $(GCCDIR)/bin/arm-none-eabi- CC = $(BINPFX)gcc ### Build rules .PHONY: version version: $(CC) --version
$ make "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-gcc --version arm-none-eabi-gcc.exe (Arm GNU Toolchain 13.3.Rel1 (Build arm-13.24)) 13.3.1 202 40614 Copyright (C) 2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabiBy selecting the path based on the development environment, there is no need to make changes while switching between OS. Gmake has the built-in variable MAKE_HOST that can be tested for this.
### Build environment selection ifeq (linux, $(findstring linux, $(MAKE_HOST))) GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi else GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" endif BINPFX = $(GCCDIR)/bin/arm-none-eabi- CC = $(BINPFX)gcc ### Build rules .PHONY: version version: $(CC) --versionI use the path prefix $(HOME)/Packages instead of ~/Packages when defining GCCDIR as some sub-processes called by gmake may have issues with ~ expansion (in this case ld). This way gmake will handle the expansion before calling the sub-processes.
$ touch empty.c $ make empty.o "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-gcc -c -o empty.o empty.cCompilation is succesful and empty.o file is generated.
There are sample link scripts that come with the toolchain, they are located in the subfolder share/gcc-arm-none-eabi/samples/ldscripts. For now I can use the simplest script: mem.ld.
### Build environment selection ifeq (linux, $(findstring linux, $(MAKE_HOST))) GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi else GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" endif BINPFX = $(GCCDIR)/bin/arm-none-eabi- CC = $(BINPFX)gcc LD = $(BINPFX)ld LD_SCRIPT = $(GCCDIR)/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld ### Build rules %.elf: %.o $(LD) -T$(LD_SCRIPT) -o $@ $<
$ make empty.elf "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-ld -T"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" /share/gcc-arm-none-eabi/samples/ldscripts/mem.ld -o empty.elf empty.oLink terminates successfully and creates empty.elf.
### Build environment selection ifeq (linux, $(findstring linux, $(MAKE_HOST))) GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi else GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" endif BINPFX = $(GCCDIR)/bin/arm-none-eabi- CC = $(BINPFX)gcc LD = $(BINPFX)ld OBJCOPY = $(BINPFX)objcopy LD_SCRIPT = $(GCCDIR)/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld ### Build rules %.elf: %.o $(LD) -T$(LD_SCRIPT) -o $@ $< %.bin: %.elf $(OBJCOPY) -O binary $< $@ %.hex: %.elf $(OBJCOPY) -O ihex $< $@Now, if I start in a directory that contains only this Makefile and an empty empty.c file, I can successfully build.
$ make empty.bin empty.hex "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-gcc -c -o empty.o empty.c "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-ld -T"D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" /share/gcc-arm-none-eabi/samples/ldscripts/mem.ld -o empty.elf empty.o "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-objcopy -O binary empty.elf empty .bin "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-m ingw-w64-i686-arm-none-eabi"/bin/arm-none-eabi-objcopy -O ihex empty.elf empty.h ex rm empty.o empty.elfNotice that gmake automatically removes the intermediary .o and .elf files on completion.
The generated empty.bin is empty.
### Build environment selection ifeq (linux, $(findstring linux, $(MAKE_HOST))) GCCDIR = $(HOME)/Packages/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi else GCCDIR = "D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi" endif BINPFX = @$(GCCDIR)/bin/arm-none-eabi- CC = $(BINPFX)gcc LD = $(BINPFX)ld OBJCOPY = $(BINPFX)objcopy LD_SCRIPT = $(GCCDIR)/share/gcc-arm-none-eabi/samples/ldscripts/mem.ld ### Build rules .PHONY: clean clean: @echo CLEAN @rm -f *.o *.elf *.bin *.hex %.elf: %.o @echo $@ $(LD) -T$(LD_SCRIPT) -o $@ $< %.bin: %.elf @echo $@ $(OBJCOPY) -O binary $< $@ %.hex: %.elf @echo $@ $(OBJCOPY) -O ihex $< $@
$ make clean CLEAN $ make empty.bin empty.hex empty.elf empty.bin empty.hex rm empty.o empty.elf
Next, I will select a micro-controller from the STM32 family and generate a binary file that it can execute.