Tutorial de CMake

Llevo varios años usando de forma habitual CMake. Sin embargo me doy cuenta que alguien que quiera empezar a usar este sistema va a encontrarse con documentación confusa.

1º Regla de CMake. La documentación puede ser confusa

¿Qué es CMake?

CMake se trata de una herramienta multiplataforma para generar instrucciones de compilación del código. No sustituye a las herramientas de compilación como Make o MSBuild, sino que nos proporciona un único lenguaje que será transformado a las instrucciones del sistema operativo donde nos encontremos. Sería un sustituto de Autotools.

cmake-dia

Las ventajas son que no tenemos que tener varios archivos para gestionar la compilación. Usando CMake podemos generar el resto. Actualmente CMake (3.2.3) soporta:

  • Unix Make
  • Ninja
  • CodeBlocks
  • Eclipse CDT
  • KDevelop
  • Sublime Text 2
  • Borland Make
  • MSYS Make
  • MinGW Make
  • NMake
  • NMake JOM
  • Watcom WMake
  • Kate
  • CodeLite
  • Xcode
  • Visual Studio (desde el 6 hasta 2013)

Usando CMake

En CMake las configuraciones estan centralizadas por defecto en un archivo llamado CMakeLists.txt. Este se encuentra en la carpeta central del proyecto. Normalmente con CMake los proyectos se construyen en una carpeta diferente de la que tenemos el código fuente. Es corriente crear una carpeta build en lo alto del proyecto. Así si tenemos un proyecto con CMake ya descomprimido haríamos lo siguiente.

También puedes usar la aplicación gráfica. Muy cómoda cuando debamos modificar las configuraciones.

cmake-gui

Podemos ajustar las variables de CMake desde la interfaz de usuario, usando el modo interactivo de la línea de comandos (cmake .. -i) o usando flags cuando llamamos a CMake (cmake .. -DCMAKE_CXX_FLAGS=-std=c++11)

El archivo CMakeLists.txt

Ya estamos listos para crear nuestro primer archivo de configuración de CMake.

proyecto

Vamos a ir viendo distintas versiones del archivo donde voy a ir añadiendo diferentes tareas. Estate atento a los comentarios de los archivos

Compilar como programa main.cpp

Y ya está.

Trabajar con opciones y condicionales

CMake permite ajustar muchas opciones como hemos visto con el asistente gráfico de CMake. Sin embargo no todas las variables se muestran ahí. Solo son modificables las que nosotros marquemos explícitamente. Se usa OPTION()

Usar librería estática

Usar librería dinámica

Seleccionar archivos de forma masiva

Usar SET para los archivos es muy fácil de entender, pero es posible que no queramos mantener una lista explícita del código fuente.

Esto tiene un inconveniente y es que CMake no detecta automáticamente si hay nuevos archivos que cumplen la característica, por lo que hay que forzar la recarga.

Copiar, crear, eliminar y descargar archivos

Incluir archivos de cabecera

A veces es necesario incluir archivos de cabecera en localizaciones no estándar

Plugins de CMake

CMake es extensible a través de módulos. La instalación por defecto de CMake trae unos cuantos módulos, no obstante, podemos añadir módulos solo para nuestro proyecto. Los módulos tienen extensión .cmake. Normalmente se dejan en una carpeta llamada cmake.

Mostrar información y generar errores

En ciertas situaciones querremos que no se pueda compilar el proyecto. MESSAGE es la solución.

Condicionales avanzados

Bucles

Submódulos

CMake usa un único archivo, pero quizá nos conviene repartir la configuración de CMake por varias carpetas entre zonas diferenciadas.

Librerías externas

Una de las características más interesantes de CMake es que es capaz de encontrar librerías externas que necesite nuestro programa. Esta característica se implementa con plugins de CMake. Aquí voy a necesitar wxWidgets.

Definiciones

Podemos añadir directivas del preprocesador de C++ con CMake

Dependencias

Se pueden crear árboles de dependencias en CMake

Usando Qt

Ejemplo práctico usando CMake y Qt5 que es capaz de usar QML. Soporta archivos QRC de recursos. Requiere los plugins de Qt5.

Usando Java

CMake soporta Java, aunque no maneja dependencias como Maven o Gradle.

Usar C++11

