SDK Multiplataforma en C logo

SDK Multiplataforma en C

Crear nueva aplicación

❮ Anterior
Siguiente ❯

Me considero una persona técnica que eligió un gran proyecto y una excelente manera para llevarlo a cabo. Linus Torvalds.


En Compilar NAppGUI hemos visto como compilar y empaquetar el SDK. También, en ¡Hola Mundo!, aprendimos la estructura básica de una aplicación basada en NAppGUI. Ha llegado el momento de crear nuestras propias aplicaciones, aprovechando los módulos CMake incluidos en la carpeta /prj de la instalación.

Este capítulo está enfocado en el uso de CMake. Si utilizas otro build system en tus proyectos, deberás adaptar tu mismo la gestión de dependencias.

1. Uso de find_package()

NAppGUI soporta el comando find_package() de CMake, por lo que gestionar las dependencias es sumamente sencillo. También proporciona una serie de módulos dentro del directorio /prj de la instalación, que simplifican la creación de proyectos. Crea una nueva carpeta y añade este único fichero CMakeLists.txt:

CMakeLists.txt
1
2
3
4
5
6
7
cmake_minimum_required(VERSION 3.0)
project(NAppHello)
find_package(nappgui REQUIRED)
include("${NAPPGUI_ROOT_PATH}/prj/NAppProject.cmake")
include("${NAPPGUI_ROOT_PATH}/prj/NAppCompilers.cmake")
nap_config_compiler()
nap_project_desktop_app(napphello hello)

Ejecutamos de CMake dentro de la nueva carpeta:

 
// Windows
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=C:/nappgui
cmake --build build --config Debug

// macOS
cmake -G Xcode -S . -B build -DCMAKE_INSTALL_PREFIX=/usr/local/nappgui
cmake --build build --config Debug

// Linux
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local/nappgui
cmake --build build

Para versiones de CMake inferiores a 3.13:

 
// Windows
mkdir build & cd build
cmake .. -DCMAKE_INSTALL_PREFIX=C:/nappgui
cmake --build . --config Debug

// macOS
mkdir build ; cd build
cmake .. -G Xcode -DCMAKE_INSTALL_PREFIX=/usr/local/nappgui
cmake --build . --config Debug

// Linux
mkdir build ; cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local/nappgui
cmake --build .

En el directorio /build/Debug/bin tendrás el ejecutable napphello (Figura 1).

Aplicación NAppGUI Hello World.
Figura 1: Aplicación recién creada.

El comando find_package() sabe como localizar un paquete dentro de los directorios habituales del sistema, en función de cada plataforma. Necesitaremos especificar el prefijo únicamente cuando el paquete esté instalado en cualquier directorio alternativo.

-DCMAKE_INSTALL_PREFIX no implica prioridad en la búsqueda. find_package() podría encontrar primero una instalación en las carpetas del sistema.

2. NAppProject.cmake

La función nap_project_desktop_app() que hemos utilizado para crear nuestra aplicación, se encuentra dentro del módulo NAppProject.cmake y agilizará ciertos aspectos del proyecto (recursos, dependencias, nuevos archivos, etc). Abrimos la solución de Visual Studio que se ha generado en /build (Figura 2).

Captura del explorador de soluciones de VisualStudio.
Figura 2: Solución creada por NAppProject.cmake.
 
nap_project_desktop_app(appName path)
  • appName: El nombre de la aplicación.
  • path: Subdirectorio donde se ubicará el proyecto (en este caso hello). Se admite cualquier profundidad de ruta. Por ejemplo: games/myapp, demo/games/myapp, etc.

La primera vez que se ejecuta esta función se realizan varias cosas:

  • Se ha creado un nuevo directorio hello con una aplicación de escritorio por defecto napphello.c y un CMakeLists.txt.
  • Se ha creado una carpeta hello/res con una imagen, y se ha utilizado como icono de la aplicación. En Recursos seguiremos profundizando sobre como incluir imágenes y textos en la aplicación.
  • El hello/CMakeLists.txt recién creado, ha enlazado automáticamente con los binarios de NAppGUI.

