[UCR]  
[/\]
Universidad de Costa Rica
Escuela de Ciencias de la
Computación e Informática
[<=] [home] [<>] [\/] [=>]

MAKE: cómo compilar rápido en Clipper

Adolfo Di Mare



Resumen [<>] [\/] [/\]

Se discute cómo usar el programa MAKE para recompilar programas Clipper para aumentar hasta en cinco veces la velocidad de compilación. This paper describes how to use the MAKE program to recompile Clipper programs faster, speeding up compilation times even five times.

      Muchos de nuestros programadores han aprendido a programar solos, sin tener la oportunidad de conocer todas las herramientas que han sido desarrolladas para mejorar el oficio. Nuestros programadores no son malos, pero como no conocen algunos trucos importantes, son menos productivos de lo que deberían.

      Después de programar durante tres o cuatro años, lo común es sentir que ya se sabe todo, y que no hay nada nuevo por aprender. ¿Porqué leerse un nuevo manual, si con lo que ya se sabe puede hacerse cualquier trabajo, efectivamente? En la profesión de la computación es necesario continuar aprendiendo, pues todavía no es totalmente claro cuáles son todos los conocimientos básicos del oficio, en contraste con otras profesiones como el derecho o la medicina.

      Cuando se usa el lenguaje Clipper es necesario recompilar el programa muchas veces, pues la programación es un proceso iterativo, en el que el programa correcto no se obtiene en la primera prueba, sino después de muchos intentos y correcciones. Pero como muchos programadores ya saben, cada recompilación con Clipper toma mucho, mucho tiempo.

      La razón de esto es que con frecuencia los programas no están estructurados en módulos, y entonces cada vez que se hace un cambio debe recompilarse todo el programa. Algunos programadores avispados parten su programa en pedazos, y cuando hacen un cambio, nmanualmente recompilan únicamente el módulo que ha sido modificado.

      Pero al hacer todo este proceso manualmente puede olvidarse recompilar algún módulo; el resultado sería no usar la nueva versión del módulo, pues no ha sido recompilado. Veamos un ejemplo completo, que me he tomado la libertad de pedir prestado a mi hermano quien, como yo, se dedica a la programación.

      El escribió un programa Clipper para mantener cuentas de cheques. Como usa ciertas convenciones de programación, todos los nombres de los módulos de sus sistemas comienzan con dos letras que los distinguen. En este caso, las letras son SC (por Sistema de Cheques). Los módulos del sistema son los siguientes:

Directorio  C:\USR\ADH\LUIS\*.prg

SC00  .PRG   2288      SC07  .PRG    1649
SC01  .PRG  13764      SC08  .PRG   12544
SC02  .PRG   3078      SC09  .PRG    4075
SC03  .PRG   2462      SC10  .PRG    1248
SC04  .PRG   3483      SCMENS.PRG     574
SC05  .PRG   2011      SCTYPE.PRG     417
SC06  .PRG  13555

      El programa principal se llama SC00.prg, y los demás son sus módulos. Como puede verse del tamaño de cada módulo, el sistema no es muy grande. Pero recompilarlo todo en un computador con procesador 8086 a 7Mhz toma 10 minutos. En una IBM/xt toma cerca de 20 minutos, que es inaceptable.

      La primera mejora que debemos hacer es compilar por separado cada uno de los módulos. Cada archivo con extensión .prg generaría entonces un correspondiente archivo objeto con extensión .obj. Todos los móulos deben ser combinados luego con el ligador de eslabonamiento (Link o Plink86)[1]. Al compilar se obtienen los siguientes archivos:

Directorio  C:\USR\ADH\LUIS\*.obj

SC00  .OBJ   3014      SC07  .OBJ    2610
SC01  .OBJ  15821      SC08  .OBJ   15094
SC02  .OBJ   3830      SC09  .OBJ    5517
SC03  .OBJ   3662      SC10  .OBJ    2788
SC04  .OBJ   4665      SCMENS.OBJ    1123
SC05  .OBJ   3025      SCTYPE.OBJ     963
SC06  .OBJ  15890

      Si usamos el Clipper versión otoño 1986, cada .obj se obtiene mediante el comando:
   Clipper archivo -m -n
