Compilación

Ahora que el software está configurado correctamente, sólo falta compilarlo. Generalmente esta parte es fácil, y no presenta problemas serios.

Make

make es la herramienta favorita de la comunidad de software libre para compilar los fuentes. Tiene dos cosas interesantes:

  • le permite ganar tiempo al desarrollador, porque le permite administrar la compilación de su proyecto de manera eficiente,

  • permite que el usuario final compile e instale el software en pocas líneas de comando, incluso si no tiene conocimientos preliminares de desarrollo.

Las acciones a ejecutar para obtener una versión compilada de los fuentes generalmente se almacenan en un fichero denominado Makefile o GNUMakefile. De hecho, cuando se invoca a make, este lee dicho fichero, si existe, en el directorio corriente. Si no es así, se puede especificar el fichero usando la opción -f con make.

Reglas

make funciona de acuerdo a un sistema de dependencias, razón por la cual la compilación de un fichero binario (“objetivo”) necesita pasar por varias etapas (“dependencias”). Por ejemplo, para crear el fichero binario (imaginario) glloq, se deben compilar y luego vincular los ficheros objeto main.o e init.o (ficheros intermedios de la compilación). Estos ficheros objeto también son objetivos, cuyas dependencias son sus ficheros fuente correspondiente.

Este texto sólo es una introducción mínima para sobrevivir en el mundo sin piedad de make. Para una documentación exhaustiva, debe referirse a Managing Projects with Make (Administración de proyectos con Make), segunda edición, de O'Reilly, por Andrew Oram y Steve Talbott.

Go, go, go!

Por lo general, el uso de make obedece a muchas convenciones. Por ejemplo:

  • make sin argumentos simplemente ejecuta la compilación del programa, sin instalarlo.

  • make install compila el programa (aunque no siempre), y asegura la instalación de los ficheros necesarios en el lugar adecuado del sistema de ficheros. Algunos ficheros no siempre se instalan correctamente (man, info), ellos deben ser copiados por el usuario. Algunas veces, make install tiene que volver a ser ejecutado en los subdirectorios. Por lo general, esto pasa con los módulos desarrollados por terceros.

  • make clean borra todos los ficheros temporales creados por la compilación, y, en la mayoría de los casos, el fichero ejecutable.

La primera etapa para compilar un programa es ingresar (ejemplo imaginario):

$ make
gcc -c glloq.c -o glloq.o
gcc -c init.c -o init.o
gcc -c main.c -o main.o
gcc -lgtk -lgdk -lglib -lXext -lX11 -lm glloq.o init.o main.o -o glloq

Excelente, el fichero binario está compilado correctamente. Ahora estamos preparados para la etapa siguiente, que es la instalación de los ficheros de la distribución (ficheros binarios, ficheros de datos, etc...) Consulte la sección “Instalación”.

Explicaciones

Si Usted es lo suficientemente curioso para mirar el fichero Makefile, encontrará comandos conocidos (rm, mv, cp, ...), aunque también encontrará algunas cadenas extrañas, de la forma $(CFLAGS).

Estas son variables, es decir las cadenas que generalmente se fijan al comienzo del fichero Makefile, y luego se reemplazan por el valor con el cual están asociadas. Esto es bastante útil cuando quiere usar las mismas opciones de compilación varias veces a la vez.

Por ejemplo, puede mostrar la cadena “pepe” en la pantalla usando make all:

TEST = pepe
all:
	echo $(TEST)

La mayoría de las veces, se definen las variables siguientes:

  1. CC: este es el compilador que va a utilizar. Generalmente es cc1, que en la mayoría de los sistemas libres, es sinónimo de gcc. Cuando tenga dudas, ponga aquí gcc.

  2. LD: este es el programa usado para asegurar la fase de la compilación final (consulte la sección “Las cuatro fases de la compilación”) El valor predeterminado es ld.

  3. CFLAGS: estos son los argumentos adicionales que se pasarán al compilador durante las primeras etapas de la compilación. Entre ellos:

    • -I<ruta>: le especifica al compilador donde buscar algunos ficheros de encabezado adicionales (por ejemplo: -I/usr/X11R6/include permite incluir los ficheros de encabezado que están en el directorio /usr/X11R6/include)

    • -D<símbolo>: define un símbolo adicional, útil para los programas cuya compilación depende de los símbolos definidos (ejemplo: utilizar el fichero string.h si está definida HAVE_STRING_H)

    Generalmente hay líneas de compilación de la forma:

    $(CC) $(CFLAGS) -c pepe.c -o pepe.o
  4. LDFLAGS (o LFLAGS): estos son los argumentos que se usan durante la última etapa de compilación. Entre ellos:

    • -L<ruta>: especifica una ruta adicional donde buscar bibliotecas (por ejemplo: -L/usr/X11R6/lib)

    • -l<biblioteca>: especifica una biblioteca adicional para usar durante la última etapa de compilación.

