viernes, 25 de noviembre de 2016

Examinando el árbol de código fuente

Desempaquetar el archivo tar da como resultado la creación de un nuevo directorio, llamado diction-1.11. Este directorio contiene el árbol de código fuente. Miremos dentro:

[me@linuxbox src]$ cd diction-1.11
[me@linuxbox diction-1.11]$ ls
config.guess diction.c       getopt.c     nl
config.h.in  diction.pot     getopt.h     nl.po
config.sub   diction.spec    getopt_int.h README
configure    diction.spec.in INSTALL      sentence.c
configure.in diction.texi.in install-sh   sentence.h
COPYING      en              Makefile.in  style.1.in
de           en_GB           misc.c       style.c
de.po        en_GB.po        misc.h       test
diction.1.in getopt1.c       NEWS

En él, vemos una cantidad de archivos. Los programas pertenecientes al Proyecto GNU, así como muchos otros, proporcionarán los archivos de documentación README, INSTALL, NEWS y COPYING. Estos archivos contienen la descripción del programa, información de cómo construirlo e instalarlo, y sus términos de licencia. Siempre es una buena idea leer los archivos README e INSTALL antes de intentar construir el programa.

Los otros archivos interesantes en este directorio son los que terminan en .c y .h:

[me@linuxbox diction-1.11]$ ls *.c
diction.c getopt1.c getopt.c misc.c sentence.c style.c
[me@linuxbox diction-1.11]$ ls *.h
getopt.h getopt_int.h misc.h sentence.h

Los archivos .c contienen los dos programas C proporcionados por el paquete (style y diction), divididos en módulos. Es una práctica común para programas grandes dividirlos en trozos más pequeños y fáciles de manejar. Los archivos de código fuente son de texto ordinario y pueden examinarse con less:

[me@linuxbox diction-1.11]$ less diction.c

Los archivos .h se conocen como archivos de cabecera (header files). Estos, también, son texto ordinario. Los archivos de cabecera contienen descripciones de las rutinas incluidas en un archivo de código fuente o biblioteca. Para que el compilador pueda conectar los módulos, debe recibir una descripción de los módulos necesarios para completar todo el programa. Al principio del archivo diction.c, vemos esta línea:

#include "getopt.h"

Esto ordena al compilador que lea el archivo getopt.h mientras lee el código fuente de diction.c para poder "saber" qué hay en getopt.c. El archivo getopt.c proporciona rutinas que son compartidas por los programas style y diction.

Encima de la declaración include de getopt.h, vemos otras declaraciones include como estas:

#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

Estas se refieren también a archivos de cabecera, pero se refieren a archivos de cabecera que se encuentran fuera del árbol de código fuente actual. Son proporcionados por el sistema para soportar la compilación de cada programa. Si miramos en /usr/include, podemos verlos:

[me@linuxbox diction-1.11]$ ls /usr/include

Los archivos de cabecera en este directorio se instalaron cuando instalamos el compilador.

miércoles, 23 de noviembre de 2016

Obteniendo el código fuente

Para nuestro ejercicio de compilación, vamos a compilar un programa del Proyecto GNU llamado diction. Es un pequeño pero práctico programa que comprueba la calidad de escritura y edición de los archivos de texto. Como programa, es bastante pequeño y fácil de construir.

Siguiendo la norma, primero vamos a crear un directorio para nuestro código fuente llamado src y luego descargaremos el código fuente en él usando ftp:

