Acerca de¶
Comprender el proceso de compilación y saber cómo automatizarlo es una habilidad
esencial para cualquier programador de C. Estos ejercicios te guiarán a través
de la creación de proyectos multi-archivo, el uso de gcc para compilar y
enlazar, y la escritura de Makefiles básicos para gestionar la compilación de
forma eficiente.
Para profundizar en los conceptos teóricos, podés consultar los siguientes capítulos del apunte:
Proyecto Multi-archivo Manual¶
Ejercicio 6.1 - Separar un programa ⭐⭐☆☆☆¶
Tarea: Tomá un programa simple que tengas en un solo archivo .c (por
ejemplo, una calculadora con funciones sumar y restar) y dividilo en tres
archivos:
calculadora.h: El archivo de cabecera. Debe contener solo los prototipos de las funcionessumaryrestary las guardas de inclusión.calculadora.c: La implementación. Debe incluircalculadora.hy contener el código de las funcionessumaryrestar.main.c: El programa principal. Debe incluircalculadora.hy llamar a las funciones para usarlas.
Ejercicio 6.2 - Compilación manual ⭐⭐☆☆☆¶
Tarea: Usando la terminal, compilá y enlazá los archivos del ejercicio anterior sin usar un Makefile.
Automatización con Makefile¶
Ejercicio 6.3 - Makefile básico ⭐☆☆☆☆¶
Tarea: Crear un Makefile para el proyecto del ejercicio anterior. El
Makefile debe tener los siguientes objetivos (targets):
all: El objetivo por defecto, que debe compilar y enlazar todo el programa para crear el ejecutablemi_calculadora.clean: Un objetivo “phony” que elimina todos los archivos generados por la compilación (.oy el ejecutable).
Compilación Condicional¶
Ejercicio 6.4 - Mensajes de depuración ⭐⭐☆☆☆¶
Tarea: Modificá tu proyecto para incluir mensajes de depuración que solo se impriman cuando se compile en “modo debug”.
Ejercicio 6.5 - Compilación Básica ⭐☆☆☆☆¶
Compilá un programa simple desde línea de comandos.
Orientación:
gcc -o programa programa.c
./programa-oespecifica nombre del ejecutableSin
-o, creaa.outpor defecto
Ejercicio 6.6 - Warnings Habilitados ⭐☆☆☆☆¶
Compilá con warnings completos y corregí los problemas.
Orientación:
gcc -Wall -Wextra -std=c99 -pedantic programa.c -o programa-Wall: warnings comunes-Wextra: warnings adicionales-std=c99: estándar C99-pedantic: estricto con estándar
Ejercicio 6.7 - Dos Archivos Separados ⭐⭐☆☆☆¶
Separáun programa en main.c y funciones.c.
funciones.h:
#ifndef FUNCIONES_H
#define FUNCIONES_H
int sumar(int a, int b);
#endiffunciones.c:
#include "funciones.h"
int sumar(int a, int b) {
return a + b;
}main.c:
#include <stdio.h>
#include "funciones.h"
int main() {
printf("%d\n", sumar(3, 4));
}Compilación:
gcc -c funciones.c # Genera funciones.o
gcc -c main.c # Genera main.o
gcc funciones.o main.o -o programaEjercicio 6.8 - Include Guards ⭐⭐☆☆☆¶
Explicá por qué se necesitan include guards y implementalos.
Orientación:
#ifndef MI_HEADER_H
#define MI_HEADER_H
// Contenido del header
#endif // MI_HEADER_HPreviene inclusión múltiple
Evita errores de redefinición
Ejercicio 6.9 - Makefile Básico ⭐⭐⭐☆☆¶
Creá Makefile para compilar proyecto de ejercicio 3.
Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14CC = gcc CFLAGS = -Wall -Wextra -std=c99 programa: main.o funciones.o $(CC) main.o funciones.o -o programa main.o: main.c funciones.h $(CC) $(CFLAGS) -c main.c funciones.o: funciones.c funciones.h $(CC) $(CFLAGS) -c funciones.c clean: rm -f *.o programa
Uso:
make # Compila
make clean # LimpiaEjercicio 6.10 - Biblioteca Matemática ⭐⭐⭐☆☆¶
Creá biblioteca con funciones matemáticas: factorial, potencia, fibonacci.
Estructura:
proyecto/
├── matematica.h
├── matematica.c
├── test.c
└── MakefileOrientación:
matematica.h: declaracionesmatematica.c: implementacionestest.c: programa que usa la biblioteca
Ejercicio 6.11 - Flags de Optimización ⭐⭐⭐☆☆¶
Compilá con diferentes niveles de optimización y medí diferencia.
Orientación:
gcc -O0 programa.c -o prog_O0 # Sin optimización
gcc -O1 programa.c -o prog_O1 # Básica
gcc -O2 programa.c -o prog_O2 # Recomendada
gcc -O3 programa.c -o prog_O3 # AgresivaMedí tiempo de ejecución:
time ./prog_O2-O0útil para debugging-O2balance entre velocidad y tamaño-O3máxima optimización
Ejercicio 6.12 - Compilación Condicional ⭐⭐⭐☆☆¶
Usá directivas de preprocesador para debug opcional.
Orientación:
#ifdef DEBUG
printf("Debug: valor = %d\n", valor);
#endifCompilación:
gcc -DDEBUG programa.c -o programa # Con debug
gcc programa.c -o programa # Sin debugEjercicio 6.13 - Módulo de Utilidades ⭐⭐⭐⭐☆¶
Creá módulo utils con funciones de uso general: intercambio, mínimo, máximo.
Estructura:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17// utils.h #ifndef UTILS_H #define UTILS_H void intercambiar(int *a, int *b); int minimo(int a, int b); int maximo(int a, int b); #endif // utils.c #include "utils.h" // Implementaciones... // main.c #include "utils.h" // Uso...
Ejercicio 6.14 - Makefile con Variables ⭐⭐⭐⭐☆¶
Mejorá Makefile usando variables y patrones.
Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18CC = gcc CFLAGS = -Wall -Wextra -std=c99 -O2 LDFLAGS = -lm SRCS = main.c utils.c matematica.c OBJS = $(SRCS:.c=.o) TARGET = programa $(TARGET): $(OBJS) $(CC) $(OBJS) $(LDFLAGS) -o $(TARGET) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET) .PHONY: clean
Ejercicio 6.15 - Dependencias Automáticas ⭐⭐⭐⭐☆¶
Generá dependencias automáticamente con gcc.
Orientación:
DEPS = $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@-MMD: genera archivo .d con dependencias-MP: crea targets phony para headers
Ejercicio 6.16 - Biblioteca Estática ⭐⭐⭐⭐⭐¶
Creá biblioteca estática (.a) y usala en programa.
Orientación:
1 2 3 4 5 6 7 8# Compilar objetos gcc -c modulo1.c modulo2.c # Crear biblioteca estática ar rcs libmibiblioteca.a modulo1.o modulo2.o # Usar biblioteca gcc main.c -L. -lmibiblioteca -o programa
ar: archiver, crea bibliotecas-L.: buscar bibliotecas en directorio actual-lmibiblioteca: enlazar con libmibiblioteca.a
Ejercicio 6.17 - Biblioteca Compartida ⭐⭐⭐⭐⭐¶
Creá biblioteca compartida (.so) y usala.
Orientación:
1 2 3 4 5 6 7 8 9 10 11 12# Compilar con PIC (Position Independent Code) gcc -fPIC -c modulo.c # Crear biblioteca compartida gcc -shared modulo.o -o libmodulo.so # Compilar programa gcc main.c -L. -lmodulo -o programa # Ejecutar (necesita encontrar .so) export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./programa
Ejercicio 6.18 - Proyecto Multi-Directorio ⭐⭐⭐⭐⭐¶
Organizá proyecto en directorios: src/, include/, obj/, bin/.
Estructura:
proyecto/
├── src/
│ ├── main.c
│ └── modulo.c
├── include/
│ └── modulo.h
├── obj/ (generado)
├── bin/ (generado)
└── MakefileMakefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18SRCDIR = src INCDIR = include OBJDIR = obj BINDIR = bin CFLAGS = -I$(INCDIR) -Wall -Wextra SRCS = $(wildcard $(SRCDIR)/*.c) OBJS = $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS)) $(BINDIR)/programa: $(OBJS) | $(BINDIR) $(CC) $^ -o $@ $(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ $(OBJDIR) $(BINDIR): mkdir -p $@
Ejercicio 6.19 - Targets Adicionales ⭐⭐⭐⭐☆¶
Agregá targets útiles: run, test, install, uninstall.
Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13run: $(TARGET) ./$(TARGET) test: $(TARGET) ./$(TARGET) test_input.txt install: $(TARGET) install -m 755 $(TARGET) /usr/local/bin/ uninstall: rm -f /usr/local/bin/$(TARGET) .PHONY: run test install uninstall
Ejercicio 6.20 - Compilación Debug/Release ⭐⭐⭐⭐⭐¶
Makefile con modo debug y release.
Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16MODE ?= release ifeq ($(MODE),debug) CFLAGS += -g -O0 -DDEBUG TARGET = programa_debug else CFLAGS += -O2 -DNDEBUG TARGET = programa endif all: $(TARGET) @echo "Compiled in $(MODE) mode" # Uso: # make # Release # make MODE=debug # Debug
Ejercicio 6.21 - Análisis Estático ⭐⭐⭐⭐☆¶
Integrá herramientas de análisis en Makefile.
Makefile:
1 2 3 4 5 6 7 8 9 10check: $(SRCS) cppcheck --enable=all $(SRCS) format: $(SRCS) clang-format -i $(SRCS) valgrind: $(TARGET) valgrind --leak-check=full ./$(TARGET) .PHONY: check format valgrind
Ejercicio 6.22 - Cross-Compilation ⭐⭐⭐⭐⭐¶
Configurá cross-compilation para diferentes arquitecturas.
Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15# Compilación nativa CC_NATIVE = gcc TARGET_NATIVE = programa # Cross-compilation para ARM CC_ARM = arm-linux-gnueabi-gcc TARGET_ARM = programa_arm arm: CC = $(CC_ARM) arm: TARGET = $(TARGET_ARM) arm: $(TARGET) native: CC = $(CC_NATIVE) native: TARGET = $(TARGET_NATIVE) native: $(TARGET)
Ejercicio 6.23 - Sistema de Build Completo ⭐⭐⭐⭐⭐¶
Proyecto completo con múltiples bibliotecas y tests.
Estructura:
proyecto/
├── lib/
│ ├── util/
│ │ ├── util.h
│ │ └── util.c
│ └── math/
│ ├── math.h
│ └── math.c
├── src/
│ └── main.c
├── tests/
│ ├── test_util.c
│ └── test_math.c
└── MakefileOrientación:
Compilar bibliotecas separadamente
Enlazar con main
Target para tests
Target para todo (all)
Ejercicio 6.24 - CMake Básico ⭐⭐⭐⭐⭐¶
Convertí proyecto a usar CMake en lugar de Makefile.
CMakeLists.txt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19cmake_minimum_required(VERSION 3.10) project(MiProyecto C) set(CMAKE_C_STANDARD 99) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") include_directories(include) add_executable(programa src/main.c src/modulo.c ) target_link_libraries(programa m) # Tests enable_testing() add_executable(tests tests/test_main.c) add_test(NAME tests COMMAND tests)
Uso:
mkdir build
cd build
cmake ..
make
./programaNotas Finales¶
Estas consignas cubren compilación desde comandos básicos hasta proyectos complejos multi-archivo con automatización profesional.