11 VirtualBox y CodeLite

11.1 ¿Por qué una máquina virtual?

La máquina virtual se utiliza para tener un entorno homogéneo de programación, tanto por parte de los estudiantes como por parte de los consultores, de forma que cualquier enunciado/solución publicado en las aulas de teoría funcione para todos los estudiantes, y que todos los programas que realice se comporten igual en los entornos que se utilizarán para corregirlos.

Hace unos semestres nos encontramos con unos pocos casos en los que un programa que funcionaba correctamente en el PC de un estudiante fallaba a la hora de ser corregido. Y también algunos enunciados que en determinados sistemas operativos/versiones de compiladores C tampoco funcionaban correctamente. Por este motivo se decidió utilizar una máquina virtual.

Los profesores no tenemos forma de controlar que realmente utilicéis la FP20222 o bien un CodeLite instalado directamente en vuestro PC, pero si no es así se puede dar alguna situación comentada y nada deseable.

11.2 VirtualBox: requerimientos

Para poder utilizar VirtualBox es necesario que disponga de acceso a la opción de virtualización. Si no es así, se pueden obtener errores del tipo: VT-X está deshabilitado en el BIOS para todos los CPUs.

El error se puede producir por varias razones:

  • La BIOS del PC tiene deshabilitada la opción. Para solucionarlo, hay que entrar dentro de la BIOS del PC y encontrar la opción de activación de la virtualización (varía según el fabricante): puede ser VT-x, Virtualization Technology, VTX/AMD-V, Intel Virtual Technology, Tecnología de virtualización (VTX/VTD), etc.
  • Tenemos activo un antivirus que tiene activada una virtualización propia que entra en conflicto con la requerida para VirtualBox. En este caso, únicamente hay que desactivar la opción de virtualización del antivirus.

11.3 Cómo instalar las Guest Additions

Las Guest Additions son una serie de drivers que mejoran la interacción entre host y máquina virtual. Para instalarlas únicamente hay que hacer:

  1. Poner en marcha la máquina virtual FP20222
  2. Ir a la barra de menú superior -> VirtualBox -> Devices -> Insert Guest Additions CD Image … -> instalará una unidad de CD con las Guest Additions.
  3. Abrir un terminal desde Lubuntu -> System Tools -> LXTerminal.
  4. Dentro del terminal LXTerminal ejecutar el siguiente (la versión que se esté instalando puede ser más nueva que la 6.0.12):
cd /media/uoc/VBox_GAs_6.0.12/     
sudo sh ./VBoxLinuxAdditions.run
  1. Reiniciar la FP20222 para activar las Guest Additions.

11.4 Primeros pasos con CodeLite

En las xWiki encontraréis el módulo Introducción al entorno de programación CodeLite, en el que se detallan los pasos que hay que realizar para preparar el entorno.

A continuación se resumen una serie de aspectos que se comentan en la xWiki y que son importantes de recordar:

  • Un workspace de CodeLite es una agrupación de proyectos.
  • Únicamente se puede tener un workspace abierto dentro de CodeLite.
  • Para crear un workspace: CodeLite -> Workspace -> New Workspace … -> Workspace type: C ++ -> Workspace name: el que corresponda; Workspace Path: /home/uoc/Documentos/codelite/workspaces/ (o cualquier otro) -> fin.
  • Como no se puede tener más de un workspace abierto, no podréis crear ninguno nuevo si previamente no cerráis el workspace activo. Si dentro del menú de CodeLite véis la opción New Workspace en gris y que no se puede seleccionar, significa que ya tiene un workspace abierto. Para cerrarlo: CodeLite -> Workspace -> Close Workspace.
  • Para añadir un proyecto a un workspace: CodeLite -> File -> New -> New Project -> de tipo Console: Simple ejecutable (gcc)-> Project name: el que corresponda -> Compiler: gnu gcc; Debugger: GNU gdb debugger -> fin.
  • El proyecto que acabamos de crear contiene un programa hello world de muestra, que si ejecutamos muestra el mensaje “hello world” por pantalla. Este programa en C lo podemos editar y añadir/quitar lo que queramos. Es aquí dentro donde debemos codificar nuestros programas en C (¡no los algoritmos!).
  • Si tenemos más de un proyecto dentro de un workspace, la forma que tenemos para indicar cuál de ellos es el que está activo es haciendo doble clic sobre el nombre del proyecto. Veréis que el nombre queda remarcado en negrita y cursiva: a partir de este momento, este será el proyecto que compilaremos y ejecutaremos desde las opciones del menú de CodeLite. Aunque estemos visualizando en pantalla el código de otro proyecto, la compilación y ejecución siempre se hará del proyecto activo.
  • Para mostrar la barra de herramientas (iconos) en la parte superior: CodeLite -> View -> Show toolbar.
  • El icono del play de color verde hacia la derecha de la barra de herramientas es el debugger, y no sirve para compilar.
  • Para compilar y ejecutar podemos hacer: CodeLite -> Build -> Build and run project. También se puede compilar con el icono de la barra de herramientas de la flecha blanca abajo con fondo verde, y ejecutar con el icono de las ruedas dentadas grises.
  • El resultado de la ejecución del programa se mostrará en una pantalla nueva tipo terminal. Es importante ir cerrando estas ventanas una vez que ya hayamos comprobado el resultado de la ejecución.

