Cómo escribir tu propio Makefile
Creo que muchos amigos han tenido esta experiencia al mirar varias páginas de archivos MAKE en proyectos de código abierto y se sienten confundidos. En el estudio y el trabajo diarios, también evito los archivos MAKE de forma intencionada o no. Si puedo cambiarlos, no los escribiré. Si puedo usar IDE, usaré IDE. De hecho, escribir archivos MAKE no es tan difícil como cree, siempre que comprenda los principios y los practique usted mismo varias veces. También puedes escribir tu propio archivo MAKE y dejar que otros te miren con envidia.
A continuación presentaré mis resultados de aprendizaje. Estoy en la etapa inicial y agradezco sus correcciones.
En pocas palabras, el archivo MAKE define una serie de reglas para especificar qué archivos deben compilarse primero, qué archivos deben compilarse más tarde, qué archivos deben compilarse nuevamente e incluso los scripts de shell se pueden ejecutar en el archivo MAKE. El beneficio del archivo MAKE es: "compilación automática". Una vez escrito, solo se necesita un comando de creación y todo el proyecto se compila de manera completamente automática, lo que mejora en gran medida la eficiencia del desarrollo de software.
Acerca de la compilación y vinculación de programas
En términos generales, ya sea C o C, el archivo fuente primero debe compilarse en un archivo de código intermedio, que es un archivo .obj en Windows. En UNIX, es un archivo .o
, es decir, un archivo objeto. Esta acción se llama compilar. En términos generales, cada archivo fuente debe corresponder a un archivo de destino intermedio (archivo O o archivo OBJ). . Luego, una gran cantidad de archivos
objeto se sintetizan en archivos ejecutables. Esta acción se denomina vinculación.
Al compilar, el compilador necesita una sintaxis correcta y una declaración correcta de funciones y variables. Para este último, generalmente necesita decirle al compilador la ubicación del archivo de encabezado (el archivo de encabezado solo debe ser la declaración y la definición debe colocarse en el archivo C/C. Siempre que toda la sintaxis sea correcta). el compilador puede compilar el documento de destino intermedio.
Al vincular, se trata principalmente de funciones de vínculo y variables globales, por lo que podemos utilizar estos archivos objeto intermedios (archivos O o archivos OBJ) para vincular nuestras aplicaciones. Al vinculador no le importa el archivo fuente donde se encuentra la función, solo el archivo objeto intermedio (Objeto
Archivo) de la función. La mayoría de las veces, debido a que hay demasiados archivos fuente, hay. Hay demasiados archivos de objetos intermedios generados por la compilación. Al vincular, es necesario indicar claramente el nombre del archivo de destino intermedio, lo cual es muy inconveniente para la compilación. Por lo tanto, debemos empaquetar el archivo de destino intermedio. En Windows, se llama este paquete. un "archivo de biblioteca" (archivo de biblioteca
), que es un archivo .lib. En UNIX, es un archivo de almacenamiento, que es un archivo .a.
Empecemos a ver cómo escribir el archivo MAKE nosotros mismos.
Reglas de Makefile
Objetivo:
Condiciones requeridas (tenga en cuenta los espacios a ambos lados de los dos puntos)
Comando (tenga en cuenta el uso de la tecla de tabulación antes al principio)
Explique:
1
El objetivo puede ser uno o más, puede ser un archivo objeto, puede También puede ser un archivo ejecutable, o incluso puede ser una etiqueta.
2
Las condiciones requeridas son los archivos o objetivos necesarios para generar el objetivo
3
El comando es lo que se necesita ejecutado para generar el script de destino
En resumen, significa que una regla de archivo MAKE estipula las dependencias de la compilación, es decir, el archivo de destino depende de las condiciones y las reglas de generación se describen mediante comandos. Durante la compilación, si los archivos condicionales requeridos son más nuevos que el destino, se ejecutará un comando de compilación para actualizar el destino.
El siguiente es un ejemplo sencillo. Si un proyecto tiene 3 archivos de encabezado y 8 archivos C, para completar las tres reglas mencionadas anteriormente, nuestro Makefile debería verse como el siguiente.
editar: main.o kbd.o comando.o display.o
/
insertar.o buscar.o archivos.o utils.o p>
cc -o editar
main.o kbd.o comando.o display.o /
insertar.o buscar.o
archivos .o utils.o
main.o: main.c
defs.h
cc -c main.c
kbd .o: kbd.c defs.h
comando.h
cc -c kbd.c
comando.o: comando.c defs.h
comando.h
cc -c comando.c
display.o: display.c defs.h
buffer.h
cc -c display.c
insert.o: insert.c defs.h
buffer.h
cc -c insert .c
search.o: search.c defs.h
buffer.h
cc -c search.c
archivos .o: archivos.c defs.h buffer.h
comando.h
cc -c archivos.c
utils.o: utils.c
defs.h
cc -c utils.c
limpiar:
rm editar main.o
kbd.o command.o display.o /
insert.o search.o files.o
utils.o
Escriba el contenido anterior en Makefile, luego ejecute make para compilar y ejecute make
clean para eliminar todos los archivos de destino. Explique, es decir, generar la edición final del archivo de destino depende de una serie de archivos de destino .o, y estos archivos .o deben compilarse y generarse con los archivos fuente.
Cabe señalar que no hay ninguna condición después de la limpieza, y la limpieza en sí no es un archivo, es solo un nombre de acción sin nada después de los dos puntos. Entonces make no encontrará automáticamente la dependencia. los comandos definidos posteriormente no se ejecutarán automáticamente.
Cómo funciona make
En el modo predeterminado, es decir, solo ingresamos el comando make. Luego,
1. make buscará un archivo llamado "Makefile" o "makefile" en el directorio actual.
2. Si lo encuentra, encontrará el primer archivo de destino (destino) en el archivo. En el ejemplo anterior, encontrará el archivo "editar" y utilizará este archivo como documento de destino final.
3. Si el archivo de edición no existe, o la hora de modificación del archivo .o del que depende la edición es más reciente que el archivo de edición, se ejecutará con el comando definido más adelante. generar el archivo de edición.
4. Si el archivo .o del que depende la edición no existe, make buscará la dependencia del archivo .o de destino en el archivo actual. Si lo encuentra, generará el archivo . o presentar de acuerdo con esa regla. (Esto es un poco como un proceso de pila)
5. Por supuesto, su archivo C y su archivo H existen, por lo que make generará el archivo .o y luego usará .o
< p. > La tarea final de la vida útil de un archivo es ejecutar la edición del archivo.Uso de variables en archivos MAKE
El conocimiento previo es suficiente para que usted mismo pueda completar un archivo MAKE simple, pero las sutilezas de los archivos MAKE son mucho más que eso. Echemos un vistazo a cómo hacerlo. use variables en archivos MAKE. Use variables en él.
En el ejemplo anterior, veamos primero las reglas de edición:
edit: main.o kbd.o command.o
display.o /
insertar.o buscar.o archivos.o
utils.o
cc -o editar principal.o kbd.o comando.o mostrar.o
/
insert.o search.o files.o utils.o
Podemos ver que la cadena del archivo [.o] se repite dos veces Esta vez, si nuestro proyecto necesita agregar un nuevo archivo [.o], entonces debemos agregarlo en dos lugares (deben ser tres lugares y un lugar limpio). Por supuesto, nuestro archivo MAKE no es complicado, por lo que no es agotador agregarlo en dos lugares, pero si
el archivo MAKE se vuelve complicado, es posible que olvidemos un lugar que debe agregarse, lo que provocará la compilación. fracasar. Por lo tanto, para que el archivo MAKE sea fácil de mantener, podemos usar variables en el archivo MAKE. La variable del archivo MAKE también es una cadena, que puede entenderse mejor como una macro en lenguaje C.
Entonces usamos la variable objetos
objects = main.o kbd.o command.o display.o
/
insert .o search.o files.o utils.o
De esta manera, el makefile original queda como sigue:
objects = main.o kbd.o command.o display . o
/
insertar.o buscar.o archivos.o utils.o
editar: $(objetos)
cc - o editar $(objetos)
main.o: main.c defs.h
cc -c
main.c
kbd.o: kbd.c defs.h comando.h
cc -c kbd.c
comando.o: comando.c defs.h comando.h
cc -c comando.c
display.o: display.c defs.h buffer.h
cc -c display.c
insertar .o: insert.c defs.h buffer.h
cc -c insert.c
search.o: search.c defs.h buffer.h
cc -c buscar.c
archivos.o
: archivos.c defs.h buffer.h comando.h
cc -c archivos . c
utils.o
: utils.c defs.h
cc -c utils.c
limpiar:
p>rm
editar $(objects)
Esto parece mucho más conveniente y ahorra problemas. ¿Qué pasa si hay nuevos archivos .o? Por supuesto, se agrega en los objetos, por lo que solo se necesita un cambio, lo cual es muy conveniente.
Dejemos que make deduzca automáticamente
GNU make es muy poderoso. Puede deducir automáticamente los comandos detrás de los archivos y las dependencias de los archivos, por lo que no necesitamos revisar cada [.o]. Escriba comandos similares después del archivo, porque nuestra marca lo reconocerá automáticamente y derivará el comando por sí mismo.
Siempre que make vea un archivo [.o], agregará automáticamente el archivo [.c] a las dependencias. Si make encuentra un what.o, entonces what.c será un dependiente. archivo de lo que sea.o. Y
cc -c what.c
también se deducirá, por lo que nuestro archivo MAKE ya no necesita ser tan complicado. Nuestro nuevo archivo MAKE está disponible nuevamente.
objetos = main.o kbd.o comando.o display.o
/
insertar.o buscar.o archivos.o utils.o p>
editar: $(objetos)
cc -o editar $(objetos)
main.o: defs.h
kbd.o :
defs.h comando.h
comando.o : defs.h comando.h
display.o : defs.h
buffer.h
insertar.o: defs.h buffer.h
buscar.o: defs.h
buffer.h
archivos.o: defs.h buffer.h comando.h
utils.o:
defs.h
limpio:
rm edit
$(objects)
Por supuesto, si te sientes un poco incómodo con tantas dependencias [.o] y [.h], está bien, no hay problema , esto es muy fácil de hacer. ¿Quién le dijo que proporcionara la función de derivar comandos y archivos automáticamente? Echemos un vistazo al último estilo de makefile.
objetos = main.o kbd.o comando.o display.o
/
insertar.o buscar.o archivos.o utils.o p>
editar: $(objetos)
cc -o editar $(objetos)
$(objetos): defs.h
kbd. o
comando.o archivos.o : comando.h
display.o insertar.o buscar.o archivos.o :
búfer.h p>
limpiar:
rm editar $(objetos)