lunes, 12 de noviembre de 2012

Integrando CMake con Eclipse CDT

Acostumbro a usar Eclipse para desarrollar en C++. Admito que se bebe la memoria (sobretodo cuando indexa el código), pero la funcionalidad que me da para navegar, buscar, autocompletar y depurar es impagable.

Ahora, la compilación deja un poco que desear. Para empezar, porque compilar un proyecto de Eclipse desde la linea de comandos no es tarea fácil. Para seguir, porque a veces se lía un poco con las dependencias y compila menos cosas de las que debiera. No mola nada que tu programa falle porque la mitad de los fuentes están compilados contra una versión de un fichero de cabecera distinta de la otra mitad. Lo digo por experiencia.

Así que la opción era pasarse a otro sistema de compilación, pero manteniendo la integración con Eclipse. Tras varias pruebas, el que más me convencía era CMake. Multiplataforma, código abierto, permite generar todos los ejecutables y librerías que quieras (y no solo uno por proyecto, como hace Eclipse) y gestiona el descubrimiento de las dependencias que te hagan falta. Bueno, y muchas más cosas. Yo, desde que lo uso, soy más feliz.

Sin embargo la integración con Eclipse no es inmediata. El mismo wiki de CMake propone varias opciones. La primera es generar el proyecto de Eclipse CDT con CMake, y la ponen como recomendada. Tiene varias desventajas conocidas. Yo además veo un par de choques de conceptos. Primero, los ficheros generados por CMake deberían ser transitorios, mientras que Eclipse espera que los ficheros de proyecto sean permanentes, como el código fuente. Segundo, CMake generará un fichero de proyecto por cada configuración (Debug, Release, RelWithDebInfo o MinSizeRel), mientras que Eclipse utiliza el mismo proyecto para todas las configuraciones.

La segunda opción, en la que me he basado, propone el camino contrario: usar un proyecto de tipo Standard Makefile que llame a CMake en el momento de compilar. En este tipo de proyecto, Eclipse asume que el usuario gestiona sus ficheros Makefile. En el wiki sugieren usar o bien una herramienta externa o bien make targets adicionales para llamar a CMake. Eso hace que la compilación pueda requerir un paso adicional por parte del usuario, así que he ido un poco más alla: utilizar un Makefile maestro que dependa de los Makefiles que genera CMake, y que por tanto le llame cuando sea necesario. Además, las reglas dependerán de la configuración usada por Eclipse y llamarán a CMake de manera consecuente. El Makefile es el siguiente:

CONFIG?=Debug

all: build/$(CONFIG)/Makefile
    $(MAKE) -C build/$(CONFIG)

build/$(CONFIG)/Makefile: build/$(CONFIG)
    cmake -E chdir build/$(CONFIG) cmake -G "Unix Makefiles" ../../ -DCMAKE_BUILD_TYPE:STRING=$(CONFIG)

build/$(CONFIG):
    mkdir -p build/$(CONFIG)

.PHONY: clean

clean:
    rm -fr build/$(CONFIG)
   
Comienza estableciendo la variable CONFIG, en caso de que no exista, a la configuración Debug. Luego vienen las tres reglas principales:
  1. Una regla que compila el código cuando el fichero build/$(CONFIG)/Makefile se haya generado.
  2. Una regla que genera ese fichero llamando a CMake desde el directorio build/$(CONFIG), si existe.
  3. Y una regla que crea ese directorio.
Finalmente está la regla que limpia la compilación anterior.

Fijaos que al llamar a CMake, se establece la variable CMAKE_BUILD_TYPE al mismo valor que CONFIG, para que compile el proyecto con los parámetros adecuados. Las alternativas, como he dicho antes, son Debug, Release, RelWithDebInfo y MinSizeRel. Así que hay hacer que Eclipse llame a make con el valor apropiado de la variable CONFIG. Es tan sencillo como ir a las propiedades del proyecto -> C/C++ Build -> Environment, y añadir una variable de entorno llamada CONFIG con el valor que queramos. Si le damos el valor ${ConfigName}, haremos que el nombre de la configuración de Eclipse coincida con la de CMake, y la jugada ya es redonda.

sábado, 10 de noviembre de 2012

Dual-boot y virtualización

Vaya, hacía ya tiempo que no escribía por aquí... pero nunca es tarde.