A partir de CMake 3.1, podemos definir el estándar de C y C++ que vamos a usar

Comandos personalizados, Doxygen

En CMake podemos crear comandos personalizados. Por ejemplo, generar documentación con Doxygen

Archivos de configuración

En Autotools es común usar un archivo con configuraciones en tiempo de compilación. Normalmente se trata de una cabecera con soporte para plantillas. En CMake se puede hacer.

config.hpp.in

Instalar

CMake permite instalar también los programas

CPack

Pero make install es un poco incómodo. No se puede distribuir fácilmente. Aquí CMake presenta CPack, que genara instaladores. Yo soy reacio a usarlos pues son de mala calidad pero soporta:

  • ZIP
  • TAR.GZ
  • TAR.BZ2
  • TZ
  • STGZ – Genera un script de Bash que ejecutará la descompresión y hará la instalación
  • NSIS
  • DragNDrop
  • PackageMaker
  • OSXX11
  • Bundle
  • Cygwin BZ2
  • DEB
  • RPM

CPack necesita que usemos el comando cpack en vez de cmake

Usando ensamblador

CMake soporta correctamente GNU ASM. Nasm requiere más trabajo.

Algunas variables interesantes

|CMAKE_CURRENT_SOURCE_DIR|La ruta completa a la carpeta donde se encuentra CMakeLists.txt|
|CMAKE_MODULE_PATH|Las rutas para buscar plugins de CMake|
|PROJECT_BINARY_DIR|La carpeta que se está usando para guardar los resultados de la compilación|
|CMAKE_INCLUDE_PATH|Las carpetas de búsqueda de cabeceras|
|CMAKE_VERSION|Versión de CMake|
|CMAKE_SYSTEM|El nombre del sistema|
|CMAKE_SYSTEM_NAME|El sistema operativo|
|CMAKE_SYSTEM_PROCESSOR|El procesador|
|CMAKE_GENERATOR|El generador usado en ese momento|
|UNIX|Si estamos en Linux, OS X, BSD o Solaris será cierto|
|WIN32|Si estamos en Windows|
|APPLE|En OS X|
|MINGW| Usando MinGW|
|MSYS| Usando MSYS|
|BORLAND| Usando Borland|
|CYGWIN| Usando Cygwin|
|WATCOM| Usando OpenWatcom|
|MSVC| Usando Visual Studio|
|MSVC10| Usando Visual Studio 10|
|CMAKE_C_COMPILER_ID| El identificador de compilador de C|
|CMAKE_CXX_COMPILER_ID| El identificador de compilador de C++|
|CMAKE_COMPILER_IS_GNUCC| El compilador de C es una variante de GNU GCC|
|CMAKE_COMPILER_IS_GNUCXX| El compilador de C++ es una variante de GNU G++|
|CMAKE_BUILD_TYPE| La configuración Debug/Release que estamos usando|
|CMAKE_C_COMPILER| La ruta al compilador de C|
|CMAKE_C_FLAGS| La configuración del compilador de C|
|CMAKE_C_FLAGS_DEBUG| La configuración del compilador de C solo si estamos en la configuración Debug|
|CMAKE_C_FLAGS_RELEASE| La configuración del compilador de C solo si estamos en la configuración Release|
|CMAKE_SHARED_LINKER_FLAGS| La configuración del compilador para librerías compartidas|
|BUILD_SHARED_LIBS| Por defecto en ADD_LIBRARY, las librerías son compartidas. Podemos cambiar esto|

Muchas más en la wiki de CMake

RPath

El RPath es importante en los sistemas UNIX. Se trata de cargar librerías dinámicas que no están en directorios estándar.


Esto hará que los ejecutables construidos en UNIX puedan cargar librerías desde la carpeta donde se encuentran. Al estilo Windows.

Instala programas en Haiku con HaikuPorts y HaikuPorter

Haiku introdujo recientemente su nuevo sistema de paquetería. Este dispone de varios métodos para obtener los programas. El método más sencillo es HaikuDepot, la aplicación gráfica con paquetes ya compilados listos para descargar e instalar con un click. Sin embargo hay mucho más software disponible en el árbol de recetas de Haiku, conocido como HaikuPorts, que usa un programa propio para su gestión llamado HaikuPorter. HaikuPorter no gestiona la instalación, sino la creación de los paquetes desde la fuentes originales.

