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 and grep 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