Llevo unos días lanzando unas simulaciones que corren en Linux, y que requieren tanto procesador como memoria abundantes. Y como recientemente me compré un equipo jugón en casa, había pensado en lanzar alguna ahí. Problema: equipo jugón == Windows (hasta que salga Steam para Linux...). Hasta ahora tenía una Debian virtualizada, que me iba muy bien para tareas de edición fotográfica, y podría haberla usado. Pero claro, así no puedo disponer totalmente de los cuatro núcleos y los 8 gigas de ram, así que mejor si Linux se ejecuta como anfitrión.

Total, que la idea era instalar Linux como arranque dual, pero poder seguir manteniendo la virtualización para ejecutarlo cómodamente desde Windows. ¿¿¿Es eso posible??? Pues sí, amiguitos. En pocas palabras, hay que crear una máquina virtual que utilice un disco físico como unidad virtual, en el que previamente hemos instalado Linux. Sin embargo, hay que tener en cuenta que el hardware que va a ver Linux como anfitrión no será el mismo que vea como virtualizado: discos duros, interfaces de red, tarjetas de sonido, tarjetas gráficas... Veamos el detalle.

 

Instalar Linux

He usado Windows 7, Debian GNU/Linux 7 (testing en este momento) y VMWare Player 9 para montar el tinglado. Tengo un disco SSD de sistema de 128 gigas, y un disco mecánico de datos de 1 tera.

En un principio, Windows ocupaba los dos discos, pero encoger las particiones para instalar Linux es bastante fácil. Vamos a Mi PC, botón derecho, Administrar, Administrador de discos, botón derecho en las particiones que queremos encoger y Reducir volumen. Podía haber ido a lo fácil y usar sólo una parte del disco de datos para Linux, pero ya que Windows disfruta de un arranque realmente rápido gracias al SSD, Linux no podía ser menos. Así que dejé una partición de 8 gigas en el SSD para la raíz de Linux y una de 50 gigas en el mecánico para el home. De sobra, ya que desde Linux no hay problema en montar y usar las otras particiones NTFS.

Y lo siguiente ya es instalar Debian. Yo siempre tiro de instalación por red. Te bajas una imagen de CD pequeña y luego sólo los paquetes que necesitas. Esta parte debería ser fácil, en principio, pero ayer tenía la negra: el instalador beta que viene con la distribución de pruebas tenía problemas para cargar los módulos del núcleo, así que sin red. Y claro, difícil hacer una instalación por red sin red... Así que usé el instalador de la distribución estable, con idea de actualizar a la de pruebas lo primero de todo. Total, que el instalador estable tenía problemas para conectar a la red también. Había que estar constantemente tirando y levantando de nuevo el interfaz de red para conseguir que descargara los paquetes. Pero bueno, esto no sería divertido si no terminara a las 4 de la mañana, ¿no?

 

Configuración del hardware

Como he dicho antes, hay que configurar Linux teniendo en cuenta que va a ver un hardware distinto dependiendo de si arranca como anfitrión o virtualizado. En general no habrá mayor problema: hoy en día, casi todo se configura al vuelo, con dispositivos extraibles y cosas así. Pero hay ciertos detalles que hay que tener en cuenta. En general, si hay que tomar alguna acción en tiempo de ejecución dependiendo de si el entorno es virtualizado o no, se puede usar un programa como vmware-checkvm (en el caso de VMWare) o imvirt (en cualquier caso). Ambos imprimen por la salida estándar una descripción del gestor de virtualización que se está usando. En caso no estar en un entorno virtualizado, vmware-checkvm devuelve un valor de retorno distinto de cero, e imvirt escribe "Physical" en la salida estándar.

 

Discos duros

He instalado Linux en la partición /dev/sda3, con el espacio de intercambio en /dev/sdb2 y el home en /dev/sdb3. ¿Seguirán llamándose así cuando arranque en virtualizado? Ni de coña. Pero Linux hace tiempo que resolvió este problema: UUIDs. En el fichero /etc/fstab, en lugar de especificar el dispositivo que se debe usar para cada sistema de ficheros, podemos identificarlos por UUID. De este modo es igual en qué dispositivo esté cada sistema de ficheros, siempre se montarán en el lugar que les corresponde.

Para conocer el UUID se usa el comando blkid:

# sudo blkid /dev/sdb3
/dev/sdb3: UUID="8d817db1-25a5-4ef1-a88e-ac47d60a3cf3" TYPE="ext4"

En el fichero fstab deberá aparecer como:

