Introducción
Este artículo describe una prueba de Makefile que emula el sistema de compilación de U-Boot, enfocándose en la separación entre archivos objeto y código fuente. La estructura se basa en principios clave de U-Boot Maekfile, como la gestión de directorios de salida y la inclusión modular de reglas de compilación.
Estructura del Código Fuente de Prueba
El código fuente de prueba consta de cuatro directorios: tres carpetas de origen que contienen archivos .c y sus Makefiles, y un directorio raíz con archivos config.mk y rules.mk.
Detalles de los Archivos Makefile
Makefile Principal
ifneq ($(OUTPUT_DIR),)
saved_output := $(OUTPUT_DIR)
# Crear el directorio de salida si no existe
$(shell [ -d $(OUTPUT_DIR) ] || mkdir -p $(OUTPUT_DIR))
OUTPUT_DIR := $(shell cd $(OUTPUT_DIR) && /bin/pwd)
$(if $(OUTPUT_DIR),,$(error El directorio de salida "$(saved_output)" no existe))
endif
OBJ_ROOT := $(if $(OUTPUT_DIR),$(OUTPUT_DIR),$(CURDIR))
SRC_ROOT := $(CURDIR)
TOP_DIR := $(SRC_ROOT)
LN_DIR := $(OBJ_ROOT)
export SRC_ROOT OBJ_ROOT TOP_DIR
ifneq ($(OBJ_ROOT),$(SRC_ROOT))
REMOTE_BUILD := 1
export REMOTE_BUILD # Variable usada en config.mk
endif
include $(TOP_DIR)/config.mk # Incluye definiciones de compilador y reglas
CROSS_COMPILE =
export CROSS_COMPILE
OBJS = add/add.o sub/sub.o test/test.o # Objetivos a generar
OBJS := $(addprefix $(obj),$(OBJS)) # Rutas completas de objetos
.PHONY : $(OBJS) # Forzar reconstrucción al modificar fuentes
ALL = $(obj)programa
all: $(ALL)
$(obj)programa: $(OBJS)
$(CC) $^ -o $@
$(OBJS):
make -C $(dir $(subst $(obj),,$@)) # Ejecuta Makefiles en subdirectorios
SUBDIRS = add/ sub/ test/
.PHONY: clean distclean
clean:
for dir in $(SUBDIRS); do make -C $$dir clean; done
rm -f $(ALL)
distclean:
for dir in $(SUBDIRS); do make -C $$dir distclean; done
rm -f $(ALL)
Archivo config.mk
ifneq ($(OBJ_ROOT),$(SRC_ROOT)) # Verifica si la separación de directorios está activa
ifeq ($(CURDIR),$(SRC_ROOT)) # Caso: directorios separados, en raíz de fuentes
dir :=
else
dir := $(subst $(SRC_ROOT)/,,$(CURDIR))
endif
obj := $(if $(dir),$(OBJ_ROOT)/$(dir)/,$(OBJ_ROOT)/) # Ruta completa para objetos
src := $(if $(dir),$(SRC_ROOT)/$(dir)/,$(SRC_ROOT)/) # Ruta actual de fuentes
$(shell mkdir -p $(obj)) # Crear directorio de objetos si no existe
else # Caso: directorios de objetos y fuentes iguales
obj :=
src :=
endif
# Definición de herramientas de compilación
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
#########################################################################
ifndef REMOTE_BUILD
%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
else
$(obj)%.s: %.S
$(CPP) $(AFLAGS) -o $@ $<
$(obj)%.o: %.S
$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
endif
#########################################################################
Archivo rules.mk
#########################################################################
$(obj).depend: $(src)Makefile $(TOP_DIR)/config.mk $(SRCS) # SRCS definido en Makefiles de subdirectorios
@rm -f $@
@for f in $(SRCS); do \\
g=`basename $$f | sed -e 's/\\(.*\\)\\.\\w/\\1.o/'`; \\
$(CC) -M $(HOST\_CFLAGS) $(CPPFLAGS) -MQ $(obj)$$g $$f >> $@ ; \\
done
#########################################################################
Makefile de Subdirectorio
include $(TOP_DIR)/config.mk # Incluye configuración de compilación
COBJS := add.o # Objetivos de archivos .c
SOBJS := # Objetivos de archivos .S
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) # Fuentes para compilación
OBJS := $(addprefix $(obj),$(COBJS)) # Rutas completas de objetos
SOBJS := $(addprefix $(obj),$(SOBJS))
all: $(obj).depend $(OBJS) # Generar dependencias antes de compilar
clean:
rm -f $(SOBJS) $(OBJS)
distclean: clean
rm -f $(LIB) $(obj).depend
#########################################################################
# Incluye reglas para dependencias
include $(SRC_ROOT)/rules.mk
sinclude $(obj).depend # Incluye archivo de dependencias generado
#########################################################################
Métodos de Compilación
Para compilar con objetos en el mismo directorio que las fuentes, ejecutar en el directorio raíz: make.
Para compilar con objetos en un directorio separado, se puede usar un variable de entorno: export OUTPUT_DIR=/tmp/salida y luego make, o directamente make OUTPUT_DIR=/tmp/salida.