Generador de documentación doxygen

Logotipo de Doxygen
textoalt

Introducción

Si has visitado páginas de Github dedicadas a librerías C++ tal vez hayas visto que muchas contienen un fichero con el nombre Doxyfile, y también es habitual páginas web con documentación del estilo de esta imagen. Por ejemplo, la documentación de wxWidgets está hecha usando doxygen.

Pues bien, esos ficheros contienen la configuración para el generador de documentación doxygen, y las documentaciones que generan tienen esa forma.

Ejemplo de documentación
Ejemplo de documentación

Doxygen puede generar documentación a partir del código fuente en diferentes lenguajes, aunque aquí nos centraremos en C++, y en diferentes formatos: HTML, LaTeX, RTF, XML, Man page y DocBook. También será posible crear versiones PDF o CHM (HTML comprimido).

La documentación se genera desde el propio código fuente a documentar, y será tanto más completa cuanto más detallados sean los comentarios que se añadan, pero se generará documentación incluso aunque no se incluyan comentarios.

Se puede integrar en Code::Blocks, que ya incluye opciones de menú para utilizarlo, y solo será necesario instalar doxygen y configurar correctamente Code::Blocks para que pueda encontrar el programa.

Instalación

Aunque es posible compilar doxygen a partir de los ficheros fuente, será más sencillo descargar la versión compilada desde la página oficial.

Iremos al enlace de "Download" y elegiremos la versión de sistema operativo que nos interese. En el caso de Windows, la versión del instalador contiene tanto el código fuente como los binarios, la documentación en HTML y ejemplos, y la versión zip solo los binarios.

Si optamos por descargarnos el fichero zip, deberemos descomprimirlo en una carpeta con el nombre "bin", por ejemplo, C:\doxygen\bin, esto nos facilitará la configuración para usarlo desde Code::Blocks.

Configurar Code::Blocks

Para poder usar doxygen desde Code::Blocks bastará con añadir la ruta al directorio bin de doxygen al path en las variables de entorno del sistema.

Esto nos permitirá acceder al menú "DoxyBlocks", ya sea la opción Doxywizard o Extract documentation de Code::Blocks.

También disponemos de una opción en el menú DoxyBlocks de Code::Blocks para modificar las preferencias. Se nos abrirá un cuadro de diálogo en el que podremos establecer algunos valores para personalizar doxygen.

Estilo de los comentarios

Nos permite seleccionar el estilo de los comentarios de bloque y línea. Elige el que más te guste.

Valores por defecto para el fichero Doxyfile

Permite definir ciertos valores para el proyecto actual. Uno de ellos es el lenguaje de salida. Es interesante que ese lenguaje coincida con el que usaremos en los comentarios destinados a generar la documentación.

Valores por defecto 2 para el fichero Doxyfile

Permite seleccionar el formato de salida, y si tenemos instalado GraphViz, activarlo.

General

Aquí hay varias opciones que nos puede interesar establecer, como las rutas a los programas doxygen, doxywizard o Dot (de GraphViz).

En las opciones generales, una interesante es "Use @ in Tags", que utilizará el carácter '@' en lugar de '\' en las etiquetas de los comentarios de bloque.

Documentar el código

Para que doxygen cree una documentación más completa, y que no incluya solo la estructura básica de funciones, tipos y clases, será necesario incluir comentarios.

Sin embargo, esos comentarios deben tener una sintaxis concreta para ser procesados correctamente por doxygen. Veamos en qué consiste esa sintaxis.