donde archivo es cada uno de SC*.prg. La opción "-m" evita que al compilar cada archivo también se compilen todos los módulos que usa. La opción "-n" le indica a Clipper que si puede haga el programa más rápido, aunque ocupe un poco más de espacio.

      Una vez modularizado el programa, cada vez que se haga un cambio a un módulo hay que recompilar el archivo correspondiente. Por ejemplo, si se cambiara el módulo SCmens.prg, deberemos ejecutar el comando:
   Clipper SCmens -m -n
El problema surge cuando se hacen muchos cambios, y ya uno no se acuerda de qué cosas cambió: en este caso lo más seguro es recompilar todos los módulos.

      Pero hacer esto de nuevo toma mucho tiempo (cerca de 8 minutos para este sistema)[2]. Un mejor método es fijarse en las fechas de creación de cada archivo: si un .prg es más nuevo que su .obj es porque necesita ser recompilado, pues obviamente el .obj fue producido con una versión anterior (desactualizada) del .prg. Por ejemplo, supongamos que el módulo SC04.prg fue modificado por última vez en la fecha
   Dic-15-1987 || 12:13 pm
y que fue compilado un buen rato después, en
   Jul-28-1988 ||  5:35 pm.
En este contexto, el comando dir SC04.* daría el siguiente listado:

Directorio  C:\USR\ADH\LUIS\SC04.*

SC04     PRG     3483   Dic-15-1987  12:13 pm
SC04     OBJ     4665   Jul-28-1988   5:35 pm

      Como puede verse, el .obj es más nuevo que su archivo .prg, que no ha sido cambiado recientemente. O sea, después de cambiar el .prg se obtuvo el .obj, por lo que la fecha del .prg es más vieja que la del .obj.

      Pero supongamos ahora que le hacemos un cambio al .prg (en este caso lo único que hice fue borrar y reescribir una letra):

Directorio  C:\USR\ADH\LUIS\SC04.*

SC04     PRG     3483   Ago-05-1988  11:47 am
SC04     OBJ     4665   Jul-28-1988   5:35 pm

      Ahora el .obj es más viejo que el .prg. Aunque el .obj existe, es anterior al .prg, lo que indica que fue obtenido a partir de una versión anterior, ya obsoleta, del .prg. Por eso tenemos que recompilar el .prg para obtener un .obj nuevo:

Directorio  C:\USR\ADH\LUIS\SC04.*

SC04     PRG     3438   Ago-05-1988  11:47 am
SC04     OBJ     4665   Ago-05-1988  11:48 am

      Ahora sí se cumple que el módulo compilado .obj tiene fecha posterior al módulo fuente. Para obtener el programa completo nuevo, basta ahora ejecutar el Link con los parámetros adecuados. El tiempo total de recompilación no pasa ahora de 2 minutos (que es 4 veces más rápido que 8 minutos, o 5 veces más rápido que 10). Veamos como el programa MAKE [Fel-79] automatiza el proceso de verificar que cada .obj sea más viejo que el .prg que lo generó. Para esto mi hermano usa el siguiente archivo[3], llamado MAKEFILE:

# MAKEFILE: Recompila todo el sistema SC*.* con  Clipper

# Para recompilar basta ejecutar el comando C:>MAKE

# Se necesita esta regla, de primero, para que MAKE siempre
# verifique todo (SCprk no existe nunca como archivo).
mSC00: SCprk SC00.exe

# Regla general para compilar un archivo .prg en Clipper
# Clipper deja el archivo compilado en $&.obj
.prg.obj:
  Clipper $& -m -n

# Aquí hay que poner todos los .obj que se obtienen al
# compilar un .prg con el Clipper.
SC00.exe:   \
  SC00.obj  \
  SC01.obj  \
  SC02.obj  \
  SC03.obj  \
  SC04.obj  \
  SC05.obj  \
  SC06.obj  \
  SC07.obj  \
  SC08.obj  \
  SC09.obj  \
  SC10.obj  \
  SCMENS.obj  \
  SCTYPE.obj
    tlink @SC00.lnk \Clipper\extendC,SC00,  \
          SC00.MAP,\Clipper\Clipper \Clipper\memo