Sucesivas llamadas a CMake no sobrescribirán los archivos del proyecto, por lo que podemos editarlos sin temor a perder los cambios. Una vez creado el proyecto, nap_project_desktop_app() se limitará a llamar a add_subdirectory() para actualizar cambios. El comando nap_desktop_app() del hello/CMakeLists.txt sabe como manejar las particularidades entre diferentes plataformas. Por ejemplo, en caso de macOS creará un bundle en lugar de un ejecutable aislado.

No tenemos porque limitarnos a una sola aplicación. Nuestra solución admitirá diferentes targets. Por ejemplo añade esta línea al CMakeLists.txt y vuelve a lanzar cmake -S . -B build.

CMakeLists.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cmake_minimum_required(VERSION 3.0)
project(NAppHello)
find_package(nappgui REQUIRED)
include("${NAPPGUI_ROOT_PATH}/prj/NAppProject.cmake")
include("${NAPPGUI_ROOT_PATH}/prj/NAppCompilers.cmake")
nap_config_compiler()
nap_project_desktop_app(napphello hello)

# New project
nap_project_desktop_app(nappbye bye)

En caso de que la solución ya estuviese abierta, es posible que el IDE te avise que han habido cambios (Figura 3). Tras pulsar [Reload], verás que ha aparecido el nuevo proyecto (Figura 4).

Advertencia que muestra Visual Studio, al detectar que se han añadido nuevos archivos.
Figura 3: Aviso de cambios en Visual Studio.
Captura del explorador de soluciones de VisualStudio con nuevos cambios en la solución.
Figura 4: Actualización de la solución, con el nuevo proyecto nappbye.

3. Añadir archivos

Volviendo al proyecto napphello, vemos que por defecto solo se crea un archivo de código fuente (napphello.c) que contiene toda la aplicación. Es muy probable que quieras dividir el código entre diferentes archivos. Crea un par de nuevos archivos hello/myfunc.c y hello/myfunc.h desde el IDE o directamente desde el explorador. Ábrelos y añade estas líneas:

/hello/myfunc.h
1
2
3
4
5
// Example of new header

#include <core/core.hxx>

real32_t myadd_func(real32_t a, real32_t b);
/hello/myfunc.c
1
2
3
4
5
6
7
8
// Example of new c file

#include "myfunc.h"

real32_t myadd_func(real32_t a, real32_t b)
{
    return a + b;
}

Abre /hello/napphello.c y edita la función i_OnButton.

/hello/napphello.c
1
2
3
4
5
6
7
8
9
...
static void i_OnButton(App *app, Event *e)
{
    real32_t res = myadd_func(56.4f, 23.3f);
    textview_printf(app->text, "Button click (%d-%.2f)\n", app->clicks, res);
    app->clicks += 1;
    unref(e);
}
...

Vuelve a re-generar la solución con cmake -S . -B build. El IDE, Visual Studio en este caso, nos vuelve a informar que han habido cambios en el proyecto napphello. Simplemente presiona [Reload All] como ya hicimos en el caso anterior.

Vuelve a compilar y ejecutar napphello para ver los cambios que acabas de realizar. Puedes crear tantos archivos y subcarpetas dentro del directorio hello como necesites para organizar mejor tu código. Recuerda siempre ejecutar cmake -S . -B build cada vez que añadas o elimines archivos del proyecto. El comando nap_desktop_app() actualizará la solución "clonando" la estructura de directorios dentro del proyecto (napphello en este caso).

Llegados a este punto te recomendamos que dediques algo de tiempo a investigar, compilar y probar los ejemplos de la carpeta demo dentro del repositorio de NAppGUI.

4. Aplicaciones por línea de comandos

