Crear nueva aplicación
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
:
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).
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).
|
nap_project_desktop_app(appName path) |
appName
: El nombre de la aplicación.path
: Subdirectorio donde se ubicará el proyecto (en este casohello
). 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 defectonapphello.c
y unCMakeLists.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
.
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).
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:
1 2 3 4 5 |
1 2 3 4 5 6 7 8 |
Abre /hello/napphello.c
y edita la función i_OnButton
.
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.
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! |
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 casoutils/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:
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
y23
. - Estándar C++:
98
,11
,14
,17
,20
,23
y26
.
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.