jueves, 28 de abril de 2011

Compilar e instalar MonoDevelop y ASP.NET desde código fuente en Ubuntu y Debian. Otros aspectos de interés

En este artículo continuaremos con la instalación de Mono desde código fuente en Ubuntu y Debian, ahora enfocando el ambiente de desarrollo MonoDevelop y ASP.NET. Posteriormente, veremos algunos aspectos de configuración que nos permitirán trabajar de forma cómoda con aplicaciones de Mono y hablaremos un poco sobre la portabilidad y compatibilidad de marcos de trabajo y aplicaciones.
Prerrequisitos
Vimos en el artículo anterior una descripción de las bibliotecas principales y paquetes de Mono, además de los vínculos desde donde pueden descargarse. Recomendamos, para realizar una instalación minimal, la descarga de los siguientes paquetes:
Por supuesto, antes de compilar debemos tener correctamente instalado Mono, versión 2.6.7 o superior, además de los prerrequisitos vistos en el artículo anterior. Para que cuando se configure la compilación no se produzcan errores en las dependencias de librerías de desarrollo, debemos ejecutar la siguiente línea desde bash:
sudo aptitude install xulrunner-dev libgtk2.0-dev libglade2-dev \
libgnome2-dev libgnomecanvas2-dev libgnomeui-dev librsvg2-dev \
libgtksourceview2.0-dev libgtkhtml3.14-dev libvte-dev \
libpanel-applet2-dev libwebkit-dev libwnck-dev apache2-threaded-dev
Tampoco debemos olvidar que, para el caso de ASP.NET, es necesario el servidor web Apache2:
sudo aptitude install apache2
Compruebe que la variable PKG_CONFIG_PATH incluye el directorio donde está la configuración de paquetes del último Mono instalado, por ejemplo /opt/mono/lib/pkgconfig, si no, incluya en .bashrc la línea siguiente:
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/opt/mono/lib/pkgconfig
Configuración, compilación e instalación
Los pasos ya los conocemos, normalmente no llevan variaciones, y deben realizarse en los correspondientes directorios después de descompactar los paquetes de código fuente. Ahora, el orden sí es importante, ya que, por ejemplo, el paquete monodevelop-2.4.2 depende de mono-addins-0.5. El orden ya lo definimos en el epígrafe de Prerrequisitos. Y como memento, esto es lo que debemos ejecutar:
./configure --prefix=/opt/mono
make -j 4
sudo make install
Es posible que alguno de los paquetes produzca algún error en la compilación. No se asuste, eso sucede en las mejores familias. He aquí un listado de los errores más comunes:
  • Faltan dependencian. Se produce a veces cuando se utiliza la opción -j n en el primer make.
    Solución: Ejecute make sin la opción mencionada.
  • Error, no encuentra el ensamblado Mono.GetOptions. Por lo general, se produce en códigos de pruebas o ejemplos que utilizan versiones más antiguas de Mono.
    Solución: Debe localizarse el archivo para la compilación automática, Makefile, en el directorio donde está el archivo .cs que provocó el error. Dentro de Makefile, buscar el nombre del fichero que dio problemas, y comentar consecuentemente con # las líneas en las que aparezca. Por último, vuelva a ejecutar make.
  • Error en PrintSample.cs. Este es un archivo de pruebas que utiliza una API vieja.
    Solución: Localice el archivo y comente todo el código con /* y */.
Así luce MonoDevelop:

Configuración de mod_mono
mod_mono es el paquete de código fuente que genera el módulo de Apache mod_mono.mod, el cual se ejecuta cuando los sitios web se marcan como manejados por Mono. Una vez compilado e instalado, se coloca en el directorio /etc/apache2 un archivo mod_mono.conf, que contiene la configuración básica para las aplicaciones ASP.NET, carga el módulo y registra las extensiones de los archivos a manejar. Para estar a tono con el modo en que se configura Apache en Ubuntu o Debian,  podemos ejecutar este pequeño script, que registrará automáticamente el módulo:
sudo mv /etc/apache2/mod_mono.conf /etc/apache2/mods-available
sudo ln -s /etc/apache2/mods-available/mod_mono.conf \
  /etc/apache2/mods-enabled/mod_mono.conf
sudo /etc/init.d/apache2 restart
Luego, en el archivo /etc/apache2/httpd.conf podemos registrar tantos sitios de ASP.NET como queramos usando un fragmento similar al siguiente:
Alias /demo "/opt/mono/lib/xsp/test"
AddMonoApplications "/demo:/opt/mono/lib/xsp/test"
<Location /demo>
         SetHandler mono