11.5 Cómo activar un proyecto

Dentro de CodeLite, en la parte izquierda se muestran todos los proyectos que se han creado en el espacio de trabajo. Si nos fijamos en el nombre de todos ellos, veremos que uno está remarcado en negrita; por ejemplo podemos tener:

  • PEC01
  • PEC02
  • PEC03
  • PEC04

Esto significa que cuando vamos a CodeLite -> Build -> Build and Run Project, se ejecutará la acción sobre el project PEC02, aunque por pantalla esté mostrando el código de otro project.

Si se hace doble clic con el ratón sobre el nombre del project PEC04, ahora veremos:

  • PEC01
  • PEC02
  • PEC03
  • PEC04

A partir de este momento, el Build and Run Project se aplicará sobre PEC04.

11.6 Cambiar idioma del teclado

Para cambiar el idioma del teclado en Lubuntu, pulsad con el botón derecho del ratón sobre la barra gris superior -> Add/ Remove Panel Items -> pestaña Panel Applets -> botón Add -> seleccionad el plugin Keyboard Layout Handler -> Add -> Close.

En estos momentos en la parte superior derecha se mostrará el idioma definido por defecto por el teclado -> marca sobre la bandera con el botón derecho -> “Keyboard Layout Handler” settings -> desmarca la opción Keep system layout -> se añade el idioma que se desee desde el botón Add; se puede priorizar un idioma u otro poniéndolo en primera posición en la lista. Una vez que se haya guardado la configuración deseada, ya se habrá cambiado la disposición del teclado al nuevo idioma.

Si se han dejado definidos varios idiomas en la lista, cada vez que se haga click sobre la bandera de la parte superior derecha, se cambiará al otro idioma de la lista.

11.7 Cambiar el teclado asociado a un idioma

Para un mismo idioma tenemos la posibilidad de seleccionar múltiples teclados, y hacer que tanto la máquina virtual como CodeLite funcionen correctamente con nuestro teclado. En caso de que tengamos problemas con el teclado, podemos modificarlo de la siguiente forma:

  1. Accedemos al icono Lubuntu en la parte superior izquierda -> Preferences -> seleccionamos Fcitx.
  2. En la parte superior derecha se mostrará el icono de un teclado -> allí seleccionamos la opción Configure Current Input Method.
  3. Se mostrará una nueva pantalla: desmarcamos la opción Only show current language en la parte inferior, y ya podremos elegir el teclado que coincida con lo que tengamos.

11.8 Programa por defecto al crear un proyecto

Cada vez que se crea un nuevo proyecto en CodeLite, por defecto siempre contiene el código del programa hello world:

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("hello world\n");
    return 0;
}

Por lo tanto, cuando queremos crear nuestro propio programa, basta con borrar el programa que crea por defecto y empezar a codificar nuestro programa nuevo.

Si a pesar de todo no se quiere que se muestre este código cada vez, podemos modificar el código por defecto asociado a los nuevos proyectos:

  • Editar el archivo /usr/share/codelite/templates/projects/ejecutable/main.cpp, que es el que se carga por defecto al crear cada nuevo proyecto.
  • Crear un nuevo template de CodeLite y utilizarlo en el momento de crear un nuevo proyecto. La creación de un nuevo templates se hace a partir de un proyecto que tengamos -> botón derecho sobre el nombre del proyecto -> Save as template ....

11.9 Cómo fijar el kernel de inicio con Lubuntu

A pesar de ser una situación nada habitual, puede darse el caso de que Lubuntu sólo nos arranque en un determinado kernel por problemas con determinadas tarjetas gráficas.

Aunque el kernel siempre se puede seleccionar en el momento de inicio de Lubuntu, podemos fijar cuál es el que queremos utilizar aunque este no sea el más nuevo de todos. Una posible opción para hacerlo es con la aplicación Grub Customizer; para instalarla hacemos:

sudo add-apt-repository ppa:danielrichter2007/grub-customizer

Nos identificamos con la password del usuario uoc.

A continuación, actualizamos la lista de packages de todos los repositorios:

sudo apt-get update
sudo apt-get install grub-customizer

En este punto tendremos instalado Grub Customizer dentro de la máquina virtual FP20222: este programa nos permitirá confirmar exactamente qué hay definido en el arranque grub de la máquina virtual. Para ejecutar el programa: icono de Lubuntu -> System Tools -> Grub Customizer -> poner contraseña uoc -> en la pestaña inicial List configuration se muestran todos los kernels de que dispone el entorno en estos momentos.

Es recomendable hacer una copia previa de las PEC/PR que podamos tener dentro de la FP20222 antes de cambiar el kernel de inicio. Para cambiar el kernel de arranque por defecto: Grub Customizer -> pestaña General Settings -> como default entry, seleccionar el kernel que funciona correctamente de entre todos los disponibles. Una vez elegido, se pulsa el botón Save de la parte superior izquierda.

Para aplicar el cambio que acabáis de guardar en el arranque de Lubuntu hay que abrir un terminal de Lubuntu desde System Tools -> LXTerminal, y desde el terminal teclear:

sudo update-grub

Una vez que haya finalizado el proceso, hay que realizar un reboot de la FP20222 para que coja ahora por defecto el kernel elegido.

11.10 Kernel driver not installed (rc=-1908)

En caso que usemos el sistema operativo macOS y obtengamos el error de VirtualBox Kernel driver not installed (rc=-1908) ... VERR_VM_DRIVER_NOT_INSTALLED (-1908), lo podemos solucionar de la siguiente forma:

  1. Ir al icono de Apple, en la parte superior izquierda -> Preferencias del sistema -> Seguridad y privacidad -> pestaña General -> en la part inferior aparecerá el mensaje System software from developer Oracle America Inc. was blocked from loading -> pulsar el botón Permitir.
  2. Si no se muestra el mensaje indicado en el punto anterior, significa que han pasado más de 30 minutos desde la primera vez que se ha generado el error. En este caso es necesario desinstalar VirtualBox -> volver a instalarlo -> forzar de nuevo el error -> ejecutar los pasos indicados en el punto anterior.

De esta forma permitimos que macOS pueda ejecutar productos de Oracle, entre los que se encuentra VirtualBox.

11.11 BUG: unable to handle kernel NULL pointer dereference at 00000004

Se ha detectado que el kernel más nuevo de la máquina virtual FP20222 tiene alguna incompatibilidad con los processadores AMD Ryzen 5. Este hecho provoca que el proceso de arranque quede parado, mostrando por pantalla el error BUG: unable to handle kernel NULL pointer dereference at 00000004.

La solución pasa por utilizar una versión de kernel anterior. Los pasos a seguir son:

  1. Paramos completamente la máquina virtual y la volvemos a iniciar.
  2. Al principio de todo, cuando se muestre la pantalla negra de arranque de la máquina virtual, pulsamos la tecla shift.
  3. Se mostrará el menú de arranque: entramos dentro de la opción Advanced options for ubuntu -> seleccionamos el kernel más antiguo en modo normal, no en modo recovery.

Una vez validado que podemos iniciar correctamente con un kernel distinto, lo podemos fijar siguiendo las indicaciones del punto Cómo fijar el kernel de inicio con Lubuntu.

11.12 Debugging en CodeLite

La depuración (debugging) de nuestros programas nos permite detectar y corregir errores de programación, sobre todo cuando su tamaño empieza a ser importante. Sirve tanto para detectar errores que hacen que nuestro programa finalice abruptamente, como errores en los cálculos que provocan resultados incorrectos (los de este segundo caso cuestan más de detectar que no los primeros).

El debugger de C, al igual que el compilador, es un pequeño programa externo a CodeLite; esto significa que si quisiéramos instalar CodeLite en nuestro PC, posteriormente habría que añadir un compilador y un debugger de C. La máquina virtual FP20222 ya lo tiene instalado y configurado, por lo que ya lo podemos usar.

El debugger es un pequeño programa que permite ejecutar nuestro código C y poner pausas puntuales dentro de él. Estas pausas se llaman breakpoints, y su objetivo es detener el programa en determinadas líneas del código y poder observar así el valor que toman las variables.

Haremos unas pruebas básicas con el debugger en el siguiente código de ejemplo:

#include <stdio.h>
#define MAX_ELEMENTOS 5