[me@linuxbox ~]$ mkdir src
[me@linuxbox ~]$ cd src
[me@linuxbox src]$ ftp ftp.gnu.org
Connected to ftp.gnu.org.
220 GNU FTP server ready.
Name (ftp.gnu.org:me): anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd gnu/diction
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r-- 1 1003 65534  68940 Aug 28 1998 diction-0.7.tar.gz
-rw-r--r-- 1 1003 65534  90957 Mar 04 2002 diction-1.02.tar.gz
-rw-r--r-- 1 1003 65534 141062 Sep 17 2007 diction-1.11.tar.gz
226 Directory send OK.
ftp> get diction-1.11.tar.gz
local: diction-1.11.tar.gz remote: diction-1.11.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for diction-1.11.tar.gz
(141062 bytes).
226 File send OK.
141062 bytes received in 0.16 secs (847.4 kB/s)
ftp> bye
221 Goodbye.
[me@linuxbox src]$ ls
diction-1.11.tar.gz

Nota: Como somos los "mantenedores" de este código fuente mientras lo compilamos, lo guardaremos en ~/src. El código fuente instalado por nuestra distribución se instalará en /usr/src, mientras que nuestro código fuente destinado al uso de múltiples usuarios se instala a menudo en /usr/local/src.

Como podemos ver, el código fuente se proporciona normalmente en forma de archivo tar comprimido. Algunas veces se llama tarball, este archivo contiene el source tree (árbol de código fuente), o jerarquía de directorios y archivos que componen el código fuente. Tras llegar al sitio ftp, examinamos la lista de archivos tar disponibles y seleccionamos la versión más reciente para descargar. Usando el comando get contenido en ftp, copiamos el archivo del servidor ftp a la máquina local.

Una vez que se ha descargado el archivo tar, tiene que ser desempaquetado. Esto se hace con el programa tar:

[me@linuxbox src]$ tar xzf diction-1.11.tar.gz
[me@linuxbox src]$ ls
diction-1.11        diction-1.11.tar.gz

Consejo: El programa diction, como todo el software del Proyecto GNU, sigue ciertos estándares para el empaquetado de código fuente. La mayoría del resto de código fuente disponible en el ecosistema Linux también sigue este estándar. Un elemento del estándar es que cuando el código fuente del archivo tar es desempaquetado, se creará un directorio que contiene el árbol de código fuente, y que este directorio se llamará project-x.xx, conteniendo así tanto el nombre del proyecto como el número de versión. Este esquema también permite una fácil instalación de múltiples versiones del mismo programa. Sin embargo, a menudo es una buena idea examinar la disposición del árbol antes de desempaquetarlo. Algunos proyectos no crearán el directorio, pero en su lugar colocarán los archivos directamente en el directorio actual. Esto provocará un desorden en tu, de otra forma, bien organizado directorio src. Para evitar esto, usa el siguiente comando para examinar el contenido del archivo tar:

tar tzvf archivotar | head

lunes, 21 de noviembre de 2016

Compilando un programa en C

Compilemos algo. Sin embargo, antes de hacerlo, vamos a necesitar algunas herramientas como el compilador, el enlazador y make. El compilador C usado casi universalmente en el entorno Linux se llama gcc (GNU C Compiler - Compilador GNU de C), escrito originalmente por Richard Stallman. La mayoría de las distribuciones no instalan gcc por defecto. Podemos comprobar si el compilador esta presente así:

[me@linuxbox ~]$ which gcc
/usr/bin/gcc

El resultado de este ejemplo indica que el compilador está instalado.

Consejo: Tu distribución puede tener un meta-paquete (una colección de paquetes) para el desarrollo de software. Si es así, considera instalarlo si quieres compilar programas en tu sistema. Si tu sistema no ofrece un meta-paquete, prueba a instalar los paquetes gcc y make. En muchas distribuciones, esto es suficiente para realizar el siguiente ejercicio.

viernes, 18 de noviembre de 2016

¿Todos los programas se compilan?

No. Como hemos visto, hay programas como los scripts de shell que no requieren compilación. Se ejecutan directamente. Están escritos en lo que se conoce como lenguajes de script o interpretados. Estos lenguajes han ganado popularidad en los últimos años e incluyen Perl, Python, PHP, Ruby y muchos otros.

