gcc – How to build the project once and link it when building other projects?

Question:

I have the following problem, assuming my project structure is as follows ( / is the root).

/bin                   # Directorio vacío, es la salida del makefile.
/include/*.h           # assembler.h core.h utils.h, Todos los headers estan aquí.
/src/assembler/*.c     # assembler.c tokenizer.c y otras herramientas del ensamblador.
/src/core/*.c          # utils.c core.c y todos los ficheros del núcleo compartido.
/src/machine/*.c       # bla.c foo.c .... Todos los ficheros de la máquina virtual.

All projects under /src have a dependency on the core project, but have access to the headers of the /include directory.

Using GNU make I need to be able to compile only one of the projects I am working on, without the need to alter other projects, so far I have used the following Makefile :

# #$@% Makefile
CC=gcc
FLAGS=-Wall -Wextra -Wpedantic -Werror -std=c11 -O3
INCLUDES=-Iinclude

checkbin:
    # Ensure bin is there.
    @if [ ! -e "bin" ]; then mkdir "bin"; fi

assembler: checkbin # First check for binaries folder.
    $(CC) -o bin/assembler $(INCLUDES) $(FLAGS) src/core/*.c src/assembler/*.c

vm: checkbin
    $(CC) -o bin/vm $(INCLUDES) $(FLAGS) src/core/*.c src/machine/*.c

clean:
    @if [ -e "bin" ]; then \
        rm -rf "bin"; \
    fi

default: assembler # set assembler to default...

The Makefile does the job, but it does a lot of work; it is recompiling the core every time i go to compile some other project like machine or assembler .

To compile them separately I know I have to use gcc 's -c flag, but inputting multiple files with this flag doesn't allow me to use the -o flag to specify the output, for example:

$(CC) -c $(FLAGS) $(INCLUDES) /src/core/*.c 
# Si intento poner -o "bin/core" en este caso, me arroja error

How can I move the compiled files of the dependency project, in this case core , into their respective /bin/core directory so that it can be used later to compile any other project?

For example:

/bin/core/utils.o
/bin/core/core.o

And binds to the following statement:

# Asumiendo los valores puestos arriba:
assembler: checkbin
    @if [ ! -e "bin/assembler" ]; then mkdir "bin/assembler"; fi
    # ... <- instrucción que pondrá los .o en el directorio /bin/assembler/*.o
    $(CC) -o /bin/assembler/assembler /bin/core/*.o /bin/assembler/*.o
    # Sólo necesitamos enlazar los archivos objeto.

Answer:

The basic solution was as Trauma described in his comment, for this I had to re-structure the project in such a way that it would be as follows:

/components/*.h      # Todos los archivos cabecera
/core/bin            # Carpeta que contendra los archivos objeto.
/core/*.c            # Archivos de codigo del core
/core/Makefile       # Makefile del proyecto Core
/hasm/bin        
/hasm/*.c            # Codigo del proyecto assembler
/hasm/Makefile
/machine/bin     
/machine/*.c         # Codigo del proyecto machine
/machine/Makefile

And configure the Makefile in each project that needs core so that it will verify if it is compiled and thus copy its object files, otherwise, it compiles the project. Staying as follows:

# hasm makefile.
CC=gcc
FLAGS=-Wall -Wextra -Wpedantic -Werror -O3 -std=c11 -c
INCLUDES=-I../components
OUTPUT=hasm # Cambia con el nombre del proyecto.

default: build

# Crea un objetivo condicionalmente, si existen los binarios del proyecto Core.
ifeq ("$(wildcard $(ls ../core/bin/*.o 2> /dev/null))","") # Verifica si hay archivos en /core/bin
dependencies:
    @make -C ../core;
else
dependencies:
    @echo "Core good.";
endif

# Mira a ver si existe el foder bin en el directorio actual.
checkbin:
    @if [ ! -e "bin" ]; then mkdir "bin"; echo "Created!"; else echo "Exists!"; fi

# Construye el proyecto.
build: dependencies checkbin 
    @echo "Building project..."
    $(CC) $(FLAGS) $(INCLUDES) src/*.c  # Compila con el flag -c los archivos del proyecto.
    @mv *.o bin/                        # Mueve todos los archivos objeto al folder bin.
    @cp ../core/bin/*.o bin/;           # Copia los archivos de "../core/bin/" a "./bin/"
    $(CC) -o bin/$(OUTPUT) bin/*.o      # Enlaza con gcc.

# Elimina el folder bin y algun .o que quede en el directorio actual.
clean:
    @if [ -e "bin" ]; then rm -rf "bin"; fi
    @if [ -f *.o ]; then rm -f *.o; fi

When making make , the build recipe is executed, which has dependencies as a prerequisite and checkbin , in dependencies , takes care of calling make -C ../core , where -C specifies that the Makefile is located in the directory to your right, this compiles the dependencies of the project, i.e. core .

After that, proceed to copy the object files inside the /core/bin/ folder to the folder of the project you are working on and link them without problem.

Scroll to Top