Manejo de Proyectos a través de Makefiles
Descripción
El comando Make nos permite administrar grupos de programas. En la medida que trabajamos con programas más largos, el proceso de recompilación toma más tiempo. Por otro lado notamos que generalmente estamos trabajando en una sección reducida del programa y el resto permanece sin cambio. El programa make nos ayuda a desarrollar grandes programas al mantener registro de las partes del programa que han cambiado, así compila sólo aquella parte modificada desde la última compilación.

Compilación simple
compilación simple
El comando en este caso es simple: cc file.c , pero hay tres pasos antes de llegar al ejecutable final.

Compilación de varios archivos
varios archivos

Cuando el programa es más grande o tiene varias unidades lógicas, tiene sentido dividir el código fuente en archivos separados .c más fáciles de manejar. En este caso el comando será: cc green.c blue.c
 
Compilación Separada

Separada
 
El proceso puede ser dividido en dos compilaciones y un ligado.
La opción -c permite avanzar sólo el paso en rojo. cc -c green.c generará así green.o pero no a.out.
para producir el ejecutable en este caso se deberá hacer:
cc -c green.c
cc -c blue.c
cc green.o blue.o

Grafo de Dependencias
Dependencias

make opera en base a las dependencias de los archivos. Por ejemplo para crear program.o se requiere program.c Puede haber otras dependencias con program.h también.

Ahora, si hacemos un cambio en un archivo make puede darse cuenta qué archivos deben ser recompilados para generar una nueva versión del proyecto.
Grafo editado

¿Cómo trabaja make?
grafo makefiel

El comando make obtiene el grafo de dependencia de un archivo de texto llamado makefile o Makefile.

Construcción del archivo Makefile
makemake
El formato básico es:
target : archivos_fuente(s)
    comando(s) (debe ser precedido por un tab)
Podemos poner comentarios poniendo el signo # como primer caracter de la línea.

Usando Makefile con make
Una vez construido basta con invocar:
%make

make lee el archivo makefile o Makefile del directorio actual y lo procesa. En este caso el resultado sería:
% make
cc -c data.c
cc -c main.c
cc -c io.c
cc data.o main.o io.o -o project1
%


Uso de Macros
Se pueden definir macros para almacenar nombres. El formato es:
OBJECTS = data.o io.o main.o

Cuando queremos usar la macro (queremos usar su valor) lo hacemos con el string $(OBJECTS).

Por ejemplo:

OBJECTS = data.o main.o io.o
project1: $(OBJECTS)
cc $(OBJECTS) -o project1
data.o: data.c data.h
cc -c data.c
main.o: data.h io.h main.c
cc -c main.c
io.o: io.h io.c
cc -c io.c
También se pueden especificar los valores de una macro en la línea de comando de make.
make 'OBJECTS=data.o newio.o main.o' project1
Esto escribe sobre el valor de OBJECTS definido dentro de Makefile

Macros especiales
Hay algunas macros ya definidas y usadas por make. Algunas son:
CC
    Se refiere al compilador C actual. Por defecto cc.
$@
    Nombre completo del "target" actual
$?
    La lista de dependencias actuales fuera de fecha.
$<
    El archivo fuente de la dependencia actual.
Se puede manipular algunas macros. por ejemplo: si  OBJS = data.o io.o main.o, y usamos $(OBJS:.o=.c) en el Makefile sustituirá .o al final por .c, Este conducirá a : data.c io.c main.c
       

Reglas predefinidas
Make sabe que para generar un archivo .o requiere del correspondiente .c  y hace cc -c program.c
Por lo anterior no es necesario especificar todo y podemos reducir nuestro archivo makefile.
OBJECTS = data.o main.o io.o
project1: $(OBJECTS)
cc $(OBJECTS) -o project1
data.o: data.h
main.o: data.h io.h

io.o: io.h
Más simplificaciones:
Es posible poner  más de un archivo en la sección target de la regla de dependencia. En este caso la dependencia es el and entre todas.
OBJECTS = data.o main.o io.o
project1: $(OBJECTS)
cc $(OBJECTS) -o project1
data.o main.o: data.h
io.o main.o: io.h

Significa que main.o depende de data.h y io.h además de main.c que no es necesario anotar,.
 
Uso de sufijos
Make tiene un target especial llamada .SUFFIXES que permite definir sufijos. Por ejemplo la línea de dependencia:
.SUFFIXES:  .cpp
Le indica a make que usaré estos sufijos especiales para construir mis  reglas:

Ahora así como make sabe construir .o a partir de .c, yo puedo indicar:

.cpp.o:
        $(CC)   -c    $<

o más corto aún
.cpp.o: ; $(CC)   -c    $<


Más información: ver man make y el manual GNU de make