Los lenguajes de script se ejecutan por un programa especial llamado intérprete. Un intérprete toma el archivo del programa y lee y ejecuta cada instrucción contenida dentro de él. En general, los programas interpretados se ejecutan mucho más lentamente que los programas compilados. Esto es porque cada instrucción de código en un programa interpretado se traduce cada vez que se ejecuta, mientras que en un programa compilado, una instrucción de código fuente se traduce sólo una vez, y esta traducción se graba permanentemente en el archivo ejecutable final.

Entonces ¿por qué son tan populares los programas interpretados? Para muchas tareas de programación, los resultados son "suficientemente rápidos", pero la ventaja real es que generalmente es más rápido y fácil desarrollar programas interpretados que programas compilados. Los programas se desarrollan a menudo en un ciclo repetitivo de código, compilación, prueba. A medida que un programa crece en tamaño, la fase de compilación del ciclo puede llegar a ser muy larga. Los lenguajes interpretados eliminan el paso de la compilación y por lo tanto aumentan la velocidad de desarrollo del programa.

miércoles, 16 de noviembre de 2016

¿Qué es compilar?

Digamos que, compilar es el proceso de traducir código fuente (la descripción legible por humanos de un programa escrito por un programador) al lenguaje nativo del procesador del ordenador.

El procesador del ordenador (o CPU) trabaja a un nivel muy elemental, ejecutando programas en lo que se llama lenguaje máquina. Este es un código numérico que describe operaciones muy pequeñas, como "añade este byte", "apunta a esta localización en la memoria" o "copia este byte."

Cada una de esas instrucciones se expresan en binario (unos y ceros). Los primeros programas de ordenador se escribieron usando este código numérico, que explicaría por qué los que los escribieron se dice que fumaban mucho, bebían litros de café y usaban gafas con cristales gordos.

El problema se solucionó con la llegada del lenguaje ensamblador, que reemplazaba los códigos numéricos con caracteres mnemotécnicos (ligeramente) más fáciles de usar como CPY (para copiar) y MOV (para mover). Los programas escritos en lenguaje ensamblador se procesan a lenguaje máquina por un programa llamado ensamblador. El lenguaje ensamblador aún se usa en la actualidad para ciertas tareas especializadas de programación, como controladores de dispositivos y sistemas embebidos.

A continuación llegamos a lo que se llama lenguajes de programación de alto nivel. Se llaman así porque permiten que el programador esté menos preocupado con los detalles de lo que está haciendo el procesador y más con resolver los problemas que tiene entre manos. Los primeros (desarrollados durante los años cincuenta) incluyen FORTRAN (diseñado para tareas científicas y técnicas) y COBOL (diseñado para aplicaciones comerciales). Ambos tienen un uso limitado en la actualidad.

Aunque hay muchos lenguajes de programación populares, dos predominan. La mayoría de programas escritos para sistemas modernos están escritos en C o C++. En los ejemplos que siguen, compilaremos un programa en C.

Los programas escritos en lenguajes de programación de alto nivel son convertidos a lenguaje máquina procesándolos en otro programa, llamado compilador. Algunos compiladores traducen las instrucciones de alto nivel en lenguaje ensamblador y luego usan un ensamblador para realizar el último paso de traducirlo a lenguaje máquina.

Un proceso usado a menudo junto con el compilado es el llamado enlazado. Hay muchas tareas comunes realizadas por programas. Tomemos, por ejemplo, abrir un archivo. Muchos programas realizan esta tarea, pero sería un despilfarro que cada programa implemente su propia rutina para abrir archivos. Tiene más sentido tener una única pieza de programación que sepa cómo abrir archivos y permitir a todos los programas que lo necesiten compartirla. Dar soporte a tareas comunes se logra mediante lo que se llaman bibliotecas. Contienen múltiples rutinas, cada una realiza alguna tarea común que puede ser compartida por múltiples programas. Si miramos en los directorios /lib y /usr/lib, podemos ver dónde están muchas de ellas. Un programa llamado enlazador se usa para realizar las conexiones entre la salida del compilador y las bibliotecas que el programa compilado requiere. El resultado final de este proceso es el archivo ejecutable del programa, listo para ser usado.

