Hace unos meses, se me ocurrió el siguiente genérico Makefile
para tareas escolares:
# ------------------------------------------------
# Generic Makefile
#
# Author: [email protected]
# Date : 2010-11-05
#
# Changelog :
# 0.01 - first version
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc -std=c99 -c
# compiling flags here
CFLAGS = -Wall -I.
LINKER = gcc -o
# linking flags here
LFLAGS = -Wall
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:.c=*.o)
rm = rm -f
$(TARGET): obj
@$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
@echo "Linking complete!"
obj: $(SOURCES) $(INCLUDES)
@$(CC) $(CFLAGS) $(SOURCES)
@echo "Compilation complete!"
clean:
@$(rm) $(TARGET) $(OBJECTS)
@echo "Cleanup complete!"
Básicamente, esto se compilará todas .c
y .h
archivo para generar .o
los archivos y el ejecutable projectname
en la misma carpeta.
Ahora, me gustaría impulsar esto un poco. ¿Cómo puedo escribir un Makefile para compilar un proyecto C con la siguiente estructura de directorios?
./
./Makefile
./src/*.c;*.h
./obj/*.o
./bin/<executable>
En otras palabras, me gustaría tener un Makefile que las fuentes compila C desde ./src/
dentro ./obj/
y luego enlace todo para crear el ejecutable en ./bin/
.
He intentado leer diferentes Makefiles, pero simplemente no puedo hacer que funcionen para la estructura del proyecto anterior; en cambio, el proyecto no se compila con todo tipo de errores. Claro, podría usar IDE completo (Monodevelop, Anjuta, etc.), pero honestamente prefiero quedarme con gEdit y el viejo terminal.
¿Hay algún gurú que pueda darme una solución funcional o información clara sobre cómo se puede hacer esto? ¡Gracias!
** ACTUALIZAR (v4) **
La solución definitiva :
# ------------------------------------------------
# Generic Makefile
#
# Author: [email protected]
# Date : 2011-08-10
#
# Changelog :
# 2010-11-05 - first version
# 2011-08-10 - added structure : sources, objects, binaries
# thanks to http://stackoverflow.com/users/128940/beta
# 2017-04-24 - changed order of linker params
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc
# compiling flags here
CFLAGS = -std=c99 -Wall -I.
LINKER = gcc
# linking flags here
LFLAGS = -Wall -I. -lm
# change these to proper directories where each file should be
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm = rm -f
$(BINDIR)/$(TARGET): $(OBJECTS)
@$(LINKER) $(OBJECTS) $(LFLAGS) -o $@
@echo "Linking complete!"
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
@$(CC) $(CFLAGS) -c $< -o $@
@echo "Compiled "$<" successfully!"
.PHONY: clean
clean:
@$(rm) $(OBJECTS)
@echo "Cleanup complete!"
.PHONY: remove
remove: clean
@$(rm) $(BINDIR)/$(TARGET)
@echo "Executable removed!"
Makefile
. Me estoy acercando, pero tengo problemas con las variables automáticas, así que parece que de todos modosRespuestas:
Primero, su
$(OBJECTS)
regla es problemática porque:file1.o
yfile2.o
)foo.o
) no es lo que realmente producirá la regla (obj/foo.o
).Sugiero lo siguiente:
La
$(TARGET)
regla tiene el mismo problema de que el nombre de destino no describe realmente lo que crea la regla. Por esa razón, si escribemake
varias veces, Make reconstruirá el objetivo cada vez, aunque no haya ninguna razón para hacerlo. Un pequeño cambio corrige que:Una vez que todo esté en orden, puede considerar un manejo de dependencias más sofisticado; si modifica uno de los archivos de encabezado, este archivo MAKE no sabrá qué objetos / ejecutables deben reconstruirse. Pero eso puede esperar otro día.
EDITAR:
Lo siento, omití parte de la
$(OBJECTS)
regla anterior; Lo he corregido. (Me gustaría poder usar "strike" dentro de una muestra de código).fuente
obj/file1.o: In function 'main': \n main.c:(.text+0x0): multiple definition of 'main' \n obj/main.o:main.c:(.text+0x0): first defined here
main
funciones? ¿Quizás uno dentrofile1.c
y otro dentromain.c
? Si es así, no podrá vincular estos objetos; solo puede haber unomain
en un ejecutable.file1.c
pero da el mismo mensaje a todos los archivos del proyecto. Ymain.c
es el único con una función principal ... emain.c
importafile1.h
yfile2.h
(no hay relación entrefile1.c
yfile2.c
), pero dudo que el problema venga de ahí.$(OBJECTS)
regla; Lo he editado. Con la línea incorrecta recibí un error, pero no el que obtuviste ...Puede agregar el
-I
indicador a los indicadores del compilador (CFLAGS) para indicar dónde debe buscar el compilador los archivos fuente, y el indicador -o para indicar dónde debe dejarse el binario:Para colocar los archivos de objeto en el
obj
directorio, use la-o
opción al compilar. Además, observe las variables automáticas$@
y .$<
Por ejemplo, considere este sencillo Makefile
Actualizar>
Al mirar su archivo MAKE, me doy cuenta de que está usando la
-o
bandera. Bueno. Continúe usándolo, pero agregue una variable de directorio de destino para indicar dónde se debe escribir el archivo de salida.fuente
-l ...
alCFLAGS
y ... ya existe el-o
argumento para el vinculador (LINKER
)make
, desde donde se encuentra el MakefileHe dejado de escribir archivos MAKE en estos días, si su intención es aprender, adelante, de lo contrario, tiene un buen generador de archivos MAKE que viene con eclipse CDT. Si desea algún soporte de mantenimiento / múltiples proyectos en su árbol de compilación, eche un vistazo a lo siguiente:
https://github.com/dmoulding/boilermake ¡Encontré esto bastante bueno ...!
fuente