¿Qué pasa si... no funciona?

No tenga pánico, le puede pasar a cualquiera. Entre las causas más comunes:

  1. glloq.c:16: decl.h: No such file or directory (glloq.c :16: decl.h: no hay fichero o directorio con ese nombre)

    El compilador no pudo encontrar el fichero de encabezado correspondiente. Por lo tanto, la etapa de configuración del software debería haber anticipado este error. Cómo resolver este problema:

    • verifique que verdaderamente exista el fichero de encabezado en cuestión en uno de los directorios siguientes: /usr/include, /usr/local/include, /usr/X11R6/include o en alguno de sus subdirectorios. De no ser así, búsquelo por todo el disco (con find o locate), y, si todavía no lo encuentra, verifique que ha instalado la biblioteca de desarrollo correspondiente a este fichero de encabezado. Puede encontrar ejemplos de los comandos find y locate en las respectivas páginas Man.

    • Verifique que el fichero de encabezado se pueda leer (para verificarlo, puede ingresar less <ruta>/<fichero>.h)

    • Si es un directorio como /usr/local/include o como /usr/X11R6/include, Usted tiene que agregar, a veces, un argumento nuevo al compilador. Abra el fichero Makefile correspondiente (tenga cuidado de abrir el fichero correcto, los que se encuentran en el directorio donde falla la compilación[36]) con su editor de texto favorito (Emacs, Vi, etc) Busque la línea errónea, y agregue la cadena -I<ruta>, donde <ruta> es la ruta donde se puede encontrar el fichero de encabezado en cuestión, justo después de la llamada del compilador (gcc, o, a veces, $(CC)) Si no sabe donde agregar esta opción, agréguela al comienzo del fichero, después de CFLAGS=<algo> o después de CC=<algo>.

    • ejecute make de nuevo, y si todavía sigue sin funcionar, verifique que esta opción (ver el punto anterior) se agrega durante la compilación en la línea errónea.

    • si todavía sigue sin funcionar, pida ayuda al autor del software, a su gurú local, o a la comunidad de software libre para resolver su problema (consulte la sección “Soporte técnico”)

  2. glloq.c:28: `struct pepe' undeclared (first use this function) (glloq.c:28: “struct pepe” no está declarada (esta es la primera utilización en esta función))

    Las estructuras son tipos de datos especiales, que usan todos los programas. El sistema define un montón de ellas en los ficheros de encabezados. Eso significa que es muy probable que el problema sea la falta o el mal uso de un fichero de encabezado. El procedimiento correcto para resolver el problema es:

    • intente verificar si la estructura en cuestión es una estructura definida por el programa o por el sistema. Una solución es usar el comando grep para ver si la estructura está definida en alguno de los ficheros de encabezado.

      Por ejemplo, cuando Usted está en la raíz de la distribución:

      $ find . -name '*.h'| xargs grep 'struct pepe' | less

      Es posible que aparezcan muchas líneas en la pantalla (por ejemplo, cada vez que se define una función que use esta estructura) Elija, si existe, la línea donde se define la estructura mirando el fichero de encabezado obtenido por la utilización del comando grep.

      La definición de una estructura es:

      struct pepe {
          <contenido de la estructura pepe>
      };
      

      Verifique si ella corresponde a lo que Usted tiene. De ser así, eso significa que no se incluye el encabezado en el fichero .c erróneo. Hay dos soluciones:

      • agregar la línea #include "<nombre_de_fichero>.h" al comienzo del fichero .c erróneo.

      • o copiar y pegar la definición de la estructura al comienzo del fichero .c (esto no es de lo mejor, pero al menos por lo general, funciona)

    • si este no es el caso, haga lo mismo con los ficheros de encabezado del sistema (que, generalmente, se encuentran en los directorios siguientes: /usr/include, /usr/X11R6/include y /usr/local/include) Pero en este caso, use la línea #include <<nombre_de_fichero>.h>.

    • si todavía no existe esta estructura, intente encontrar en que biblioteca (es decir, conjunto de funciones agrupadas en un solo paquete) debería estar definida (ver en el fichero INSTALL o README cuales son las bibliotecas que usa este programa y las versiones necesarias) Si la versión que necesita el programa no está instalada en el sistema, Usted deberá actualizar esta biblioteca. Cabe destacar que debe tener sumo cuidado al manipular los ficheros de encabezado del sistema, ya que estos son comunes a muchos programas.

    • si todavía sigue sin funcionar, verifique que el programa funciona adecuadamente sobre su arquitectura (algunos programas todavía no han sido portados a todos los sistemas UNIX) Verifique también que ha configurado el programa correctamente (por ejemplo, cuando ejecutó configure) para su arquitectura.

  3. parse error (error de análisis sintáctico)

    Este es un problema que es relativamente complicado de resolver, porque generalmente es un error que aparece en cierta línea, pero después que el compilador lo encontró. A veces, es simplemente un tipo de datos que no está definido. Si Usted encuentra un mensaje de error del tipo:

    main.c:1: parse error before `glloq_t
    main.c:1: warning: data definition has no type or storage class
    

    entonces el problema es que el tipo glloq_t no está definido. La solución al problema es más o menos la misma que en el problema anterior.

    [Note]Nota

    puede haber un error del tipo parse error en las bibliotecas curses antiguas si la memoria no nos falla.

  4. no space left on device (no queda espacio en el dispositivo)

    Este problema es simple de resolver: no hay espacio suficiente en el disco para generar un fichero binario a partir del fichero fuente. La solución consiste en liberar espacio en la partición que contiene el directorio de instalación (borrar ficheros innecesarios, ficheros temporales, desinstalar programas que no use). Si descomprimió en /tmp, mejor hágalo en /usr/local/src que evita la saturación innecesaria de la partición /tmp. Verifique si hay ficheros core[37] en su disco. De ser así, elimínelos o haga que el usuario al cual pertenezcan los elimine.

  5. /usr/bin/ld: cannot open -lglloq: No such file or directory (/usr/bin/ld: no puedo abrir -lglloq: no hay fichero o directorio alguno con ese nombre).

    Esto significa claramente que el programa ld (usado por gcc durante la última etapa de la compilación) no puede encontrar una biblioteca. Para incluir una biblioteca, ld busca un fichero cuyo nombre está en los argumentos del tipo -l<biblioteca>. Este fichero es lib<biblioteca.so>. Si ld no puede encontrarlo, produce un mensaje de error. Para resolver el problema, siga los pasos que se indican a continuación:

    1. verifique que el fichero existe en el disco rígido usando el comando locate. Por lo general, las bibliotecas gráficas se encuentran en /usr/X11R6/lib. Por ejemplo:

      $ locate libglloq

      Si la búsqueda no tiene resultado, puede buscar con el comando find (ejemplo: find /usr -name "libglloq.so*") Si Usted no puede encontrar la biblioteca, entonces tendrá que instalarla.

    2. una vez que está localizada la biblioteca, verifique que ld puede accederla: el fichero que especifica donde encontrar estas bibliotecas es /etc/ld.so.conf. Agregue el directorio en cuestión al final del mismo y ejecute ldconfig. También puede agregar este directorio a la variable de entorno LD_LIBRARY_PATH. Por ejemplo, si el directorio a agregar es /usr/X11R6/lib, ingrese:

      $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6/lib

      (si su shell es bash)

    3. si todavía no funciona, verifique que el formato de la biblioteca en cuestión es un fichero ejecutable (o ELF) (con el comando file) Si esta es un vínculo simbólico, verifique que el vínculo es correcto y no apunta a un fichero inexistente (por ejemplo, con nm <lib>). Los permisos pueden ser erróneos (por ejemplo, Usted usa una cuenta que no es root y la biblioteca está protegida contra lectura).

  6. glloq.c(.text+0x34): undefined reference to `glloq_init' (glloq.c(.text+0x34): referencia indefinida al símbolo `glloq_init')

    Esto significa que no se resolvió un símbolo durante la última etapa de la compilación. Por lo general, este es un problema de biblioteca. Puede haber varias causas:

    • la primera cosa a hacer es saber si se supone que el símbolo esté presente en una biblioteca. Por ejemplo, si es un símbolo que comienza por gtk, pertenece a la biblioteca gtk. Si el nombre de la biblioteca es difícil de identificar (como por ejemplo, zorglub_gloubiboulga), se pueden listar los símbolos de una biblioteca con el comando nm. Por ejemplo,

      $ nm libglloq.so
      0000000000109df0 d glloq_message_func
      000000000010a984 b glloq_msg
      0000000000008a58 t glloq_nearest_pow
      0000000000109dd8 d glloq_free_list
      0000000000109cf8 d glloq_mem_chunk

      Agregar la opción -o a nm permite mostrar el nombre de la biblioteca en cada línea, lo cual facilita la búsqueda. Imaginemos que buscamos el símbolo bulgroz_max, una solución cruda es realizar una búsqueda del tipo:

      $ nm /usr/lib/lib*.so | grep bulgroz_max
      $ nm /usr/X11R6/lib/lib*.so | grep bulgroz_max
      $ nm /usr/local/lib/lib*.so | grep bulgroz_max
      /usr/local/lib/libfrobnicate.so:000000000004d848 T bulgroz_max

      ¡Formidable! El símbolo bulgroz_max está definido en la biblioteca zorglub (la letra mayúscula T se encuentra delante de su nombre) Entonces, Usted sólo tiene que agregar la cadena -lzorglub en la línea de compilación editando el fichero Makefile: agréguela al final de la línea donde se define la variable LDFLAGS o LFGLAGS (o, en el peor de los casos, CC), o en la línea correspondiente a la creación del fichero binario final.

    • la compilación está hecha con una versión de la biblioteca que no es la que permite el software. Lea el fichero README o INSTALL de la distribución para saber que versión de la biblioteca debe usar.

    • no todos los ficheros objeto de la distribución están vinculados correctamente. Falta, o no se menciona, el fichero donde está definida esta función. Ingrese nm -o *.o, para saber el nombre del fichero .o correspondiente y agréguelo en la línea de compilación si es que falta.

    • la función o variable en cuestión puede ser fantasiosa. Intente eliminarla: edite el fichero fuente en cuestión (el nombre del mismo se especifica al comienzo del mensaje de error) Esta es una solución desesperada cuya consecuencia ciertamente será un funcionamiento anárquico del software (error de segmentación en el arranque, etc.)

  7. Segmentation fault (core dumped) (Error de segmentación (se produjo un fichero core)).

    A veces, el compilador se cuelga lamentablemente y produce este mensaje de error. No tengo consejo alguno, salvo pedirle que instale una versión más reciente de su compilador.

  8. no queda espacio en /tmp

    La compilación necesita espacio temporal durante las diferentes etapas; si no tiene espacio suficiente, falla. Por lo tanto, debe limpiar la partición, pero debe tener cuidado ya que algunos programas en curso de ejecución (servidor X, tuberías...) se pueden colgar si se borran algunos ficheros. ¡Usted debe saber lo que está haciendo! Si tmp es parte de una partición que no la contiene solamente (por ejemplo, la raíz), busque y borre algunos ficheros core eventuales.

  9. make / configure en bucle infinito

    Generalmente, esto es un problema de la hora en su sistema. En efecto, make necesita saber la fecha y la hora de la computadora y de los ficheros que verifica. Este compara las fechas de los ficheros y usa el resultado para saber si el objetivo es más reciente que la dependencia.

    Algunos problemas en la fecha pueden inducir a make a reconstruirse a sí mismo indefinidamente (o a construir y reconstruir un subárbol en bucle) Si es así, el uso del comando touch (cuya consecuencia es poner en la hora corriente a los ficheros pasados como argumento) resuelve el problema la mayoría de las veces.

    Por ejemplo:

    $ touch *

    O también (más bruto, pero eficiente):

    $ find . | xargs touch


[36] Analice el mensaje de error que devuelve make. Normalmente, las últimas líneas deberían contener un directorio (un mensaje como make[1]: Leaving directory `/home/reina/Proyecto/pepe'). Elija aquel que tiene el número más grande. Para verificar que es el bueno, vaya al directorio y ejecute make de nuevo para obtener el mismo error.

[37] Fichero generado por el sistema cuando un proceso intenta acceder a una ubicación de memoria a la cual no tiene permiso para acceder. Estos archivos se utilizan para analizar la razón de tal comportamiento para corregir el problema.