lunes, 14 de noviembre de 2016

Compilando programas

En este capítulo, veremos cómo construir programas compilando código fuente. La disponibilidad del código fuente es la libertad fundamental que hace que Linux sea posible. Todo el ecosistema de desarrollo Linux se basa en el libre intercambio entre desarrolladores. Para muchos usuarios de escritorio, compilar es un arte perdido. Solía ser bastante común, pero hoy en día, los proveedores de distribuciones mantienen amplios repositorios de binarios precompilados, listos para descargar y usar. En el momento de la escritura de este libro, el repositorio Debian (uno de los más grandes de todas las distribuciones) contiene casi 23.000 paquetes.

Entonces ¿por qué compilar software? Hay dos razones:
  1. Disponibilidad. A pesar del número de programas precompilados en los repositorios de las distribuciones, algunas distribuciones pueden no incluir todas las aplicaciones deseadas. En este caso, la única forma de obtener el programa deseado es compilarlo de su fuente.
  2. Puntualidad. Mientras que algunas distribuciones se especializan en las últimas versiones de los programas, muchas no lo hacen. Esto significa que para tener la última versión de un programa es necesario compilarlo.
Compilar software desde el código fuente puede llegar a ser muy complejo y técnico; mucho más allá del alcance de muchos usuarios. Sin embargo, muchas tareas de compilación son bastante fáciles y sólo necesitan unos pocos pasos. Todo depende del paquete. Veremos un caso muy simple para proporcionar una visión general del proceso y como punto de partida para aquellos que quieran emprender un estudio más a fondo.

Presentaremos un nuevo comando:
  • make - Utilidad para mantener programas

viernes, 11 de noviembre de 2016

lunes, 7 de noviembre de 2016

Resumiendo

En este capítulo, hemos visto cómo las impresoras del pasado han influido en el diseño de los sistemas de impresión de las máquinas tipo Unix, y cuánto control tenemos en la línea de comandos para controlar no sólo la programación y ejecución de trabajos de impresión, sino también la variedad de opciones de salida.

viernes, 4 de noviembre de 2016

lprm/cancel - Cancela trabajos de impresión

CUPS aporta dos programas usados para terminar trabajos de impresión y eliminarlos de la cola de impresión. Uno es estilo Berkeley (lprm) y el otro es System V (cancel). Difieren ligeramente en las opciones que soportan, pero básicamente hacen lo mismo. Usando nuestro trabajo de impresión anterior como ejemplo, podríamos parar el trabajo y eliminarlo de la siguiente forma:

[me@linuxbox ~]$ cancel 603
[me@linuxbox ~]$ lpq
printer is ready
no entries

Cada comando tiene opciones para eliminar todos los trabajos pertenecientes a un usuario en particular, una impresora en particular y múltiples números de trabajos. Sus respectivas man pages tienen todos los detalles.

miércoles, 2 de noviembre de 2016

lpq - Muestra el estado de la cola de impresión

Para ver el estado de una cola de impresión, se utiliza el programa lpq. Esto nos permite ver el estado de la cola y de los trabajos de impresión que contiene. Aquí tenemos un ejemplo de una cola vacía de una impresora por defecto del sistema llamada "printer":

[me@linuxbox ~]$ lpq
printer is ready
no entries

Si no especificamos una impresora (usando la opción -P), se muestra la impresora por defecto del sistema. Si enviamos un trabajo a la impresora y luego vemos la cola, lo veremos listado:

[me@linuxbox ~]$ ls *.txt | pr -3 | lp
request id is printer-603 (1 file(s))
[me@linuxbox ~]$ lpq
printer is ready and printing
Rank    Owner  Job  File(s)          Total Size
active  me     603  (stdin)          1024 bytes