UUID=8d817db1-25a5-4ef1-a88e-ac47d60a3cf /home ext4 defaults 0 1

Debian testing hace esto de forma automática. Incluso utiliza el UUID en la linea de comandos del kernel para identificar el sistema de ficheros raíz. Sin embargo, en Debian estable hay que hacerlo a mano. Tenedlo en cuenta...

 

Interfaces de red

Hay que tener en cuenta que al virtualizar el Linux, va a aparecer como un sistema adicional conectado a la red, así que necesita una dirección IP propia. Con DHCP no hay problema. Tanto si configuráis la máquina virtual para que conecte con NAT como en modo bridged, el servidor de DHCP le dará una dirección sin usar. En mi caso, como estoy en un segmento con direccionamiento estático, tengo que asignarle una dirección que valga para ámbas situaciones. Básicamente hay que asignar una dirección distinta de la que tiene Windows y configurar la máquina virtual en modo bridged; en modo NAT no funciona sin DHCP. Fácil, ¿no?

Si vuestro ordenador está conectado a la red por cable, como es mi caso, Linux verá un interfaz de red eth0 tanto en virtualizado como en anfitrión. El fichero /etc/network/interfaces solo contendrá la configuración de ese interfaz. Si conectáis por wifi, lo más seguro es que en el Linux anfitrión os aparezca el interfaz wlan0 y en virtualizado eth0. Hay que poner la configuración de los dos en el fichero interfaces, y Linux ignorará la de aquel dispositivo que no exista en cada caso.

Una aclaración: yo esperaba que udev generara un nombre distinto para la interfaz de red real y para la virtual, porque tienen direcciones MAC distitnas. No fue así. Más fácil aún.

 

Tarjetas de sonido

Sin problemas. Linux usará la tarjeta que detecte en cada caso, bien la tarjeta física o bien la virtualizada. Posiblemente KDE (en mi caso) o Gnome se quejen de que aparecen y desaparecen dispositivos de audio cada vez que arrancáis Linux en un modo distinto. Simplemente les decís que no los eliminen de la lista y que no pregunten más.

 

Tarjetas gráficas

Aquí está la otra gracia: Es posible que necesites un fichero /etc/X11/xorg.conf según si Linux se ejecuta como anfitrión o virtualizado. Por ejemplo, si quieres usar los drivers propietarios (de NVidia, como es mi caso, o de cualquier otro) o seleccionar una disposición concreta de varias pantallas. En modo virtualizado el driver tiene que ser vmware.

La opción por la que he optado yo es guardar las dos configuraciones en el mismo fichero. Luego, crear un script que haga de wrapper para el servidor X, y que use una configuración distinta en función de lo que devuelva imvirt. La configuración puede ser algo así:

Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
EndSection

Section "Device"
    Identifier     "Device1"
    Driver         "vmware"
EndSection

Section "Screen"
    Identifier     "nvs"
    Device         "Device0"
    SubSection     "Display"
        Modes      "nvidia-auto-select"
    EndSubSection
EndSection

Section "Screen"
    Identifier     "vms"
    Device         "Device1"
EndSection


El wrapper, que se llama /usr/bin/Xvirt, tendría la siguiente pinta:

#!/bin/sh
if vmware-checkvm; then
    exec /usr/bin/X -screen vms "$@"
else
    exec /usr/bin/X -screen nvs "$@"
fi

Hay que conseguir que se ejecute en lugar del servidor de X. En el caso de kdm, en el fichero /etc/kde4/kdm/kdmrc hay una linea en la sección de opciones comunes a servidores locales llamada ServerCmd, que establece qué comando hay que ejecutar para iniciar el servidor. Simplemente establecemos ese valor a /usr/bin/Xvirt. Para un caso más general, también se puede renombrar /usr/bin/X por /usr/bin/_X y /usr/bin/Xvirt por /usr/bin/X.

 

Crear la máquina virtual

Una vez instalado Debian y visto que el ordenador arranca en modo dual (uso Grub 2, detalle importante más adelante), procedo a la creación de la máquina virtual. La clave está en seleccionar los discos duros que contienen el sistema Linux como discos virtuales en lugar de crear unos nuevos. En concreto, VMWare nos da la opción de hacer visibles sólo algunas de las particiones. Tener acceso a particiones que están montadas en el anfitrión es muy mala idea, podemos acabar con datos corruptos. Así, las particiones ocultas devuelven bloques de ceros al leer e ignoran las escrituras.

 