</Location>
En este caso, hemos registrado un sitio de ejemplos de ASP.NET que viene con XSP una vez que este último se ha instalado. En el sitio de Mono, hay una página dedicada a la configuración de mod_mono que ofrece muchos más detalles.

Ejecutar aplicaciones de Mono como archivos ejecutables
Primeramente, debemos colocar un archivo run_mono.sh como el siguiente en /etc/rc.local:
#!/bin/bash
/usr/sbin/update-binfmts --disable cli
/usr/sbin/update-binfmts --disable CLR
if [ ! -e /proc/sys/fs/binfmt_misc/register ]; then
        /sbin/modprobe binfmt_misc
        mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
fi

if [ -e /proc/sys/fs/binfmt_misc/register ]; then
        echo ':CLR:M::MZ::/opt/mono/bin/mono:' \
             > /proc/sys/fs/binfmt_misc/register
else
        echo "No binfmt_misc support"
        exit 1
fi
Después comprobamos, como se indica a continuación, que el enlace suave /etc/alternatives/cli apunta a la última aplicación mono instalada:
ls -l /etc/alternatives/cli
lrwxrwxrwx 1 root root 13 2010-11-19 07:58 /etc/alternatives/cli 
  -> /opt/mono/bin/mono
Si no es así, ejecutamos lo siguiente:
sudo ln -s /opt/mono/bin/mono /etc/alternatives/cli
Por último, cambiamos los permisos de la aplicación Mono para permitir la ejecución y la corremos:
chmod a+x App.exe
./App.exe
Portabilidad y compatibilidad
Para comprobar que un ensamblado compilado con Microsoft .NET Framework es compatible con Mono, determinando en qué estado de implementación se hallan las dependencias, puede usarse la herramienta Mono Migration Analyzer MoMA. También en http://go-mono.com/status/ podemos encontrar de manera exhaustiva e intuitiva el estado en la implementación de las clases de la BCL.

Estas son algunas de las bibliotecas que he comprobado que funcionan:

martes, 19 de abril de 2011

Compilar e instalar Mono desde código fuente en Ubuntu y Debian

Introducción
Mono es la alternativa libre y de código abierto del marco de trabajo .NET de Microsoft, una iniciativa de Miguel de Icaza conjuntamente con la empresa Novell, la creadora de la distribución Suse Linux. Su sitio web oficial es http://www.mono-project.com, en el cual se puede encontrar información general, descargas, tutoriales, documentación e intercambiar con la activa comunidad.
En este artículo se abordará el tema de la instalación de Mono a partir del código fuente en Ubuntu o Debian y antes de comenzar, debemos aclarar algunos aspectos particulares:
  • Este tutorial se probó con la versión 2.10 de Mono, aunque también puede aplicarse para versiones posteriores a la 2.6.7. 
  • En mi grupo de desarrollo trabajamos además de Windows con las distribuciones Ubuntu (área de desarrollo) y Debian (área de producción) para abaratar los costos de los servidores de aplicaciones, además de que ofrecen alta disponibilidad, eficiencia y flexibilidad de configuración, mantenimiento, despliegue y compatibilidad. Esto, con el valor agregado de que son sistemas bajo la GPL.
  • Aunque los repositorios oficiales de las distribuciones Debian y Ubuntu contienen la última versión con soporte de larga duración (LTS) de Mono (2.6.7 en la actualidad), siempre preferimos usar la última versión liberada, de manera que podamos aprovechar las últimas tecnologías incorporadas y las correcciones de bugs que se realizan con cada release.
