It is really useful to understand how the compiler works and I don’t mean you have to dig in until it's darkest secrets guts, but at least is good to know how to run it from the command line with some of the most useful options. For instance, did you know we can call the entire build process one step at a time? or the many options to compile, disassemble, or link.
Prior to anything you will need to read and install the openocd and the compiler from this post. I'm going to use the stm32g0b1 microcontroller but any other ARM based can also work
Just a brief clarification your compiler indeed is a series of programs installed on your computer that we can use for several things as you will see on the many posts from this blog. Ok, type the following in order to discover where on your computer it is installed
$ whereis arm-none-eabi-gcc
arm-none-eabi-gcc: /usr/bin/arm-none-eabi-gcc /usr/share/man/man1/arm-none-eabi-gcc.1.gz
Then display the content of /usr/bin
directory ( the grep command is to filter only what we want ). You will see a bunch of programs prefixed with arm-none-eabi, amount them to the actual compiler ( gcc ), the linker ( ld ) and the pre-processor ( cpp ). Since these binaries are located in a system directory we can run any of them from anywhere in our system.
$ls -l /usr/bin | grep arm-none-eabi
-rwxr-xr-x 1 root root 783232 May 24 15:21 arm-none-eabi-addr2line
-rwxr-xr-x 2 root root 725664 May 24 15:21 arm-none-eabi-ar
-rwxr-xr-x 2 root root 1893848 May 24 15:21 arm-none-eabi-as
-rwxr-xr-x 2 root root 1521328 May 6 17:11 arm-none-eabi-c++
-rwxr-xr-x 1 root root 112568 May 24 15:21 arm-none-eabi-c++filt
-rwxr-xr-x 1 root root 1521328 May 6 17:11 arm-none-eabi-cpp
-rwxr-xr-x 1 root root 964856 May 24 15:21 arm-none-eabi-dwp
-rwxr-xr-x 1 root root 35192 May 24 15:21 arm-none-eabi-elfedit
-rwxr-xr-x 2 root root 1521328 May 6 17:11 arm-none-eabi-g++
-rwxr-xr-x 2 root root 1517232 May 6 17:11 arm-none-eabi-gcc
...
For Windows user you can look for those program using the file explorer, or switch to linux, of course.whereis
andgrep
does not come with git bash
And now an example. Write the following code ( we are not interested in running or flashing the program, we just want to illustrate how to run our build tool-chain ) and saved it with the name hola.c
int main( void )
{
return 0;
}
let’s test it with our regular GCC compiler
$ gcc hola.c -o hola
No error message, no nothing will appear on screen and that means our program was compiled without any errors, now let's try to do the same thing, but using our ARM version compiler
NOTE: GCC and arm-none-eabi-gcc are the same with only one not so small difference, while GCC build programs to run in our PC arm-none-eabi-gcc builds program to be flashed into our microcontroller and more specific ARM microcontrollers. But both share the same flags and options (well at least most of them) and both runs pretty similar
$ arm-none-eabi-gcc hola.c -o hola.elf
/usr/lib/gcc/arm-none-eabi/12.1.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.1.0/../../../../arm-none-eabi/lib/libc.a(lib_a-exit.o): in function `exit':
/build/arm-none-eabi-newlib/src/build-newlib/arm-none-eabi/newlib/libc/stdlib/../../../../../newlib-4.2.0.20211231/newlib/libc/stdlib/exit.c:64: undefined reference to `_exit'
collect2: error: ld returned 1 exit status
Oh my .. The compiler, or more exactly the linker is complaining about a symbol named _exit, which by the way it is required by the standard library, and since our program is pretty simple and we don’t need the std library at all, we are going to compile ( link ) again without the standard library
$ arm-none-eabi-gcc hola.c -o hola.elf -nostdlib
/usr/lib/gcc/arm-none-eabi/12.1.0/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000
Do not pay attention to the warning message, the hola.elf file is there, but OK let's remove the warning just by adding the option -e main
The linker is complaining again about another symbol, but we specify there is another symbol it can use as an entry point for our program
$ arm-none-eabi-gcc hola.c -o hola.elf -nostdlib -e main
$ ls
hola.c hola.elf
Piece of cake!, most of the time or 99.99% of the programs we build for microcontrollers needs to split the build process at a least two steps, the compilation, and the linking and that is because.. well I will explain later, for the moment this is how we usually build our microcontroller programs
$ arm-none-eabi-gcc -c hola.c -o hola.o
$ arm-none-eabi-gcc hola.o -o hola.elf -nostdlib -e main
$ ls
hola.c hola.o hola.elf
Notice that when we compile this time we add the flag -c and indicate we need an intermediate file hola.o this is an object code file and basically contains our C instructions compiled for our machine to later be linked and generate our hola.elf which is the file we need to flash and debug.
There is another thing pending, our compiler has the ability to generate object code for several ARM processors and it is necessary to specify which one we are going to use, in my case, and since I’m using the stm32g0b1 microcontroller I need to choose the Cortex-M0plus option.
$ arm-none-eabi-gcc -c hola.c -o hola.o -mcpu=cortex-m0plus
$ arm-none-eabi-gcc hola.o -o hola.elf -nostdlib -e main -mcpu=cortex-m0plus
$ ls
hola.c hola.o hola.elf