Propuesta de update del Makefile
(Tareas en general)
#41
-
Sip, yo de nuevo con un tema parecido al del CMake... Para las otras tareas (esta era la categoría que más se acercaba) Como no estaba permitido el uso de mi ¿Cuál es el resumen de cambios implementados de mi propuesta?
No lo he probado en casos borde, pero en teoría funcionaría en todas las situaciones (siempre y cuando el En mi caso las variables son las que aparecen, pero en el caso de la mayoría, serían a lo mucho En caso de no poder Uds. aprobar o sugerir directamente el cambio, ¿con quién debería hablar para proponer la idea? Espero lean y tomen en consideración esta idea para futuras correcciones. Eso sí, no he probado todos los casos borde de las futuras tareas porque no tengo (todas) las (posibles) soluciones de dichas tareas (dah). Ejemplo optimizado: Ejemplo debug: ###############################################################################
# Makefile Múltiple Recursivo Multiplataforma #
# #
# Versión original por Vicente Errázuriz #
# Para el curso de Estructuras de Datos y Algoritmos, 2017 - 1, PUC #
# Makefile diseñada para el trabajo de varios programas con código común #
# #
# OJO: Modificada por Benja Vicente (2023 - 2), para: #
# - permitir bien SRC y BIN #
# #
# OJO 2: Modificado por Luis González (ljgonzalez1) (2025 - 1), para: #
# - Implementar búsqueda recursiva de archivos #
# - Asegurar compatibilidad con Windows, Linux y macOS. #
# - Agregar % de progreso #
# - Simplificar el las flags para optimizar y debuggear #
# - Agregar colores ANSI :D #
# - Agrgar regla de 'recreate' #
# #
###############################################################################
###############################################################################
# GUÍA DE USO #
###############################################################################
# #
# VARIABLES CONFIGURABLES: #
# PROGRAMS, COMMON, SRC, BIN, OBJ, OPT, LIB, etc. #
# #
# COMANDOS DISPONIBLES: #
# make, make clean, make recreate, make recreate binX, make binX... #
# #
###############################################################################
###############################################################################
# Variables Base #
###############################################################################
# Descomentar una:
# OPTIMIZED_MODE = true # No mostrará warnings y optimizará al máximo
OPTIMIZED_MODE = false # Mostrará warnings y no optimizará. Sirve para debug
# Directorios que serán compilados a un programa (busca de forma recursiva en la carpeta)
PROGRAMS = \
rollercoaster
# Directorios con elementos de uso común (busca de forma recursiva en la carpetas incluidas)
COMMON = \
include \
common \
lib
# La carpeta donde va todo el código
SRC = src
# La carpeta donde quedan los ejecutables
BIN = ./
# El compilador a usar: Gnu C Compiler, Standard 2011 con extensiones GNU
CC = gcc -std=gnu11
# La carpeta donde van los .o
OBJ = obj
###############################################################################
# LIBRERÍAS #
###############################################################################
# Lista de librerías a incluir (descomenta las que necesites)
LIB = \
-lm
# -lpng \
# -lpthread \
# -ljpg
###############################################################################
# CONFIGURACIÓN INTERNA (No modificar si no sabes lo que haces) #
###############################################################################
# Eliminar archivos en caso de error de compilación
.DELETE_ON_ERROR:
# Hacer que Make aborte en el primer error (-e) y ejecute en modo comando (-c)
.SHELLFLAGS := -ec
# ANSI/VT100 Códigos de Escapes
# Definir colores amarillos solo en sistemas que soporten ANSI (Unix-like)
ifeq ($(OS),Windows_NT)
YELLOW :=
YELLOW_BOLD :=
BOLD :=
NOBOLD :=
CYAN :=
GREEN :=
RESET :=
GREEN_BOLD :=
else
YELLOW := \033[33m
YELLOW_BOLD := \033[1;33m
BOLD := \033[1m
NOBOLD := \033[22m
CYAN := \033[36m
GREEN := \033[32m
RESET := \033[0m
GREEN_BOLD := \033[1;32m
endif
###############################################################################
# OPTIMIZACIÓN POR COMPILADOR, según el flag OPTIMIZED_MODE #
###############################################################################
ifeq ($(strip $(OPTIMIZED_MODE)),true)
# Modo Optimizado
OPT = -O3 -s
# Si estamos en modo optimizado, se suprimen los mensajes de entrada/salida de
# directorios en las llamadas recursivas a make.
MAKEFLAGS += --no-print-directory
else
# Modo Debug (con warnings, etc.)
OPT = -g3 -Wall -Wunused -Wextra -Wconversion -Wshadow -Wformat
endif
###############################################################################
# Detección del Sistema Operativo #
###############################################################################
DETECTED_OS := Unknown
ifeq ($(OS),Windows_NT)
DETECTED_OS := Windows
else
UNAME_OUTPUT := $(shell uname -s 2>/dev/null)
ifneq ($(UNAME_OUTPUT),)
ifeq ($(UNAME_OUTPUT),Linux)
DETECTED_OS := Linux
else ifeq ($(UNAME_OUTPUT),Darwin)
DETECTED_OS := macOS
else ifneq ($(findstring MINGW,$(UNAME_OUTPUT)),)
DETECTED_OS := Windows
else ifneq ($(findstring CYGWIN,$(UNAME_OUTPUT)),)
DETECTED_OS := Windows
else ifneq ($(findstring MSYS,$(UNAME_OUTPUT)),)
DETECTED_OS := Windows
else
DETECTED_OS := Unix-like
endif
endif
endif
ifeq ($(DETECTED_OS),Unknown)
ifneq ($(findstring /,$(shell pwd 2>/dev/null)),)
DETECTED_OS := Unix-like
else
DETECTED_OS := Windows
endif
endif
###############################################################################
# Comandos según el sistema detectado
###############################################################################
ifeq ($(DETECTED_OS),Windows)
RM_CMD := del /Q
RMDIR_CMD := rmdir /S /Q
MKDIR_CMD := mkdir
fixpath = $(subst /,\,$1)
else
RM_CMD := rm -f
RMDIR_CMD := rm -rf
MKDIR_CMD := mkdir -p
fixpath = $1
endif
###############################################################################
# Definición de NULL_DEVICE para redirección de errores en Windows y Unix-like
###############################################################################
ifeq ($(DETECTED_OS),Windows)
NULL_DEVICE := NUL
else
NULL_DEVICE := /dev/null
endif
###############################################################################
# Funciones de Recursividad #
###############################################################################
rwildcard = $(foreach d,$(wildcard $1*), \
$(call rwildcard,$d/,$2) \
$(filter $(subst *,%,$(2)),$(d)) \
)
# Equivalente a la búsqueda, pero sin 'find'
find_files = $(if $(wildcard $(SRC)/$(1)), \
$(call rwildcard,$(SRC)/$(1)/,$(2)), \
$(error El directorio $(SRC)/$(1) no existe pero está \
en PROGRAMS o COMMON) )
###############################################################################
# Definición Recursiva de Archivos #
###############################################################################
COMMON_SRC := $(if $(strip $(COMMON)), \
$(foreach d,$(COMMON),$(call find_files,$(d),*.c)),)
$(foreach prog,$(PROGRAMS), \
$(eval $(prog)_SRC := $(call find_files,$(prog),*.c) $(COMMON_SRC)) \
$(eval $(prog)_OBJS := $(patsubst $(SRC)/%.c,$(OBJ)/%.o,$($(prog)_SRC))) )
BIN_PROGRAMS := $(addprefix $(BIN)/,$(PROGRAMS))
ALL_OBJFILES := $(foreach prog,$(PROGRAMS),$($(prog)_OBJS))
TOTAL_OBJS := $(words $(ALL_OBJFILES))
ifeq ($(TOTAL_OBJS),0)
TOTAL_OBJS := 1
endif
HDRFILES := $(call rwildcard,$(SRC)/,*.h)
OBJDIR := $(sort $(dir $(ALL_OBJFILES)))
###############################################################################
# PARÁMETROS ADICIONALES #
###############################################################################
CFLAGS = $(OPT)
###############################################################################
# Evitamos que se borren los .o después de linkear #
###############################################################################
.SECONDARY: $(ALL_OBJFILES)
###############################################################################
# REGLAS #
###############################################################################
.PHONY: all clean recreate reset_counter maincomp cleanup
all:
@echo "$(YELLOW_BOLD)Compilation details: $(YELLOW)CC=$(CC) will be used with CFLAGS=$(OPT)$(RESET)"
@echo "$(YELLOW_BOLD)Detected OS: $(YELLOW)$(DETECTED_OS)$(RESET)"
@echo ""
@$(MAKE) reset_counter
@-$(MAKE) maincomp
@-$(MAKE) cleanup
@echo "done compiling"
cleanup:
@$(RM_CMD) .compile_count 2>$(NULL_DEVICE) || true
maincomp: $(OBJDIR) $(BIN) $(BIN_PROGRAMS)
@true # solo agrupar dependencias
recreate:
@echo "==> Recreating all. Cleaning first..."
@$(MAKE) clean
@echo "==> Compiling from scratch..."
@$(MAKE) all
###############################################################################
# Limpieza detallada #
###############################################################################
clean:
@echo "$(BOLD)$(GREEN)Cleaning...$(RESET)"
@echo "$(BOLD)$(CYAN)Entering folder: $(CURDIR) ...$(RESET)"
ifeq ($(DETECTED_OS),Windows)
@echo "Deleting folder $(call fixpath,$(OBJ))..."
@if exist $(call fixpath,$(OBJ)) $(RMDIR_CMD) $(call fixpath,$(OBJ))
@echo "Deleting binaries $(subst /,\,$(BIN_PROGRAMS))..."
@for %%f in ($(subst /,\,$(BIN_PROGRAMS))) do if exist %%f $(RM_CMD) %%f
@if exist .compile_count $(RM_CMD) .compile_count
else
@echo "Deleting folder $(OBJ)..."
@$(RMDIR_CMD) $(OBJ) 2>$(NULL_DEVICE) || true
@echo "Deleting binaries $(BIN_PROGRAMS)..."
@$(RM_CMD) $(BIN_PROGRAMS) 2>$(NULL_DEVICE) || true
@echo "Deleting file .compile_count..."
@$(RM_CMD) .compile_count 2>$(NULL_DEVICE) || true
endif
@echo "$(BOLD)$(CYAN)Leaving folder: $(CURDIR) ...$(RESET)"
@echo "$(BOLD)$(GREEN)Done cleaning$(RESET)"
reset_counter:
@$(RM_CMD) .compile_count 2>$(NULL_DEVICE) || true
###############################################################################
# Crear directorios #
###############################################################################
$(OBJDIR):
@$(if $(filter true,$(OPTIMIZED_MODE)),,echo "$(BOLD)$(CYAN)Creating objects folder: $(NOBOLD)$(CYAN)$@$(RESET)")
@$(MKDIR_CMD) $@
$(BIN):
@$(if $(filter true,$(OPTIMIZED_MODE)),,echo "$(BOLD)$(CYAN)Creating bin folder: $(NOBOLD)$(CYAN)$@$(RESET)")
@$(MKDIR_CMD) $@
###############################################################################
# Regla mágica para manejar dependencias #
###############################################################################
.SECONDEXPANSION:
LOCAL_DEPS = $(filter $(patsubst $(OBJ)/%, $(SRC)/%, $(dir $(1)))%, $(HDRFILES))
###############################################################################
# Regla de compilación con porcentaje de avance #
###############################################################################
.SECONDEXPANSION:
LOCAL_DEPS = $(filter $(patsubst $(OBJ)/%, $(SRC)/%, $(dir $(1)))%, $(HDRFILES))
$(OBJ)/%.o: $(SRC)/%.c $$(call LOCAL_DEps,$$@) $(HDRFILES) Makefile
@$(if $(filter true,$(OPTIMIZED_MODE)),,echo "$(GREEN)Compiling $(notdir $<)...$(RESET)")
@$(if $(filter true,$(OPTIMIZED_MODE)),,echo "$(CC) $(CFLAGS) $< -c -o $@ $(LIB)")
@$(MKDIR_CMD) $(dir $@)
@$(CC) $(CFLAGS) $< -c -o $@ $(LIB)
@ CURRENT=$$(cat .compile_count 2>$(NULL_DEVICE) || echo 0); \
CURRENT=$$((CURRENT+1)); \
echo $$CURRENT > .compile_count; \
PCT=$$((100*CURRENT/$(TOTAL_OBJS))); \
echo "$(GREEN_BOLD)[ $$PCT% ] compiled '$(notdir $<)'$(RESET)"
###############################################################################
# Linkeo final #
###############################################################################
$(BIN)/%: $$($$*_OBJS)
@echo "$(GREEN)Linking $(notdir $@)...$(RESET)"
@$(if $(filter true,$(OPTIMIZED_MODE)),,echo "$(CC) $(CFLAGS) $^ -o $@ $(LIB)")
@$(CC) $(CFLAGS) $^ -o $@ $(LIB)
@echo "$(GREEN_BOLD) compiled '$(notdir $@)'$(RESET)"
###############################################################################
# Cualquier duda no temas en preguntar! #
###############################################################################
# Disclaimer: #
# Deberías modificar solamente el nivel de Optimización (OPTIMIZED_MODE) y #
# las carpetas de archivos a compilar (PROGRAMS y COMMON). Modificar la #
# Makefile si no sabes lo que está pasando o cómo la usamos los ayudantes #
# puede resultar en un perjuicio en la evaluación de tu código. #
###############################################################################
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Hola! Cualquier cambio que hagas en el makefile queda bajo tu propia responsabilidad, en caso de haber problemas al compilar tu tarea en los computadores de los ayudantes no se aceptará recorrección. El archivo entregado esta hecho especialmente para el curso y no se espera que trabajen sobre él. |
Beta Was this translation helpful? Give feedback.
-
Ok. Creo que no me entendieron del todo. Para esta entrega, pretendo utilizar el Ahora bien... El curso ha cambiado el La pregunta: Aclaro que esto no sólo sería de interés personal, sino que una propuesta para beneficiar a todos los alumnos, ya sea este semestre u otro más adelante. Sé que algunas de mis modificaciones pueden considerarse innecesarias, pero ¿qué funcionalidades me gustaría que realmente se integraran al
Nuevamnete, lo estético es un extra. Entrega una mejor presentación y separa los outputs nada más y no es necesario. Y sin uso de CMake, como ya fue discutido antes. Como ejemplo, las variables del PROGRAMS=rollercoaster
COMMON= \
common/data_structures/lists/circular_doubly_linked_list \
common/utils \
common/utils/escape_sequences \
include \
lib/debug_print_lib/src/debug_print \
rollercoaster/roller_coaster \
rollercoaster/car \
rollercoaster/person \
rollercoaster/park
#OPT=-g # Guardar toda la información para poder debugear. No optimiza
OPT=-O3 # Optimiza al máximo, descarta toda la información de debug. A esto: OPTIMIZED_MODE = true # true / false
PROGRAMS = \
rollercoaster
COMMON = \
include \
common \
lib Y agregar una nueva carpeta no significaría siempre agregar una nueva línea en el Esto se notaría aún más cuando se quiera compilar más de un binario con archivos comunes. |
Beta Was this translation helpful? Give feedback.
Hola! Cualquier cambio que hagas en el makefile queda bajo tu propia responsabilidad, en caso de haber problemas al compilar tu tarea en los computadores de los ayudantes no se aceptará recorrección. El archivo entregado esta hecho especialmente para el curso y no se espera que trabajen sobre él.