gcc – How to compile the project once and link it when compiling 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 are dependent 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 having 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 that I must use the gcc -c flag, but when introducing several files with this flag, it does not 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 in its respective directory /bin/core so that it can be used later to compile any other project?

For example:

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

And it links 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 restructure 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 the Makefile configures it 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. Remaining 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 doing make , the build recipe is executed, which has dependencies as a prerequisite and checkbin , in dependencies , is in charge of calling make -C ../core , where -C specifies that the Makefile is in the directory a its right, with this the project dependencies are compiled, that is, core .

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

Scroll to Top