int main(int argc, char **argv) {
    int vEnteros[MAX_ELEMENTOS];
    int i;

    printf("\n>> Se inicializa el vector vEnteros[] a 0's \n\n");
    for (i=0; i<MAX_ELEMENTOS; i++) {
        vEnteros[i] = 0;   /* Línea donde queremos añadir un breakpoint */
    }
}

Queremos saber para cada iteración, qué valor va tomando la variable i, así como la posición correspondiente del vector vEnteros.

Para añadir un breakpoint en la línea indicada con un comentario, hay que situar el cursor encima de la línea y seleccionar CodeLite -> Debugger -> Toggle breakpoint. Una vez hecho, delante de todo de la línea se mostrará una redonda roja para indicar que contiene un breakpoint.

Para empezar a debuggar no usaremos el habitual Build and Run Project: en su lugar debemos elegir la opción CodeLite -> Debugger -> Start/Continue Debugger -> Build and Debug.

El código comenzará a ejecutarse y se detendrá en la línea que contiene el breakpoint. En la parte inferior de CodeLite se mostrará la pantalla Debugger con una serie de pestañas: entramos dentro Locales y veremos una tabla con los valores que las variables del programa tienen en este punto, similar a la siguiente:

Name Value Type
i 0 int
vEnteros [5] int[5]
        0 -1073743940 int
        1 4195915 int
        2 1 int
        3 -1073743940 int
        4 -1073743940 int

Para descongelar el estado y hacer una iteración más del bucle, pulsamos el botón play verde de la barra de herramientas de CodeLite, o seleccionamos CodeLite -> Debugger -> Start/Continue Debugger. La ejecución realizará una iteración del bucle y se volverá a parar, permitiendo revisar los nuevos valores que han tomado las variables del programa:

Name Value Type
i 1 int
vEnteros [5] int[5]
        0 0 int
        1 4195915 int
        2 1 int
        3 -1073743940 int
        4 -1073743940 int

Importante: si en algún punto el programa necesita una respuesta por nuestra parte (como puede ser introducir un dato desde teclado), la tendremos que poner igualmente en el terminal de ejecución (pantalla negra habitual) que abre el debugger en segundo plano .

Para salir del debugger pulsamos el botón stop rojo, o seleccionamos CodeLite -> Debugger -> Stop debugger.

Este es el uso básico del debugger, pero permite hacer más acciones, como por ejemplo:

  • Una vez estamos parados en un breakpoint, podemos ir ejecutando las siguientes líneas de código una a una, con la opción CodeLite -> Debugger -> Next.
  • Dentro de Locales se puede ver el contenido que tenemos en memoria. Necesitaremos saber antes la dirección de memoria a partir de la cual queremos mirar, pero la podemos obtener fácilmente con el especificador de tipo %p.

11.13 Librería math.h

math.h es el archivo de cabecera de la librería estándar del lenguaje C diseñada para realizar operaciones matemáticas básicas. La utilización de esta librería queda fuera del ámbito de la asignatura, ya que no se pedirán operaciones que únicamente se puedan realizar con ella. De todas formas, si alguna vez se quiere utilizar, hay que ejecutar previamente unos pasos concretos en función del entorno:

  • CodeLite: hacer clic con el botón derecho sobre el nombre del proyecto -> Settings… -> Linker -> dentro del apartado Linker Options añadir: -lm.
  • Terminal: en caso de querer usar la librería desde un programa compilado y ejecutado desde terminal, es necesario añadir el parámetro -lm en el momento de generar el ejecutable: gcc nombrePrograma.c -o nombrePrograma -lm

De esta forma ya se puede usar la librería math.h:

#include <stdio.h>
#include <math.h>

int main(int argc, char **argv) {
    int numero;
    int resultado;
    
    numero = 49;
    resultado = sqrt(numero);
    printf("La raíz cuadrada de %d es %d\n", numero, resultado);
    return 0;
}

El resultado de la ejecución será:

La raíz cuadrada de 49 és 7

11.14 CodeLite: tabulador vs espacios

En el apartado 7. Identación del módulo Guía de estilo de programación en C se indica lo siguiente:

“Se aconseja indentar con cuatro espacios por nivel. Evitar el uso de tabuladores, configurar el editor para desactivarlos (la”desactivación" de los tabuladores consiste realmente en insertar espacios en lugar de una tabulación)"

Se puede configurar CodeLite para que cada tabulador que añadamos a nuestro código se sustituya automáticamente por 4 espacios en blanco. Los pasos a seguir son: CodeLite -> Settings -> Preferences -> Editor: Intentation -> desmarcar la opción Use tabs in indentation y en el campo Columns per tab character in document indicar el valor 4.