Cómo obtener el código fuente de Mono
Para obtener la última versión estable de Mono puede accederse al sitio http://ftp.novell.com/pub/mono/sources/. Las páginas tienen vínculos al estilo FTP y existen más de 50 carpetas con proyectos relacionados con Mono. A continuación veremos una breve descripción de los principales:
Carpeta Descripción
libgdiplus/ Librería nativa que funciona como wrapper del GDI+ de Windows.
mono/ Marco de trabajo Mono, que incluye las librerías nativas del CLR, aplicaciones básicas del framework, más la Base Class Library (BCL) junto a varias librerías de clases específicas de Mono.
mono-debugger/ Debugger de Mono.
mono-basic/ Extensión de Mono para el soporte de proyectos Visual Basic .NET.
monodevelop/ IDE similar a Visual Studio para desarrollo de aplicaciones Mono.
monodevelop-database/ Extensión para conectarse a varios tipos de base de datos desde MonoDevelop.
monodevelop-debugger-gdb/ Debugger para MonoDevelop versión GNU que genera archivos gdb con información de depuración.
monodevelop-debugger-mdb/ Debugger para MonoDevelop que genera archivos MDB (Managed Debugging Engine) de Visual Studio.
monodoc/ Documentación de Mono.
mono-tools/ Herramientas comunes de desarrollo y pruebas para Mono.
mod_mono/ Módulo de Apache2 para el hospedaje de aplicaciones ASP.NET.
ikvm/ Puerto de Mono para aplicaciones que interactúan con el byte code de Java.
gtk-sharp/ Wrapper de las librerías del GTK para Mono.
gnome-sharp2/ Wrapper de las librerías de Gnome para Mono.
gnome-desktop-sharp2/ Wrapper de las librerías del escritorio Gnome para Mono.
gluezilla/ Puerto para Mono de las librerías de Mozilla.
gtksourceview-sharp-2.0/ Wrapper de las librerías de GTK para la visualización de código fuente.
monodevelop-java/  Add-in de MonoDevelop para proyectos de Java.
monodevelop-python/  Add-in de MonoDevelop para proyectos de Python.
webkit-sharp/ Librerías con herramientas de internet para Mono.
xsp/ Servidor web para desarrollo que permite hospedar aplicaciones ASP.NET.
moon/ Librerías y binarios de MoonLight, versión libre de Silverlight.
Cada carpeta contiene los paquetes de código fuente como archivos compactados (generalmente de extensión .tar.bz2) con el número de la versión. Una vez descargados, se pueden descompactar desde bash con la línea siguiente:
tar -xvf nombreDeArchivo.tar.bz2
Prerrequisitos para la compilación
Antes de comenzar los procesos de compilación, debemos instalar los paquetes de desarrollo que constituyen requerimientos y que normalmente están incluidos en los repositorios. Para ello, podemos ejecutar el siguiente comando desde una terminal bash:
sudo aptitude install build-essential libglib2.0-dev libtiff4-dev \
libgif-dev libpng12-dev libx11-dev libcairo-dev bison gettext
Crearemos el directorio mono dentro la carpeta /opt, la cual se usa normalmente para instalar software que no procede del repositorio. Esto nos traerá dos ventajas:
  1. La instalación posterior a la compilación se hará completamente dentro del directorio,  lo cual nos permitirá copiarla a cualquier otra máquina para usarla sin necesidad de recompilar.
  2. Podrán convivir varias versiones de Mono, por ejemplo, la 2.6.7 instalada por defecto desde Ubuntu 9.04, y la que compilaremos.