De forma similar a las aplicaciones de escritorio vistas anteriormente, es posible crear aplicaciones de consola. Añade esta nueva línea al CMakeLists.txt de la solución.

CMakeLists.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
cmake_minimum_required(VERSION 3.0)
project(NAppHello)
find_package(nappgui REQUIRED)
include("${NAPPGUI_ROOT_PATH}/prj/NAppProject.cmake")
include("${NAPPGUI_ROOT_PATH}/prj/NAppCompilers.cmake")
nap_config_compiler()
nap_project_desktop_app(napphello hello)
nap_project_desktop_app(nappbye bye)

# New project
nap_project_command_app(myutil utils/myutil)

Al regenerar la solución con cmake -S . -B build, Visual Studio te volverá a alertar que debes recargar la solución. Se habrá creado un nuevo proyecto en utils/myutil (Figura 5), pero esta vez si lo compilas y ejecutas no aparecerá ninguna ventana. Tan solo verás un mensaje en la consola de Visual Studio:

1
Hello world!
Captura del explorador de soluciones de VisualStudio con tres proyectos.
Figura 5: Solución con los tres ejecutables (targets).

Si abres myutil.c encontrarás el código que ha generado la salida anterior:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/* NAppGUI Console Application */

#include <core/coreall.h>

int main(int argc, char *argv[])
{
    unref(argc);
    unref(argv);
    core_start();
    bstd_printf("Hello world!\n");
    core_finish();
    return 0;
}

Que es la típica plantilla de un programa en C, a la que se le ha incluido el soporte de la librería core. A partir de aquí, ya podemos modificar el código y compilar. nap_command_app() ya lo configuró todo por nosotros.

 
nap_project_command_app(appName path)
  • appName: El nombre de la aplicación.
  • path: Ruta relativa donde se ubicará el proyecto (en este caso utils/myutil).

Ni que decir tiene que el comportamiento de nap_project_command_app() es idéntico al de nap_project_desktop_app(). No sobrescribirá los archivos del proyecto una vez creado e integrará todos los nuevos archivos que añadamos en un futuro.


5. Proyectos de ejemplo

Tienes a tu disposición varios paquetes que puedes utilizar para probar la instalación del SDK:

  • GuiHello. Varios ejemplos de uso de componentes: Botones, Etiquetas, Tablas, etc.
  • Dice. Ejemplo del uso de librerías.
  • Products. Ejemplo de peticiones HTTP en aplicaciones gráficas.
  • WebHello. Ejemplo de un navegador Web embebido en una aplicación.
  • GLHello. Ejemplo de gráficos 3D con OpenGL, embebidos en una aplicación.

6. Estándar C/C++

Por lo general, los compiladores permiten comprobar que el código se ajuste a ciertos estándares de C/C++, emitiendo advertencias o errores cuando no sea así. En pro de la portabilidad, todos los proyectos generados por nap_desktop_app() y nap_command_app() establecen los estándares más antiguos (C90 y C++98 respectivamente). Es posible que quieras utilizar estándares más modernos en tus proyectos. Abre hello/CMakeLists.txt y añade estas dos líneas:

hello/CMakeLists.txt
1
2
3
4
5
6
nap_desktop_app(napphello "" NRC_NONE)
#-----
nap_target_c_standard(napphello 11)
nap_target_cxx_standard(napphello 14)
#-----
target_link_libraries(napphello ${NAPPGUI_LIBRARIES})

El comando nap_target_c_standard() ha establecido el estándar C11 para napphello. De igual forma, nap_target_cxx_standard() ha seleccionado C++14.

  • Estándar C: 90, 99, 11, 17 y 23.
  • Estándar C++: 98, 11, 14, 17, 20, 23 y 26.
Si CMake o el compilador no soportasen el estándar indicado, se establecerá el más moderno permitido. Es responsabilidad del programador utilizar los compiladores apropiados al estándar elegido.
❮ Anterior
Siguiente ❯