Arrancando

Total, que he añadido los dos discos físicos a la máquina virtual, dejando visibles sólo las particiones de Linux. Configuro la red en modo bridged, como he dicho antes, y arranco. En la bios de la máquina virtual selecciono el primer disco para arrancar, el que tiene Grub. ¿Y qué ocurre? Nada, Grub no arranca.

Se veía venir, mis discos son SATA y VMWare añade los discos físicos como si fueran IDE, así que algún problema iban a dar. La solución no es complicada: crear un pequeño disco virtual que contenga el sector de arranque con Grub, pero utilizando los mismos ficheros que el sistema instalado. El disco puede ser todo lo pequeño que queráis, 100 megas le he puesto yo, pero puede ser menos. Eso sí, tiene que caber una partición y un sistema de ficheros. Si no, Grub se quejará. Arrancamos la máquina virtual con el CD de instalación de Debian en modo recuperación. Creamos la partición en el disco virtual y la formateamos, como ext2, por ejemplo. Luego ejecutamos un shell en el entorno del sistema instalado. Nos aseguramos que en /boot/grub están los ficheros de Grub originales, y miramos qué dispositivo se corresponde con el nuevo disco virtual; supongamos que es /dev/sdc, pues ejecutamos:

# grub-install /dev/sdc

Este comando copiará el gestor de arranque en el nuevo disco virtual y recordará en qué disco están los ficheros con el menú y las siguientes etapas de arranque. Luego reiniciamos y en la bios de la máquian virtual seleccionamos el nuevo disco virtual como dispositivo de arranque. ¿Aparece el menú de Grub? ¡Perfecto!

Fijáos que el menú es el mismo que sale al arrancar el ordenador. Es decir, podéis seleccionar tanto el Linux como el Windows que se está ejecutando en ese momento como anfitrión. Y si intentáis virtualizar el mismo sitema anfitrión... Inception!! Noooooo, es broma, no pasa nada. Recordad que habéis ocultado todas las particiones que no pertenecían a Linux, así que no hay peligro. Porque las habéis ocultado, ¿¿¿VERDAD??? Si no, id preparandoos para reinstalar todo...

 

Compartición de archivos con el Windows anfitrión

Queda un último tema por aclarar: cómo acceder a los ficheros del Windows anfitrión. Cuando el Linux se ejecuta como anfitrión, se pueden montar las particiones NTFS; cuando se ejecuta virtualizado, no se puede. Entonces hay que usar las carpetas compartidas. VMWare tiene su propio sistema de carpetas compartidas, pero a mi me ha dado muchos problemas en el pasado, con ficheros que se corrompían y baja tasa de transferencia. En cambio, con las carpetas compartidas de Windows y un cliente Samba en Linux, funciona como la seda.

La idea es que, de un modo u otro, se monte cada partición siempre en el mismo sitio. Yo he elegido /mnt/c y /mnt/d para montar las unidades C: y D: que me aparecen en Windows. Montar la partición sólo funciona en modo anfitrión, montar el la carpeta compartida sólo funciona en modo virtualizado, así que voy a hacer una pequeña chapucilla: Añadir dos lineas al fichero /etc/fstab por cada punto de montaje, uno montando la partición y otro montando la carpeta compartida. Sólo una de las dos lineas funcionará.

Por ejemplo, para montar la partición de datos, D:, añado las siguientes dos lineas al fichero /etc/fstab:

UUID=8C949FE4949FCF58 /mnt/d ntfs defaults,uid=javi,gid=javi,umaks=066 0 0
 

//192.168.0.2/d /mnt/d cifs credentials=/etc/win.creds,uid=javi,gid=javi,rw,file_mode=0600,dir_mode=0700 0 0

Fijaos que hay que establecer quién será el propietario de los ficheros y los permisos por defecto, ya que ni ntfs ni cifs son sistemas de ficheros Posix. El fichero /etc/win.creds contiene el usuario y la contraseña con las que he compartido la unidad d en Windows.

Y fin.

viernes, 23 de marzo de 2007

Pegatinas Gratis!!!

De vez en cuando vale la pena escribir en el blog. Esta es una de esas veces. Y es que los chicos de Hacker Stickers van por la vida regalando pegatinas a quien les enlace. Pues nada, pegatina al canto para mi nuevo ThinkPad x60. De Debian, claro :D

sábado, 28 de octubre de 2006

¡Quemad esas calorías, chicas!

Se puede decir que llevo un buen inicio de curso. Aparte de la cosecha de éxitos académicos de septiembre, me estoy apuntando a hacer deporte a tutiplén. Este año quemamos esos kilitos de más seguro ;P.

Primero, porque sigo con el kendo. En el cursillo de verano me hicieron el exámen para cinturón naranja, así que con un poco de suerte y esfuerzo iremos a dos cinturones por año. Lo malo es que el cursillo fue a principios de Julio, y la falta de entrenamiento pasó factura el primer día. ¡Vaya machacada! Me dolían cosas que no sabía que podían doler... Lo siento por los nuevos, pero chico, todos hemos pasado por eso el primer día XDDDD.

Por otro lado, el otro día conocí a una asociación de patinadores de Zaragoza que se llama Patinar-Zaragoza. Suelen quedar martes y jueves y los fines de semana, así que me encaja perfecto con kendo. Patinar solo ya empezaba a hacerse aburrido, y ahora tengo la oportunidad de que otras personas me señalen qué posturas hago bien o mal. Tengo todos los vicios de alguien que ha aprendido a patinar sólo. Están bastante motivados y bien organizados, lo cual no se da muy a menudo.

En definitiva, que tengo una agenda bastante apretadilla. Ayer me tenían que recoger con pala, no sé si mis músculos soportarán tanta tensión. Siempre queda un consuelo:

No hay nada mejor que el culito de una patinadora.

viernes, 27 de octubre de 2006

Una razón tan buena como cualquier otra...

... para volver a escribir en el blog. Pero no prometo nada...

Escoge una banda/grupo favorito, y responde solo con títulos de sus canciones. Escoge 5 personas para que sigan el test, sin olvidar avisarles que han sido elegidos.

Cuestionario hecho por: Javi
Nominado por: Ardaleth
Banda o grupo elegido: Pondría Prodigy, pero será muy difícil, así que me quedo con U2

¿Eres hombre o mujer?: Elevation ;P
Descríbete: Even better than the real thing
Qué sienten las personas acerca de ti: Pride
Cómo describirías tu anterior relación sentimental: Hold me thrill me kiss me kill me
Describe tu actual relación con tu novio(a) o pretendiente: I still haven't found what I'm looking for
Dónde quisieras estar ahora: Where the streets have no name
Cómo eres respecto al amor: Electrical storm
Cómo es tu vida: A celebration
Qué pedirías si tuvieras un solo deseo: Another day
Escribe una cita o frase sabia: Sometimes you can't make it on your own
Ahora despídete: Walk on

Nominando a: Nit, Papaulita, Tete, Aitor y la indiscutible Daf (aunque no tenga blog)

lunes, 20 de marzo de 2006

En el fondo somos unos salidos...

No acostumbro a hacerlo, pero el otro día estaba yo viendo la tele, en concreto la serie Sin Rastro, y van dos agentes a interrogar a un camarero de un hotel que conseguía contactos entre los clientes del hotel y prostitutas, y va y les dice:

"Últimamente había mucha demanda, hay una convención de informáticos..."

Yo casi me deswebo XDDDDD.

domingo, 19 de febrero de 2006

Cinco manías

No suelo seguir esta moda de los memes, pero como me considero una persona especialmente rara para según que cosas pues he pensado que éste podría ser interesante.

1.- Hago un ruido extraño con la nariz, sobretodo cuando tengo inicio de moquita. Retengo un poco de aire por un momento y luego lo expulso rápidamente (¡es muy difícil de explicar con palabras!).

2.- Cuando sueño despierto gesticulo. Es un poco embarazoso porque suelo soñar despierto cuando voy solo por la calle, o en el autobús.

3.- Por las mañanas me lleno el tazón de leche casi hasta que rebosa. Y luego es especialmente difícil mojar las madalenas sin que se salga todo.

4.- Cuando camino por la calle (y no voy soñando despierto) evito pisar las líneas del suelo. Incluso trazo lineas imaginarias desde los objetos que me rodean, como árboles, columnas, papeleras, ... Así tiene más emoción :D.

5.- Con la informática también soy un poco maniático, claro. El código que no está bien indentado y espaciado no es buen código. Muerte a los que usan más de 4 espacios por tabulador, a los que no tabulan nada(eso sí que es una herejía), a los que no separan los operadores de los operandos, a los que no alinean los parámetros de una función cuando tienen que partirla en varias lineas, ...