# El archivo SC00.lnk DEBE contener todos los nombres de archivo
# .obj separados por un "+".
# Una forma fácil de generar el archivo  .lnk es copiar todos
# los "*.obj \: de la regla para SC00.exe:, para sustituir el
# "\" por el "+".
# Es importante que el primer .obj que aparezca en la lista del
# tlink (contenida en SC00.lnk) sea el programa principal.

# Regla genérica para producir el nuevo .prg desde el .prk
.prk.prg:
   DBcomp $&.prk  $&.prg

# Aquí hay que poner todos los .prg que deben ser generados
# desde un .prk con el DBcomp. Si algún .prg NO tiene su .prk,
# entonces NO debe incluirse en esta lista (como el SCTYPE.prg,
# para el que no existe el archivo SCTYPE.prk)
SCprk: \
  SC00.prg \
  SC01.prg \
  SC02.prg \
  SC03.prg \
  SC04.prg \
  SC05.prg \
  SC06.prg \
  SC07.prg \
  SC08.prg \
  SC09.prg \
  SC10.prg \
  SCMENS.prg

# FIN del MAKEFILE

      En el MAKEFILE se menciona otro archivo, llamado SC00.lnk, que contiene todos los .obj para que el Tlink (Turbo Link) los procese [BI-88]:

SC00.obj +
SC01.obj +
SC02.obj +
SC03.obj +
SC04.obj +
SC05.obj +
SC06.obj +
SC07.obj +
SC08.obj +
SC09.obj +
SC10.obj +
SCMENS.obj  +
SCTYPE.obj  +

      Ahora vale una explicación de toda la maraña. En este ejemplo usamos el MAKE de Borland (versión 1.3), que obtuvimos con programa Turbo C. El ligador de eslabonamiento se llama Tlink (versión 1.1). Yo escribí el programa DBcomp.pas para mi hermano, que se usa para transformar un archivo .prk en un .prg.

      El MAKEFILE es el archivo de entrada al programa MAKE, que básicamente verifica las fechas de los archivos ahí mencionados, y con base a ellas ejecuta comandos. El MAKEFILE está compuesto de reglas, que tienen una parte izquierda (que está antes de los dos puntos), una parte derecha (que denota las dependencias), y los comandos. La idea es que si un archivo (parte izquierda) es más nuevo que alguno de los archivos de su parte derecha, entonces debe ser regenerado usando el comando respectivo. Por ejemplo, para regenerar el SC04.obj a partir del SC04.prg usaríamos la regla:
   SC04.obj: SC04.prg
     Clipper SC04 -m -n

      En este ejemplo "SC04.obj:" es la parte izquierda, "SC04.prg" es la derecha, y:
   Clipper SC04 -m -n
es el comando para regenerar el SC04.obj a partir de SC04.prg. MAKE permite reglas genéricas, como es el caso de la regla cuyo encabezado es ".prg.obj", que le indica a MAKE que si un archivo .obj es más viejo que su .prg, entonces debe ser regenerado usando el comando:
   Clipper $& -m -n
MAKE sustituye el símbolo $& por el nombre del archivo, (SC04 en nuestro ejemplo).

      La notación que debemos usar al escribir el archivo MAKEFILE es un poco incómoda, y para entenderla es necesario consultar el manual respectivo. En este escrito no hay espacio para tanto detalle, que sí está en los manuales. Baste decir que las partes izquierdas de las reglas deben escribirse a partir de la columna 1, y que todo lo demás debe estar indentado al menos apartir de la columna 2. El caracter "\" se usa para continuar renglones. MAKE es un programa que no es liberal con la sintáxis, y es importante escribir bien las cosas para que las entienda.

      Para recompilar el sistema SC basta dar el comando C:>make. Al hacer esto, MAKE tratará de satisfacer la primera regla del archivo MAKEFILE, que en este caso es:
   mSC00: SCprk SC00.exe
