🇺🇦 Слава Україні! Consulta cómo puedes ayudar a Ucrania desde España u otros países en supportukrainenow.org.

GNU Make

Recompilando dependencias

• Duración: 6:54 • #gnu #linux #make #unix #gcc #build-tools

La gracia de Make está, sin duda, en la posibilidad de recompilar algunas partes de nuestro programa sin tener que recompilarlo todo. En este vídeo te cuento el criterio que usa Make.

Este vídeo lamentablemente todavía no tiene notas de episodio. Todavía quedan algunos vídeos en este sitio web que no tienen artículos de texto por si te gusta más leer que ver vídeos, y parece que esta página es una de ellas. Hay una transcripción del audio disponible para ayudarte a llegar a este vídeo que puede que te ayude.

¡Ayúdame a saber qué es prioritario y qué no! ¿Te hubiese ayudado encontrar un artículo de texto en esta página junto al vídeo?

Desplegar transcripción del episodio

y en lo que me voy a centrar es en cómo hace Make para determinar cuándo es buena idea recompilar algo o no. Me explico, imaginemos que yo he compilado mi programa y que esto vale, por simplificar ha tardado dos segundos, pero imaginaos que tarda cinco minutos porque es un programa muy complejo y que tiene un montón de códigos fuente o que tiene un montón de líneas y le lleva tiempo. Evidentemente no nos interesa que si yo hago a Make se vuelvan a perder dos minutos, pero afortunadamente para eso, yo he establecido aquí mis reglas y he dicho que para compilar programa antes tengo que compilar todos sus objetos, y he declarado una regla independiente para cada objeto. Eso significa que si yo ahora ejecuto Make, Make se va a dar cuenta que no es necesario recompilarlo todo porque los objetos ya están creados, entonces si yo vuelvo a correr Make, me va a decir que no se tiene que hacer nada. Claro que en alguna ocasión yo tengo que hacer una modificación de un archivo. ¿Qué es lo que ocurre? ¿Qué es lo que hace que Make diga cuando algo se tiene o no que recompilar? El secreto está en las fechas de modificación y para eso voy a hacer un ls-l para que veamos las fechas en las que he modificado estos archivos. Aquí veis por ejemplo que calculadora lo he modificado esta mañana a las 2 y 18 horas. Esa es la última vez que modifique el archivo calculadora.c. Acabo de recompilar calculadora.o cuando son las 18 horas y 20 minutos. Básicamente significa que mi archivo de código fuente es 4 horas más viejo que mi archivo de código objeto. Atención a la jugada. Si yo modifico un archivo, por ejemplo aquí digo que la suma se va a cambiar y por ejemplo ahora esto se va a guardar con un valor y va a devolver el valor. Vale un pequeño cambio insignificante pero un cambio igualmente. Cuando yo lo guarde va a ocurrir una situación muy interesante. Como veis si puedo eliminar todos los archivos que me genera esto. Como veis ahora lo que ocurre es que mi archivo de código fuente es más reciente que el código objeto que lleva asociado. Eso significa que ahora sí es necesario recompilarlo porque make se dará cuenta que algo ha tenido que tocarse aquí porque el binario que hemos obtenido, bueno el objeto que hemos obtenido a partir de esta regla está obsoleto. Se ha modificado algo y el archivo de código fuente, una de sus dependencias es más moderna que el propio objetivo. Por lo tanto este objetivo tiene que estar anticuado. A lo mejor simplemente he pulsado control s y se ha hecho cualquier cosa pero bueno que en cualquier caso está obsoleto de algún modo. Entonces lo que va a ocurrir es que la próxima vez que se ejecute esa regla, por ejemplo make calculadora.o, se va a recompilar para que sea más moderno. Si yo simplemente hago make salida.c o make salida.o más bien, como veis no ocurre nada porque está ya actualizado. Pero si yo hago una modificación también a salida.c y lo cambio por el valor, pues ya no va a estar actualizado porque otra vez más el archivo de código fuente es más nuevo que el archivo de código objeto. Por lo que si yo vuelvo a ejecutarlo pues lo va a tener que recompilar. Esto es lo que hace realmente make por dentro. Cuando yo compilo un programa y tengo una serie de dependencias, lo que va a hacer es ver si esas dependencias se tienen que recompilar en función de si alguna de sus dependencias a la vez es más nueva que el propio objetivo. En ese caso lo que hace es recompilarlo. Cuando lo hacemos sobre programa, que tiene varios objetos que a la vez son sus propias reglas, se evalúa cada una de ellas y recompila lo que haga falta. Entonces en este caso, como he recompilado algunos de los objetos de los que depende programa, y programa es más antiguo que esos objetos, si yo hago make va a tener que recompilarlo. Ahora ya no tiene que hacer nada, no pasa nada, pero en este caso sí que ha sido necesario. Imaginemos que modifico también calculadora, este ya lo he tocado. Imaginemos que modifico main y ahora cambio los valores por 3 y 4. En este caso, como ha cambiado main.c, se tiene que regenerar main.o. Entonces si yo ejecuto ahora secas make, lo que va a ocurrir es que como veis se da cuenta que solo main tiene que regenerarse porque solo main es más nuevo main.c que main.o. Todos los demás, debido a que no se han modificado desde la última vez que se generó su archivo de código objeto, no es necesario que se modifiquen. Y una vez que lo tenemos actualizado, como de costumbre, se recompila el programa principal porque se ha modificado alguna de sus dependencias. Entonces si alguna vez os preguntáis cómo funciona esto, pues realmente ese es el funcionamiento. A partir de las fechas y las horas, es necesario que estén bien, por lo tanto que tengan sentido, en la mayoría de los casos va a ser así, se puede determinar cuando un objeto está obsoleto o no, o cuando un objetivo está obsoleto o no. Esto está muy bien como digo cuando tenemos decenas de cientos de archivos en distintas carpetas porque solamente se va a recompilar lo que hayamos modificado. Y eso nos va a permitir que si tenemos un programa que le tarda varios minutos en recompilarse, pues no se tarda en varios minutos, se tarda en a lo mejor varias decenas de segundos en función de lo que tarde compilarse todo lo que se ha tocado. Y luego el enlazador no necesita que se recompilen los punto o que no se tengan por qué tocar porque no se hayan tocado. En eso consiste el funcionamiento de cuando make decide cuando una dependencia es más nueva y cuando un objetivo está desincronizado o necesita de alguna forma regenerarse porque está obsoleto. Y es lo que permite que make funcione tal y como funciona, y es lo que le hace potente. Evidentemente si intentáis hackear make al máximo y lo utilizáis para cosas que no vienen al caso, por ejemplo, para vuestros propios fines, tenéis que tener en cuenta siempre esto, porque a veces ocurre que como no tenemos en cuenta las dependencias de entrada, a mí me suele ocurrir cuando utilizo make para generar archivos PDF a partir de archivos.txt. Si no tenemos en cuenta muy bien cómo funciona, es posible que a veces se ejecute código que no se tenga que ejecutar simplemente porque algunas reglas están mal hechas y sus dependencias siempre van a ser más recientes que el propio objeto. Así que en ese caso es necesario tenerlo más o menos bien en cuenta y evitar que ocurra eso, pero en cualquier caso siempre es una forma muy interesante conocer cómo funciona make por dentro porque es lo que le hace muy potente.