Para crear el directorio podemos hacerlo así:
sudo mkdir /opt/mono
Compilación básica de Mono
Mono requiere de la librería nativa libgdiplus.so para funcionar, fundamentalmente porque es la que usa el ensamblado System.Drawing.dll, por tanto la debemos compilar primero. A continuación, podemos repetir el mismo procedimiento para el código de Mono.
Tres procesos secuenciales definen la compilación.
Configuración
Dentro de las carpetas de los paquetes de código fuente descompactados, se encuentra un archivo con permiso de ejecución denominado configure. A través de él, se realiza la configuración y verificación de los prerrequisitos de manera automática. Aunque su empleo más simple es:
./configure
no usaremos esta alternativa, pues creará las condiciones para que la instalación se realice por defecto en el directorio /usr/local, que no es el que creamos para esos fines. En cambio, utilizaremos la siguiente alternativa, que sí realiza la configuración deseada:
./configure --prefix=/opt/mono
La configuración verifica cada una de las versiones de los encabezados C/C++ que existen en el sistema, comprueba los paquetes instalados y se detiene en caso de algún error o ausencia de algún prerrequisito. Es posible que los mensajes de error no sean muy descriptivos, por lo que incorporamos con anterioridad un epígrafe de prerrequisitos. Además, prepara la compilación e instalación para que se realicen con las opciones especificadas. Puede hacerse lo siguiente para ver una ayuda completa de las opciones de configuración:
./configure --help
Compilación
La compilación se realiza mediante la herramienta make, que se instala con el paquete build-essential. Este último también contiene los compiladores de C (gcc) y C++ (g++) que son utilizados por make para realizar compilaciones consecutivas y diferenciadas. make ofrece la opción -j n la cual usaremos para indicar que la compilación se hará con el máximo uso del CPU (si la computadora tiene procesador Dual Core, Core 2 Duo, Quad Core, etc. será mucho más rápido); en este caso, n indica la cantidad de jobs o procesos paralelos que realizarán la compilación.
El comando para compilar tanto el CLR (código C/C++) como la BCL (código C#), puede ser entonces:
make -j 4
Esto puede demorar, así que sin pena puede levantarse de su asiento, estirarse, tomarse un café o ir al baño. Le aseguro que sin la opción -j podría tranquilamente resolver un Sudoku de dificultad media. Esto me recuerda la primera vez que compilé un código fuente en Linux: se trataba del emulador de Super Nintendo ZSNES, en cuyo README, al final, tenía un mensaje de aliento algo así: "type make, then return, cross your fingers and start praying" (teclee make, luego enter, cruce sus dedos y comience a rezar).
Instalación
Una vez que compruebe que la compilación no terminó con un mensaje en rojo con alguna excepción .NET o un error precedido de varios asteriscos (en cuyo caso tendrá que arreglárselas googleando o con sus propios conocimientos), puede ejecutar el comando para instalar:
sudo make install
La ejecución de este es mucho más rápida y el resultado lo podrá ver dentro de la carpeta /opt/mono, que contendrá las siguientes subcarpetas:
  • bin: Archivos binarios y ejecutables de Mono, como el intérprete mono o el compilador de C# gmcs.
  • lib: Librerías nativas y ensamblados, junto con la Global Assembly Cache (GAC).
  • share: Documentación básica.
  • include: Encabezados de C/C++ para el trabajo con librerías nativas del CLR.
  • etc: Archivos de configuración.
¿Es todo?
No. Falta reconfigurar la caché de librerías nativas, especificar convenientemente las variables de entorno y probar que el intérprete funciona. El primer paso lo logramos ejecutando como root lo siguiente en bash:
echo /opt/mono/lib >/etc/ld.so.conf.d/mono.conf
ldconfig
El primer comando crea el archivo mono.conf en el directorio /etc/ld.so.conf.d/ con el texto "/opt/mono/lib", que es el directorio donde se encuentran las librerías nativas de Mono. El segundo comando actualiza la caché de librerías nativas del sistema, de manera que cuando alguna se solicite, se pueda encontrar sin problemas.
Luego, incluimos las siguientes líneas en el archivo .bashrc de nuestra carpeta home o base :
export PATH=/opt/mono/bin:$PATH
export MONO_GAC_PREFIX=/opt/mono/lib/mono/gac:$MONO_GAC_PREFIX
Incluimos el camino /opt/mono/bin en la variable de entorno PATH para poder ejecutar el intérprete mono directamente. También agregamos el nuevo directorio base del GAC a través de la variable MONO_GAC_PREFIX para que las aplicaciones ejecuten con las últimas versiones de los ensamblados. Por último creamos un archivo HelloWorld.cs con el código siguiente:
using System;
namespace HelloWorld {
 public class MainClass {
  public static void Main (string[] args) {
   Console.WriteLine("Hello world!");
  }
 }
}
ejecutamos el comando para compilar:
gmcs -r:System.dll -out:HelloWorld.exe HelloWorld.cs
Finalmente ejecutamos:
mono HelloWorld.exe
y obtendremos un amistoso "Hello world!" en la consola.
En otro artículo veremos cómo instalar desde código y configurar MonoDevelop y ASP.NET, así como ejecutar las aplicaciones de Mono sin usar el intérprete y otros aspectos importantes o interesantes.

jueves, 14 de abril de 2011

Un clúster de Oracle es más que una base de datos

Imaginemos que tenemos una tabla de un esquema de Oracle (o base de datos en cualquier otro SGBD) a la que dos instancias P1 y P2 de una aplicación acceden simultáneamente, pero queremos que las filas que se procesen en P1, no se procesen en P2, y viceversa. Un mecanismo válido para evitar la repetición es mediante el bloqueo de filas, ya sea a través de una tabla auxiliar o de una columna especial en la tabla original. Nos concentraremos en el primer caso.
Tenemos la tabla A con llave primaria A1 y tabla LOCK_A con llave primaria LOCK_A1 del mismo tipo que A1. Además, LOCK_A contará con una columna de tipo fecha/hora (DATE o TIMESTAMP, por ejemplo) llamada LAST_DATE. Se bloqueará una cantidad N de filas, pues los datos serán procesados por lotes. La tabla R contendrá las filas de A que se procesarán.
  1. Obtenemos un cursor resultado de la consulta:
    SELECT A1 FROM A WHERE A1 NOT IN (SELECT LOCK_A1 FROM LOCK_A)
  2. Comenzamos un ciclo que recorre cada fila del cursor.
  3. Comenzamos una transacción. BEGIN
  4. Con la fila actual, insertamos A1 en la columna LOCK_A1 en LOCK_A, más la fecha y hora actual (SYSDATE).
  5. Confirmamos la transacción. COMMIT
  6. Si no se produjo un error (llave primaria violada), guardamos la fila en R.
  7. Terminamos la transacción.
  8. Devolver R.
Pero también necesitamos que si ha pasado un tiempo dado, las filas se desbloqueen, por si falló alguna de las aplicaciones y otra las pueda procesar. Para ello, antes de bloquearlas, ejecutamos un comando similar al siguiente:
DELETE FROM LOCK_A WHERE SYSDATE - LAST_DATE > TIMEOUT
En este caso, TIMEOUT es un parámetro numérico (ver aritmética de fechas en Oracle).
Dos cosas a tener en cuenta:
  • LOCK_A debe tener activada la restricción (constraint) de llave primaria sobre la columna LOCK_A1, para que en caso de insertar la fila con una llave existente se produzca un error.
  • Notar en el paso 5, COMMIT deberá hacerse justo después de INSERT, pues si se hace al final del ciclo, puede que alguna de las inserciones provoque un error que impida que las demás se puedan realizar.
Visto así, todo debería funcionar correctamente. Pues no. Puede suceder que las aplicaciones procesen las mismas filas.
¿Cómo? Si la instancia de Oracle está configurada en clúster, tenemos más de una computadora que gestiona los comandos sobre la base de datos. Si, por casualidad, un nodo del clúster tiene una fecha u hora distinta a los otros nodos, o está en una zona horaria diferente, SYSDATE dará fechas diferentes según el nodo que procese la solicitud de Oracle. Por lo que una operación como SYSDATE - LAST_DATE u otra semejante puede dar números alterados, hasta valores negativos, algo que en el sentido común puede parecer imposible. Este ligero cambio, bastante difícil de detectar, puede provocar que las filas se desbloqueen en menos o más tiempo del esperado.
Solución:
  • Mantenga siempre las computadoras de un ambiente distribuido con la configuración de hora, fecha y zona horaria sincronizada. 
  • Cree una herramienta para determinar automáticamente que todas las condiciones estén creadas para que su sistema funcione con eficacia.

Cada artículo tendrá clasificación y etiquetas

En el blog optaré por clasificar los artículos en tres categorías principales:
  • Up (Arriba) : Artículos sobre logros, retos rebasados y creaciones interesantes.
  • Down (Abajo) : Artículos sobre reveses, corrección de errores y experiencias negativas que han servido para coleccionar aspectos que no deben faltar en soluciones integrales, eficaces y eficientes.
  • Go (Ir) : Artículos sobre novedades, noticias o de carácter tutorial o informativo.
 Cada artículo tendrá otras categorías o etiquetas, como:
  • Temáticas
  • Tecnologías
  • Autores
  • Sitios
Las categorías o etiquetas aparecen en el panel derecho del blog, además de los artículos publicados por año, mes y día.

Up, down, go!

Hay momentos en los que estamos "arriba", todo está bien, todo funciona. Otros momentos nos recuerdan cuán equivocados podemos estar, cuán lejos de la realidad nos hallamos, por lo que quedamos "abajo". Pero si realmente valoramos nuestro esfuerzo, nuestra capacidad para crecer y superarnos, entonces continuamos, seguimos, avanzamos. Es una cadena de eventos que se suceden uno tras de otro, o incluso a veces simultáneamente, y nos lleva de un estado superior a uno inferior o viceversa. No se detiene, por lo que a veces es difícil mantener el ritmo y recepcionar cada evento. Unos se derrumban en el camino, tienden a claudicar fácilmente y dejarse llevar por la corriente. Otros, desafían los abismos y las cumbres, nunca se detienen a esperar lo que vendrá después.
En este blog pretendo acercarme de manera muy particular a algunos de esos sucesos en la programación y las tecnologías en los que me vea involucrado o perciba a mi alrededor, para transmitir las experiencias por si a otros sirven. No se tratará de un fórum de discusión, sino más bien de un punto de referencia.
Quiero dedicar el estreno de Up, down, go! a Sain Salazar Martínez, quien en el día de ayer falleció víctima de leucemia. Contaba apenas con 30 años. Fue querido, admirado y respetado en su colectivo de trabajo. Me considero muy afortunado de haber estado bajo su guía en el grupo de desarrollo, de haber compartido con él varias veces en las buenas y las malas y, sobre todo, de haber sido su amigo. 
¡Hasta siempre!