Esta regla dice que el archivo mSC00 depende de dos archivos, llamados SCprk y SC00.exe (el segundo es el nombre del programa compilado que queremos obtener). Como esta regla no tiene ningún comando asociado, lo que MAKE hace es verificar que SCprk y SC00.exe sean más viejos que los archivos de que dependen. En este ejemplo el SC00.exe depende de todos los .obj del sistema.

      Paradójicamente, el archivo mSC00 no debe existir, para forzar a MAKE a usar las reglas que tienen por parte izquierda SCprk y SC00.exe. Lo mismo se aplica al archivo SCprk.

      La regla que tiene por parte izquierda "SC00.exe:" indica a MAKE que si algún *.obj es más nuevo que SC00.exe, entonces debe regenerarse SC00.exe invocando al programa (Tlink). Tlink usará todos los archivos .obj que forman el programa, junto con las bibliotecas Clipper adecuadas. En este caso, usamos las blibliotecas Clipper.lib y memo.lib, y el extendC.obj. El Tlink hace uso del archivo SC00.lnk, en el que (redundantemente) están los nombres de todos los .obj que forman el programa.

      Debo explicar la función del programa DBcomp.exe. Mi hermano siempre ha dicho que los programas DBase III "gastan" demasiados renglones, por lo que me pidió que le escribiera el DBcomp para "ahorrar" un poco de espacio de pantalla. El DBcomp toma cada línea
   IF editar=1 | read | ELSE | clear gets | ok = .T. | ENDIF
y la transforma en la siguientes líneas (compilables por Clipper):

IF editar=1
read
ELSE
clear gets
ok = .T.
ENDIF

      Entonces el sistema SC realmente está escrito en varios archivos *.prk, que se usan para generar los archivos *.prg. Para automatizar este proceso de conversión se usan tres reglas:

  1. mSC00: SCprk SC00.exe
  2. .prk.prg
  3. la regla que tiene por parte izquierda "SCprk"

En esta última regla se dice que el archivo SCprk depende no de los archivos *.prk sino de los *.prg; esto hace que MAKE use la regla genérica ".prk.prg" (que invoca al DBcomp) cuando un archivo .prk es más nuevo que el .prg respectivo. Aunque el archivo SCprk nunca existirá, para MAKE basta ejecutar el código que supuestamente lo crea, pues luego continuará procesando las reglas que dependen de SCprk.

      Como no todos los .prg tiene un .prk que los genere, no todos los archivos .prg deben aparecer en la parte derecha de la regla "SCprk:". En un comentario del MAKEFILE también se menciona este hecho.

      Tal vez parezca que todo esto es demasiado complicado para ser efectivo. Pero como el tiempo de recompilación se reduce drásticamente al usar este truco, entonces es importante usarlo.

      El programa MAKE es una de las más útiles herramientas derivadas del sistema operativo UNIX [RT-74], que ya casi cumple 20 años de edad. Esta herramienta es necesaria para evitar recompilar los módulos de un sistema grande, aunque puede usarse en otros contextos. En la plataforma UNIX hay otras herramientas muy útiles para programadores los programadores, como las descritas en [KP-87].

Conclusión [<>] [\/] [/\]

      Es relativamente sencillo disminuir los tiempos de compilación usando el programa MAKE para recompilar sólo aquellos módulos que han cambiado, y no todos. Como no usar MAKE al programar conduce a desperdiciar el valioso tiempo del programador, que es el recurso más caro en el ciclo de vida de un sistema, el programador que desconozca esta valiosa herramienta aumenta innecesariamente el costo de producir cualquier sistema. Hay que conocer las herramientas de la profesión.

Agradecimientos [<>] [\/] [/\]

      Mi hermano Luis Alberto Di Mare fue quien me mostró la necesidad de discutir, en el contexto expecífico del lenguaje Clipper, cómo usar tanto a MAKE como a DBcomp.

