A real world project is made of several files that needs to be first compiled and then linked, here is the most easy example to compile, just two files with no headers, again it does nothing useful but it works to illustrate what we want

sum.c

int suma( int var )
{
    return var + 20;
}

main.c

int suma( int var );

int main( void )
{
    int x;
    x = suma( 30 );
    return 0;
}

To build this program we must compile both files first, one by one and then link them together

$ arm-none-eabi-gcc -c sum.c -o sum.o -mcpu=cortex-m0plus
$ arm-none-eabi-gcc -c main.c -o main.o -mcpu=cortex-m0plus
$ arm-none-eabi-gcc main.o sum.o -o main.elf -nostdlib -e main -mcpu=cortex-m0plus
$ ls
sum.c sum.o main.c main.o main.elf

That was easy, now something more complicated, let’s say we decided to put some order in our project directory and we creates a sub directory to move the sum.c file, but not only that, we also decided to create a header file sum.h with the function prototype and included in our main.c, now the entire program looks like this

sum.c

#include "sum.h"

int suma( int var )
{
    return var + NUM;
}

sum.h

#ifndef __SUM_H
#define __SUM_H

#define NUM     30;

int suma( int var );

#endif

main.c

#include "sum.h"

int main( void )
{
    int x;
    x = suma( 30 );
    return 0;
}

Our project directory with the sub folder looks like this:

$ tree
.
├── main.c
├── driver
    ├── sum.c
    └── sum.h

To compile this program with a sub-directory it is necessary to specify the files that are in the directory driver, both, the source ( .c ) and the header ( .h ) files. The source file only needs to be specified within its directory while the header must be “included“ with the flag -I, and it is only necessary the name of the directory where is located.

$ arm-none-eabi-gcc -c driver/sum.c -o sum.o -mcpu=cortex-m0plus -I driver
$ arm-none-eabi-gcc -c main.c -o main.o -mcpu=cortex-m0plus -I driver
$ arm-none-eabi-gcc main.o sum.o -o main.elf -nostdlib -e main -mcpu=cortex-m0plus

Directory structure up to now, after build

$ tree
.
├── driver
│   ├── sum.c
│   └── sum.h
├── main
├── main.c
├── main.elf
├── main.o
├── sum.o
NOTE: if more than one sub directory is been use it is necessary to keep using the flag -I for each directory:
$ arm-none-eabi-gcc -c driver/sum.c -o sum.o -mcpu=cortex-m0plus -I directory1 -I directory2

Good!, but there is one more thing we can do in order to clean up even more our project, we can create a directory where all the generated files ( .o and elf ) will be placed, we name this directory Build

$ mkdir Build
$ arm-none-eabi-gcc -c driver/sum.c -o Build/sum.o -mcpu=cortex-m0plus -I driver
$ arm-none-eabi-gcc -c main.c -o Build/main.o -mcpu=cortex-m0plus -I driver
$ arm-none-eabi-gcc Build/main.o Build/sum.o -o Build/main.elf -nostdlib -e main -mcpu=cortex-m0plus

Directory structure up to now, after build

$ tree
.
├── Build
│   ├── main.elf
│   ├── main.o
│   └── sum.o
├── driver
│   ├── sum.c
│   └── sum.h
├── main.c

Wow now the amount of things we need to type is too damn high!, but no worries, we can solve this "dilema" with something called makefiles. More on the next post