Podemos dividir los comentarios destinados a la documentación en dos grupos.

  1. Comentarios de bloque: destinados a documentar espacios con nombre, clases, tipos, estructuras, funciones, macros, enumerados, operadores, etc. Estos comentarios se insertan antes del elemento a documentar. No tienen por qué estar emparejados comentarios de documentación y elementos, pero resulta más claro, y como veremos más adelante, tiene ventajas al usar Code::Blocks.

    Doxygen admite varios estilos de comentario, que describiremos más abajo, de momento usaremos el que en la documentación de denomina estilo Javadoc, y es el que usa Code::Blocks por defecto cuando los intestamos mediante menú o la barra de herramientas. Comienza como un comentario C normal, salvo que la etiqueta de apertura de comentario contiene un asterisco extra:

    /**
     * Comentario
     */
    

    Los asteriscos en las líneas intermedias son opcionales.

    Este tipo de comentarios admite algunas etiquetas o comandos en su interior. Estos comandos empiezan con el carácter '\':

    • Opcionalmente se puede iniciar el bloque con una de las siguientes etiquetas:

      • \struct: para documentar una estructura C/C++.
      • \union: para documentar una unión.
      • \enum: para documentar un tipo enumerado.
      • \fn: para documentar una función.
      • \var: para documentar una variable, objeto o un valor typedef o enum.
      • \def: para documentar una macro.
      • \typedef: para documentar una definición de tipo.
      • \file: para documentar un fichero.
      • \namespace: para documentar un espacio con nombre.
      • \package: para documentar un paquete Java.
      • \interface: para documentar un interfaz IDL.
      • Además de estos comandos existen muchos más. Puedes consultarlos en comandos. Veremos algunos de ellos más tarde.
    • \brief: contiene una descripción breve del elemento al que se refiere el comentario. Después de esa descripción se puede dejar una línea en blanco y añadir una descripción más detallada.
    • \param: descripción de un parámetro. Esta etiqueta se puede repetir tantas veces como sea necesario para documentar todos los parámetros.
    • \return: descripción de valor de retorno.
    • \see: referencias a clases, funciones, tipos... relacionados.
  2. Comentarios de miembros: a menudo es preferible añadir el comentario a un miembro de una clase, estructura o unión en la misma línea, en lugar de hacerlo antes. En este caso se puede usar uno de estos comentarios, que tienen la forma:

    int var; /**< Descripción detallada */
    
  3. Importante: Para documentar un miembro de una clase se debe documentar primero la clase. Lo mismo se aplica a lso espacios con nombre. Del mismo modo, para documentar una función global, un typedef un enum o un #define, se ha de documentar el fichero que lo contiene.

    Ejemplo

    Normalmente solo necesitaremos los ficheros de cabecera para generar la documentación, que contienen las declaraciones y prototipos de cualquier librería.

    Veamos como ejemplo una librería en la que estoy trabajando actualmente, que encapsula las librerías SDL2, que están escritas en C.

    Uno de los ficheros de cabecera más simples contiene algunas funciones para inicializar y liberar las librerías:

    /** \file sdl_sdl2.h
     * \brief Declaración de la clase para manejar librería SDL2.
     * \author Salvador Pozo
     * \version 0.1 beta
     * \date 2023-2024
     */
    /* Funciones SDL2 utilizadas:
     * SDL_Init
     * SDL_Quit
     */
    #include 
    
    /** \namespace sdl.
     * \brief Espacio con nombre sdl.
     *
     * Pues eso, el espacio con nombre para la envoltura de las librerías SDL2.
     */
    namespace sdl {
    
    /** \class SDL2
     * \brief Clase SDL2 de inicialización de librerías.
     *
     * Contiene los métodos para iniciar y liberar los recursos asociados a las librerías SDL2.
     */
    class SDL2 {
    protected:
        bool valid = true; /**< true si la librería pudo se inicializada con éxito. */
    
    public:
        /** \brief Constructor
         *
         * Intenta iniciar la librería con las banderas indicadas.
         * \param flags Uint32 Banderas opcionales
         * \see SDL_INIT_FLAGS
         */
        SDL2(Uint32 flags=SDL_INIT_EVERYTHING) {
            valid = (SDL_Init(flags) == 0);
        }
        /** \brief Destructor
         *
         * Libera los recursos asociados a las librerías SDL2.
         */
        ~SDL2() {
            if(valid) SDL_Quit();
        }
    };
    
    } // namespace
    

    Code::Blocks dispone de opciones de menú y una barra de herramientas específica para doxygen. Dos de las opciones: "Block comment" y "Line comment" insertan estructuras de comentario en el punto en que se encuentre el cursor del editor. Si colocamos el cursor en el inicio de la línea con el contenido que queremos comentar, los comentarios de bloque rellenarán algunos de los comandos necesarios, como los parámetros y valor de retorno de las funciones y métodos.

    Añadir una página principal.

    Además de las páginas generadas a partir de los comentarios es posible añadir un texto que se mostrará en la página de entrada y tantas páginas como queramos con diferentes contenidos. Estos textos están destinados a describir las librerías en su conjunto, añadir ejemplo, precauciones, incompatibilidades, dependencias, etc.

    La documentación aconseja para ello crear un fichero de texto con el nombre "mainpage.dox" o "mainpage.txt" en una carpeta diferente, por ejemplo "manual". El texto que queramos añadir debe usar la sintaxis de bloques de comentarios y para la página principal la etiqueta \mainpage. Por ejemplo, para la página principal:

    /** \mainpage API de prueba
     API de prueba para documentar el funcionamiento de doxygen.
    
     Aquí van las explicaciones generales sobre la API, para qué sirve, cómo utilizarla,
     precauciones, cosas que faltan, etc.
    
     También se pueden incluir instrucciones y ejemplos.
    
    - Ejemplo
    - Referencias
     */
    

    Para añadir páginas adicionales se usa la etiqueta \page, y crearemos un fichero para cada una de ellas. Por ejemplo;

    /** \page Ejemplo Ejemplo
     Ejemplo de uso de API de prueba.
    \code
    #include <iostream>
    #include "api_class3.h"
    #include "api_class4.h"
    #include "api_class5.h"
    
    int main() {
        api::derivada2 DerivadaA(4, "Jose Luis", 5);
        api::derivada3 DerivadaB(4, "Carlos", api::pareja(3,5));
    
    
        std::cout << "Variable: " << DerivadaA.Var() << std::endl;
        std::cout << "Nombre:   " << DerivadaA.Nombre() << std::endl;
        std::cout << "Propia  : " << DerivadaA.Entero() << std::endl;
    
        std::cout << "Variable: " << DerivadaB.Var() << std::endl;
        std::cout << "Nombre:   " << DerivadaB.Nombre() << std::endl;
        std::cout << "Propia  : (" << DerivadaB.Pareja().ParA() << "," << DerivadaB.Pareja().ParB() << ")" << std::endl;
    
        return 0;
    }
    \endcode
     */
    
    Incluir manual
    Incluir manual

    Para que doxygen pueda incluir estas páginas en la documentación hay que modificar la configuración. Si usamos el Wizard, iremos a la pestaña "Expert", en la sección "Input", y añadimos la carpeta donde hayamos almacenado nuestros ficheros. Si hemos creado subcarpetas con ficheros que también queremos añadir, tendremos que marcar la opción "RECURSIVE", un poco más abajo

    Configuración

    Para poder generar la documentación es necesario crear un fichero de configuración. Se trata de un fichero con el nombre "doxygen", sin extensión. Es un fichero de texto que se puede editar manualmente, pero casi nunca será necesario hacerlo, ya que se puede editar usando el programa Wizard, "doxywizard.exe".

    Importante: por defecto doxygen usa la codificación de caracteres UTF8. Si se elige como lenguaje de salida uno diferente del inglés, en nuestro caso el castellano, los acentos y las eñes no se visualizarán correctamente, salvo que los ficheros fuente de nuestro proyecto estén codificados en UTF8. En general, es buena práctica modificar la codificación en el editor de Code::Blocks a UTF8 por defecto. Esto se hace modificando las opciones de Code::Blocks desde el menú Settings->Editor->General settings->Encoding settings, y asignando el valor UTF-8. En cualquier caso, será necesario elegir la misma codificación de caracteres para los ficheros de los que se ha de extraer la documentación y la configuración de doxygen.

    Barra de herramientas doxygen
    Herramientas

    Utilizando el programa de configuración doxywizard, al que podemos acceder desde el menú de Code::Blocks, DoxyBlocks>doxywizard, o desde la barra de herramientas, usando el primer icono.

    La configuración tiene cientos de opciones, pero este artículo no está destinado a explicarlas todas. Veremos las más importantes.

    Vamos a ver cómo usar el wizard con un ejemplo.

    Supongamos que tenemos nuestra API dividida en varios ficheros fuente y de cabecera, cada uno dedicado a una o varias clases, tipos y enumerados relacionados entre si, en la misma carpeta, por ejemplo, "C:\miapi".

    En la ventana del Wizard podemos ver varias zonas. En la superior tenemos la ruta del directorio de trabajo, esta será la carpeta donde se guarde el fichero de configuración. Como norma general, ese directorio puede ser el mismo en el que está nuestro proyecto, en nuestro ejemplo "C:\miapi".

    En la parte inferior izquierda encontramos tres pestañas: "Wizard", "Expert", y "Run".

    En la pestaña "Wizard" tenemos varios apartados. En un principio estará seleccionado "Project", y en la parte derecha podremos ir navegando a través de los apartados usando los botones "Previous" y "Next".

    Apartado Project

    Wizard doxygen: Proyecto
    Wizard doxygen: Proyecto

    En al apartado "Project" podemos rellenar algunos o todos los campos, como el nombre del proyecto, una sinopsis, que indique de forma muy resumida el objeto del proyecto, la versión y opcionalmente un logotipo. Deberemos especificar el directorio donde se encuentran nuestros ficheros fuente. Se puede usar una ruta relativa, si en la misma que hemos especificado antes, bastará con un punto. ".".

    Si el proyecto se compone de fjcheros en varias carpetas podemos marcar la casilla de "scan recursivity".

    Por último, podemos indicar la carpeta donde se generará la documentación.

    Apartado Mode

    En el apartado "Mode" encontramos dos zonas. En la primera podemos elegir entre generar documentación solo para los elementos que contengan comentarios doxygen o para todos lo elementos, tengan o no comentarios.

    Si marcamos la opción de incluir referencias cruzadas, se añadirán enlaces al código fuente donde se define cada entidad.

    En la segunda zona podemos seleccionar el lenguaje para el que se debe optimizar la salida.

    Apartado Output

    En el apartado "Output" elegiremos el formato de salida. Hay seis opciones:

    • HTML: en este formato se generan páginas HTML junto a código javascript y hojas de estilo. Podemos seleccionar tres formatos:

      • HTML plano: sin panel lateral de navegación.
      • HTML con panel de navegación.
      • HTML preparado para .chm. Este formato crea ficheros HTML que se pueden usar para crear ficheros de ayuda contextuales para aplicaciones GUI. Veremos cómo hacer esto en otro artículo.

      Podemos añadir una función de búsqueda y elegir diferentes combinaciones de colores para las páginas de salida.

    • LaTeX: este formato de salida está destinado a crear documentos PDF o PostScript, pero será necesario instalar software adicional LaTeX.

    • Man pages: genera ficheros para crear páginas man de Linux.

    • Formato de texto enriquecido: genera un documento RTF, que puede ser convertido fácilmente a PDF y editado por un procesador de textos.
    • XML: genera la documentación en formato XML. Con el software adecuando permite mostrar la documentación en diferentes formas.
    • Docbook: otro formato XML que se puede usar para convertir la documentación a diferentes formatos.

    Apartado Diagrams

    En el aparatado "Diagrams" disponemos de las opciones para la generación de diagramas. Estos diagramas mostrarán, por ejemplo, las jerarquías de clases.

    Tenemos varias opciones:

    • No diagrams: para no generar diagramas.
    • Text only: se generan diagramas, pero en formato de texto, por ejemplo "Hereda de std::exception.".
    • Use built-in class diagram generator: se generarán diagramas usando el generado propio de doxygen.
    • Use dot tool from the GraphViz package: se usará una aplicación externa GraphViz para generar los diagramas. Esta opción permite personalizar mucho más los diagramas, pero requiere que se instale software adicional.

    Pestaña Expert

    Esta pestaña dispone de varios apartados, que no veremos en detalle en este artículo.

    Sin embargo hay algunas opciones que nos puede interesar establecer y que no están accesibles desde el Wizard.

    Por ejemplo, en Projects podemos establecer un icono para las páginas web en "PROJECT_ICON".

    Otra opción interesante es seleccionar el lenguaje de salida en "OUTPUT_LANGUAJE", de este modo podemos adaptar el lenguaje de los literales al contenido de la documentación.

    Si hemos instalado GraphViz para generar los diagramas es posible que tengamos que incluir la ruta del programa "dot.exe" en el parámetro "DOT_PATH" del apartado "Dot". Aunque la documentación dice que basta con incluir esa ruta en la variable de entorno "path", en mi caso no ha funcionado.

    Hay cientos de opciones, y aunque la mayoría no será necesario modificarlas, puedes repasarlas y probar distintos valores para experimentar.

    Ignorar prefijos

    A menudo nuestros identificadores harán uso de un prefijo, por ejemplo, en las librerías de wxWidgets, los identificadores de todas las clases empiezan con "wx". Esto hace que cuando se generan listas de clases, tipos o funciones aparezcan todos en la misma letra, lo que hace más complicado localizarlos buscando por orden alfabético.

    En el apartado "Index" de la pestaña "Expert" podemos indicar qué prefijos serán ignorados a la hora de mostrar índices por orden alfabético.

    Pestaña Run

    Finalmente, una vez establecidas todas las opciones, podemos pulsar "Run doxygen" para generar la documentación.

    Si hemos elegido el formato HTML, el botón "Show HTML output" abrirá la documentación en el navegador por defecto.

    Ejemplo

    Nombre Fichero Fecha Tamaño Contador Descarga
    Ejemplo doxygen doxygen.zip 2024-01-14 39161 bytes 67