Reconocimientos [<>] [\/] [/\]

      Esta investigación se realizó dentro del proyecto de investigación 326-86-053 "Conversión automática de programas después de reestructurar una base de datos", inscrito ante la Vicerrectoría de Investigación de lade la Universidad de Costa Rica. La Escuela de Ciencias de la Computación e Informática también ha aportado fondos para este trabajo.

Notas de pie de página [<>] [\/] [/\]

[1] El ligador de eslabonamiento es el programa que se encarga de tomar todos los módulos compilados de un programa, que generalmente tienen extención .obj, y los liga todos para producir el programa ejecutable final, de extensión .exe.
[2] Conforme pase el tiempo los computadores serán cada vez más veloces, pero ese aumento de capacidad se traducirá en programas más grandes. Por eso no llegaremos a despreciar el ahorro de tiempo que se puede lograr empleando la técnica descrita en este documento.
[3] Cuando el programa MAKE es invocado sin argumentos, por defecto procesa el archivo llamado MAKEFILE del directorio. Por eso es saludable que todos los módulos de un programa estén juntos en el mismo directorio.


Bibliografía [<>] [\/] [/\]

[BI-88] Borland International: Turbo Pascal Reference Manual version 5.5, Borland International, California (U.S.A.), 1988.
[Fel-79] Feldman, Stu: Make -- a program for maintaining computer programs, Software Practice and Experience, Vol.9(4), Abril 1979.
[KP-87] Kernighan, B. & Pike, Rob: El entorno de programación UNIX, Prentice-Hall, 1987.
[RT-74] Ritchie, D.M. & Thompson, K.L.: The UNIX Time-Sharing System, Communications of the ACM, Julio 1974.


El archivo DBcomp.pas se puede obtener bajando en modo binario el siguiente archivo:
ftp://www.di-mare.com/adolfo/p/src/dbcomp.pas
El programa ya compilado DBcomp.exe se puede obtener ahí también:
http://www.di-mare.com/adolfo/p/src/dbcomp.exe
El archivo MAKEFILE está en:
http://www.di-mare.com/adolfo/p/src/makedbf.mak
Todos los archivos juntos está aquí:
http://www.di-mare.com/adolfo/p/src/makedbf.zip


Indice [<>] [\/] [/\]

[-] Resumen
[-] Conclusión
[-] Agradecimientos
[-] Reconocimientos

Notas de pie de página
Bibliografía
Indice
Acerca del autor
Acerca de este documento
[/\] Principio [<>] Indice [\/] Final


Acerca del autor [<>] [\/] [/\]

Adolfo Di Mare: Investigador costarricense en la Escuela de Ciencias de la Computación e Informática [ECCI] de la Universidad de Costa Rica [UCR], en donde ostenta el rango de Profesor Catedrático. Trabaja en las tecnologías de Programación e Internet. Es Maestro Tutor del Stvdivm Generale de la Universidad Autónoma de Centro América [UACA], en donde ostenta el rango de Catedrático y funge como Consiliario Académico. Obtuvo la Licenciatura en la Universidad de Costa Rica y la Maestría en Ciencias en la Universidad de California, Los Angeles [UCLA].

[mailto] Adolfo Di Mare <adolfo@di-mare.com>


Acerca de este documento [<>] [\/] [/\]

Referencia: Di Mare, Adolfo: MAKE: cómo compilar rápido en Clipper, Reporte Técnico PIBDC-04-88, Escuela de Ciencias de la Computación e Informática, Universidad de Costa Rica, 1988.
Internet: http://www.di-mare.com/adolfo/p/makedbf.htm
http://www.di-mare.com/adolfo/p/src/makedbf.zip
Autor: Adolfo Di Mare <adolfo@di-mare.com>
Contacto: Apdo 4249-1000, San José Costa Rica
Tel: (506) 207-4020       Fax: (506) 438-0139
Revisión: ECCI-UCR, Noviembre 1997
Visitantes:

Copyright © 1997 Adolfo Di Mare
Derechos de autor reservados © 1997 Adolfo Di Mare <adolfo@di-mare.com>
[home] [<>] [/\]