haiku-depot

Haikuports y Haikuporter

Haikuports es una colección se software en forma de recetas que dicen como se deben de compilar los programas pero no los almacena. Un sistema similar al de Gentoo y FreeBSD. Haikuports usa Haikuporter para construir los paquetes así que debemos instalar antes de nada Haikuports y Haikuporter.

Instalando Haikuporter

Instalar Haikuporter requiere que abras la terminal y obtengamos su código fuente

Ahora debemos configurarlo con nuestros datos

Tendremos que editar un archivo. Os pongo como tengo el mío

Aunque en vuestro caso podeis poner “no” en ALLOW_UNTESTED y ALLOW_UNSAFE_SOURCES.

Instalando Haikuports

Volvemos a nuestra carpeta y obtenemos el código

Usando Haikuporter y Haikuports

Ya estamos listo para construir cualquier paquete con Haikuporter, no solo los nuestros. Con esto podemos acceder a gran cantidad de software. El uso básico de haikuporter es

Aunque si las dependencias nos abruman podemos saltarnoslo

Los paquetes no se instalan automáticamente, se guardan en /boot/home/haikuports/packages y para instalarlos los debemos copiar a /boot/home/config/packages. También podemos compilar con GCC4 en vez de GCC2 si el programa lo soporta. Hay que añadir _x86 al final. Comprobemos que todo funciona con un paquete al azar

Tardará en actualizar la base de datos y pueden que nos salten errores de arquitecturas pero no hay que preocuparse. En mi caso, Haikuporter quería instalar paquetes del sistema ya que había versiones nuevas en haikuports. Sin embargo, como se que iba a tardar mucho cancelé y ejecuté

Convendría ahora instalar todo lo compilado

PortAudio + libsndfile. Reproducir Ogg Vorbis, FLAC y WAV en C++

Escribo este post ya que cuando quise buscar información sobre el tema no encontré nada en castellano y en inglés poca información. Así pues escribo el que yo considero el mejor método para reproducir audio Ogg Vorbis, FLAC y WAV en C++.
Lo primero es descargar e instalar las librerías, ambas son multiplataforma. En Windows irás a la página oficial y seguirás las instrucciones:

A su vez si tenemos que compilar libsndfile también necesitaremos libogg y libvorbis para activar la reproducción de Ogg Vorbis o las librerías de FLAC para activar FLAC en la librería. El soporte para WAV es nativo y no hace falta nada.
En Linux podemos ahorrarnos tiempo instalando los paquetes binarios. En Debian/Ubuntu:

sudo apt-get install portaudio19-dev libsndfile1-dev

Ahora creamos un fichero de C. Atención, aunque C++ sea compatible con el código de C, este código de C tiene problemas en compiladores de C++. Así pues el código de aquí abajo da error con g++ pero funciona correctamente y sin advertencias en gcc. Si quieres insertarlo en un programa de C++, sigue creando este fichero como fichero de C y en el header encapsula la función definida en un “extern C”:

Ahora en el ejemplo voy a usar una función main para no liarnos y usar solo C, pero eso serán los pasos a seguir si tienes C++.  Creamos el fichero con extensión .c y escribimos la función main(). Ahora abriremos el archivo de audio con la librería encargada de decodificar el audio, libsndfile. Después inicializamos PortAudio y obtenemos el dispositivo de audio por defecto (en el caso de mi Ubuntu, es ALSA). Configuramos el dispositivo con los datos que tenemos del fichero. Abrimos un stream de PortAudio que leerá el archivo. Esta función necesita dos funciones de callbak que se crean más arriba. La principal tiene como objetivo leer el fichero más y la otra hacer algo cuando termine el fichero (se puede dejar vacía). En la de leer el fichero tenemos que tener en cuenta si el equipo es Mono o Estéreo. Yo no he llegado a saber como detectarlo, así que hago la multiplicación por 2 para el estéreo. Luego en el flujo principal iniciamos el stream, sonará, esperamos 10 segundos, paramos y cerramos el stream. Finalmente cerramos el fichero de audio y deshabilitamos PortAudio. Fácil y sencillo. Ahora el código:

Y para terminar un diagrama de salidas de audio nativas soportadas por PortAudio: