Abierta inscripción a Día de Software Libre en la ESII

— [ edit | raw ] migrated from node/1351
El próximo 28 de Abril se celebra el Día del Software Libre en la Escuela Superior de Ingeniería Informática (ESII) de Albacete. Durante el evento se organizarán charlas y talleres sobre software libre, como la Fase Final del Concurso Univ. de Software Libre de CLM, Android, Bazaar, GvSIG, etc. Entre los asistentes a los eventos habrá un sorteo de un móvil HTC con Android y un equipo Media Center. Esta jornada se engloba dentro de las actividades organizadas para la Semana Cultural del Campus Universitario de Albacete, que tendrá lugar del 26 al 30 de Abril. Puede encontrarse más información sobre la agenda de la jornada e inscribirse en: http://ceslcam.com/dia-del-software-libre-albacete.html

GNU Emacs: Macros de teclado

— [ edit | raw ] migrated from node/1350

Cómo definir, guardar y utilizar macros de teclado en emacs.

Guía de referencia para cámaras AXIS

— [ edit | raw ] migrated from node/1349

Este artículo es una guía de referencia para el uso básico de cámaras AXIS 214 Pam-Tilt-Zoom (PTZ). No obstante, es posible que para otros modelos de AXIS sea útil.

Día del Documento Libre

— [ edit | raw ] migrated from node/1348

CMake: Instalar un paquete

— [ edit | raw ] migrated from node/1345
Esta receta explica cómo utilizar, fundamentalmente, el comando INSTALL de CMake para crear objetivos de instalación.

El comando INSTALL

CMake proporciona el comando INSTALL que facilita en gran medida seleccionar los componentes de nuestro proyecto que queremos instalar y dónde. En esta receta nos vamos a centrar en un uso básico del comando. Para algo más avanzado nada mejor que la documentación.

Ejemplo

Supongamos que queremos instalar un binario y dos versiones de una misma librería: una estática y otra dinámica. El código CMake para este caso podría ser el siguiente:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

# Librerías
ADD_LIBRARY(dummy_shared SHARED dummy.cpp)
SET_PROPERTY(TARGET dummy_shared PROPERTY SOVERSION 1.0)
ADD_LIBRARY(dummy_static STATIC dummy.cpp)
SET_TARGET_PROPERTIES(dummy_shared dummy_static PROPERTIES OUTPUT_NAME dummy)

# Ejecutable
ADD_EXECUTABLE(hello hello.cpp)
Inicialmente, podrías añadir un comando por cada uno de los componentes que queremos instalar indicando el directorio destino. Sin embargo, como es habitual necesitar instalar varios objetivos, el comando INSTALL proporciona una forma más compacta:
# ... el código anterior aquí

SET_TARGET_PROPERTIES(dummy_shared
      PROPERTIES    PUBLIC_HEADER  "${CMAKE_CURRENT_SOURCE_DIR}/dummy.h"

INSTALL(TARGETS hello dummy_static dummy_shared
RUNTIME          DESTINATION    bin
ARCHIVE          DESTINATION    lib/static
LIBRARY          DESTINATION    lib
PUBLIC_HEADER    DESTINATION    include)
En primer lugar, se asocia a la librería dinámica las cabeceras que serán necesarias instalar posteriormente como "cabeceras públicas" utilizando el comando SET_TARGET_PROPERTIES. Es posible asociar distintos archivos a objetivos para, posteriormente, usarlos en el comando INSTALL. De hecho, lo apropiado sería crear un FRAMEWORK... pero quizás es demasiado para este ejemplo. Consulta el manual para obtener más información que, además, explica cómo utilizar INSTALL de otras formas. La forma en que se ha usado INSTALL es la más compacta. Básicamente, viene a decir lo siguiente (por defecto, CMAKE_INSTALL_PREFIX=/usr/local):
  • Al objetivo hello se le debe tratar como un ejecutable (RUNTIME) y debe instalarse en el directorio ${CMAKE_INSTALL_PREFIX}/bin.
  • Al objetivo dummy_static se le debe tratar como una librería estática (ARCHIVE) y debe instalarse en el directorio ${CMAKE_INSTALL_PREFIX}/lib/static.
  • Al objetivo dummy_shared se le debe tratar como una librería dinámica (LIBRARY) y debe instalarse en el directorio ${CMAKE_INSTALL_PREFIX}/lib.
  • Finalmente, las cabeceras públicas (PUBLIC_HEADER) configuradas a lo largo del programa deben instalarse en ${CMAKE_INSTALL_PREFIX}/include.
Y con ello, ya disponemos de un objetivo install en el Makefile generado que nos permitirá instalar el software.

¿Cómo personalizar mi instalación?

Supón que tienes un directorio en tu home llamado ~/usr y que las variables de entorno pertinentes las tienes configuradas a ese path. Estaría muy bien que pudieras hacer que CMAKE_INSTALL_PREFIX tuviera un valor concreto para instalar el software en ese lugar. Para ello, simplemente ejecuta lo siguiente:
$ cmake -DCMAKE_INSTALL_PREFIX=~/usr ..
Sin embargo, es posible que hayas instalado otras cosas en ese ruta (cabeceras de código, por ejemplo) y las uses en tu proyecto. Obviamente, CMake no puede buscar en todo el disco duro en busca de la cabecera problemática. Por ello, es recomendable que cuando cambies el directorio de instalación también cambies lo siguiente:
$ cmake -DCMAKE_INSTALL_PREFIX=~/usr -DCMAKE_PREFIX_PATH=~/usr ..
De esta forma, los módulos que buscan cabeceras y librerías añadirán ese path a su ruta de búsqueda (además de las rutas del sistema).

Referencias

CMake: Enlazado de librerías

— [ edit | raw ] migrated from node/1346
En esta receta se explica cómo linkar binarios con librerías estáticas y dinámicas.

Linkado básico

A estas alturas ya conocemos cómo construir archivos binarios y librerías en CMake. Ahora supón que la librería dummy que se viene utilizando en los ejemplos está instalada en un path accesible y que el programa hello.cpp hace uso de la librería de forma dinámica. Una posible implementación de este escenario sería la siguiente:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(hello)

# Para includes
FIND_PATH(dummy_path dummy.h)

IF(NOT dummy_path)
   MESSAGE(FATAL_ERROR "** Falta la cabecera dummy.h, dummy!")
ENDIF()

INCLUDE_DIRECTORIES(${dummy_path})

# Búsqueda del .so
FIND_LIBRARY(dummy_lib dummy)

IF(NOT dummy_path)
   MESSAGE(FATAL_ERROR "** Falta la librería dummy, dummy!")
ENDIF()

ADD_EXECUTABLE(hello hello.cpp)
TARGET_LINK_LIBRARIES(hello ${dummy_lib})
En primer lugar, se comprueba que es posible acceder a la librería dummy (tanto la cabecera como el archivo .so). Utilizando el comando TARGET_LINK_LIBRARIES se indica a CMake que el objetivo hello debe ser linkado con la librería dummy_lib. Para una librería estática, sería muy similar el código ya que CMake detecta que se trata de un tipo u otro y genera el código necesario para linkar estática o dinámicamente según la librería encontrada.

FindPkgConfig

Habitualmente, muchas librerías que se utilizan en sistemas como GNU utilizan la herramienta pkg-config que ayuda a obtener las distintas variables necesarias (CFLAGS, LDFLAGS, etc). CMake proporciona un módulo llamado FindPkgConfig que incluye comandos útiles para encontrar librerías que utilizan pkg-config. Pese a que se incluye en la distribución estándar, CMake no recomienda el uso de este módulo porque es posible que haya sistemas privativos que no tengan instalada la aplicación pkg-config. Pero eso, no nos preocupa... ¿verdad? :-) Supón que el programa hello utiliza glib. Podríamos comprobar que está instalado y enlazarlo como sigue:
#Carga del módulo
include(FindPkgConfig)
PKG_CHECK_MODULES(glib REQUIRED glib-2.0) # REQUIRED=Fallará si no lo encuentra

# En "glib_INCLUDE_DIRS" se han cargado los directorios (-I del compilador)
INCLUDE_DIRECTORIES(${glib_INCLUDE_DIRS})

ADD_EXECUTABLE(hello hello.cpp)

# En "glib_LIBRARIES están el nombre de las librerías (-l del compilador)
TARGET_LINK_LIBRARIES(hello ${glib_LIBRARIES}
¿Y cómo es que en glib_LIBRARIES y glib_INCLUDE_DIRS se guardan esos datos?. Los módulos Find* de CMake crean variables para que el usuario las pueda utilizar en caso de encontrar la librería o el objeto que se esté buscando. Una buena forma de saber sobre qué variables se dispone es consultando la documentación. En la cabecera de los módulos también viene esta información (en Debian /usr/share/cmake2.8/Modules/*.cmake).

CMake: Compilando aplicaciones ZeroC Ice

— [ edit | raw ] migrated from node/1347
Esta receta explica cómo compilar un Hola Mundo para el middleware ZeroC Ice utilizando CMake.

Software necesario

Puedes descargarte el software que se va a utilizar del siguiente repo subversion:
$ svn co https://arco.esi.uclm.es/svn/public/samples/cmake/hello_ice
En el repositorio se encuentra la implementación de un "Hola Mundo" para ZeroC Ice y el CMakeLists.txt asociado.

Herramientas externas

Un programa en Ice presenta un problema común: archivos que se generan con herramientas externas al proyecto son necesarios para la compilación. En Ice, slice2cpp genera código que debe ser incluido en la compilación. CMake proporciona un comando muy útil llamado ADD_CUSTOM_COMMAND y que permite definir cómo se generan ciertos objetivos. Utilizando este comando, veamos cómo quedaría el programa CMake para construir el Hola Mundo en Ice:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

PROJECT(hello_ice)

FIND_LIBRARY(ice_lib Ice)
FIND_PATH(ice_path Ice)

IF(NOT ice_path)
  MESSAGE(FATAL_ERROR "** Librería de Ice no encontrada")
ENDIF()

# Variable con los slices necesarios
SET(SLICES ${CMAKE_CURRENT_SOURCE_DIR}/slice/hello.ice)

# slice2cpp
ADD_CUSTOM_COMMAND (
  OUTPUT hello.cpp hello.h
  COMMAND slice2cpp ${SLICES}
  )

INCLUDE_DIRECTORIES(
  ${CMAKE_CURRENT_SOURCE_DIR}
  ${CMAKE_CURRENT_BINARY_DIR}  # slice2cpp deja el .h en el directorio en 'build'
  ${ice_path}
  )

ADD_EXECUTABLE(Client hello.cpp Client.cpp)
ADD_EXECUTABLE(Server hello.cpp helloI.cpp Server.cpp)
TARGET_LINK_LIBRARIES(Server ${ice_lib})
TARGET_LINK_LIBRARIES(Client ${ice_lib})
Al principio, se hacen unas liberas comprobaciones de que la librería de Ice existe. A continuación se define el comando slice2cpp diciendo que como salidas los ficheros hello.cpp y hello.h a partir del fichero Slice hello.ice. Los archivos de salida son dependencias de los distintos ejecutables que se deben crear. Finalmente, se enlaza con las librerías necesarias.

Referencias

Guía rápida de CMake en GNU/Linux

— [ edit | raw ] migrated from node/1342
Esta receta es una guía rápida de CMake. Se trata de una herramienta para la construcción automática de proyectos software, facilitando su portabilidad.

CMake: Construir una librería estática y/o dinámica

— [ edit | raw ] migrated from node/1344
Esta receta explica cómo construir librerías estáticas y dinámicas con CMake.

Software necesario

Los ejemplos que vamos a utilizar puedes descargarlos utilizando subversion desde:
$ svn co https://arco.esi.uclm.es/svn/public/samples/cmake/libstatic
$ svn co https://arco.esi.uclm.es/svn/public/samples/cmake/libshared
Los directorios contienen una librería con una definición de la clase Dummy (dummy.h y dummy.cpp) con un único método. También se incluye el CMakeLists.txt correspondiente.

Librería estática

Para crear una librería estática nada más fácil que lo que sigue:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

PROJECT(libstatic)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

ADD_LIBRARY(dummy STATIC dummy.cpp)
El comando INCLUDE_DIRECTORIES permite añadir los directorios donde se encuentran las cabeceras del proyecto. En este caso, el fichero dummy.h se encuentra en el mismo directorio donde están los fuentes (el mismo en el que se encuentra CMakeLists.txt). La variable global CMAKE_CURRENT_SOURCE_DIR tiene esta ruta. De una forma similar a como se añadían ejecutables, para crear una librería se debe utilizar ADD_LIBRARY que acepta, entre muchos otros, los siguientes parámetros:
  • objetivo: se trata un nombre simbólico para el objetivo que representa el crear la librería. Si no se especifica otra cosa, este nombre se utilizará para crear el fichero final de la forma libobjetivo.a.
  • STATIC: modo de la librería.
  • dependencias: de qué ficheros u objetivos depende la librería para su construcción

Librería dinámica

A la vista de lo anterior, parece sencillo crear una librería dinámica. ¿Bastará cambiar STATIC por SHARED?. Sí, con eso bastaría. Pero vamos a añadir algo más para hacer que la librería sea más "distribuible":
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

PROJECT(libshared)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

ADD_LIBRARY(dummy SHARED dummy.cpp)
SET_PROPERTY(TARGET dummy PROPERTY SOVERSION 1.0)
En CMake, los targets (objetivos) tienen propiedades que, a priori, tienen ciertos valores por defecto. La propiedad SOVERSION de los objetivos que son librerías dinámicas, por defecto, no tiene valor. Sin embargo, es conveniente versionar las librerías para que aquellas plataformas que lo soporten (como por ejemplo, GNU) puedan gestionar las versiones. Con el comando SET_PROPERTY se puede modificar las propiedades de las estructuras que se van creando en el programa. En este caso, para el objetivo 'dummy' se cambia el valor de la propiedad SOVERSION a 1.0. De esta forma, al compilar la librería CMake generará los enlaces simbólicos necesarios de forma automática.

Librería estática y dinámica

Es posible que para una misma librería quieras que pueda ser enlazada de forma estática y también dinámica. Veamos una posible solución:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

PROJECT(libstaticshared)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

ADD_LIBRARY(dummy_shared SHARED dummy.cpp)
SET_PROPERTY(TARGET dummy_shared PROPERTY SOVERSION 1.0)

ADD_LIBRARY(dummy_static STATIC dummy.cpp)

SET_TARGET_PROPERTIES(dummy_shared dummy_static PROPERTIES OUTPUT_NAME dummy)
No se puede utilizar dummy como objetivos de ambas librerías. Lo que se puede hacer, por tanto, es crear un objetivo por cada tipo de librería (dummy_shared y dummy_static). Si no decimos nada más, CMake nos generará los archivos libdummy_static.a, libdummy_shared.so,... Y eso, obviamente, no es lo deseable. Por ello utilizamos SET_TARGET_PROPERTIES que sirve para configurar propiedades de objetivos (es un caso particular de SET_PROPERTY).

Referencias

  • Documentación CMake2.8: consultar las propiedades genéricas y de los diferentes tipos abstractos (directorios, objetivos, ficheros fuente...).

CMake: Compilar un Hola Mundo!

— [ edit | raw ] migrated from node/1343
Esta receta explica cómo compilar un programa trivial con CMake.

Software necesario

El ejemplo que vamos a utilizar puedes descargarlo utilizando subversion desde:
svn co https://arco.esi.uclm.es/svn/public/samples/cmake/single_binary
El directorio 'single_binary' contiene una implementación (hello.cpp) de un "Hola Mundo" en C++ y el archivo CMakeLists.txt.

Versión "quick" y no tan "dirty"

El contenido del archivo es el siguiente:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(hello)
ADD_EXECUTABLE(hello hello.cpp)
En primer lugar, se especifica la versión mínima de CMake que se debe utilizar. A continuación, se debe dar un nombre al proyecto utilizando el comando PROJECT. Como se trata de un proyecto archi-sencillo, sólo consta de un ejecutable y éste se debe generar a partir del fichero "hello.cpp" (su dependencia). El comando ADD_EXECUTABLE acepta una lista de dependencias. Como puedes ver, prácticamente es una regla de Makefile pero más abstracta de forma que sea posible no sólo crear Makefiles sino también exportar a proyectos de Eclipse y otros entornos de desarrollo privativos (a los cuales no recomiendo exportar).

Versión "paranoic"

En el ejemplo anterior, desde un punto de vista ortodoxo, hemos supuesto muchas cosas. Por ejemplo, en el fichero "hello.cpp" se incluye la cabecera "iostream". ¿Hemos comprobado que está instalada? El compilador de C++ que utilizamos, ¿tiene soporte para que se pueda utilizar el namespace "std"? Como ves, hay muchas cosas que se han dado por supuestas en el ejemplo anterior. Aunque para este ejemplo no sea necesario, veamos una versión del archivo CMakeLists.txt más avanzada:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

PROJECT(hello)

INCLUDE(TestForSTDNamespace)
IF (CMAKE_NO_STD_NAMESPACE)
  MESSAGE(FATAL_ERROR "** El compilador no soporta std:: en clases STL")
ENDIF()

INCLUDE(CheckIncludeFileCXX)
CHECK_INCLUDE_FILE_CXX(iostream IS_OSTREAM)

IF(NOT IS_OSTREAM)
  MESSAGE(FATAL_ERROR "** No se encuentra la cabecera 'iostream'")
ENDIF()

ADD_EXECUTABLE(hello hello.cpp)
En este ejemplo se introduce el uso de módulos que se proporcionan en la distribución de CMake 2.8 en Debian:
  • TestForSTDNamespace: incluye el código necesario para comprobar que existe el compilador soporta el uso del espacio de nombres std. Esta macro modifica una variable global (CMAKE_NO_STD_NAMESPACE) con el resultado de dicho test.
  • CheckIncludeFileCXX: se trata de un módulo que contiene el comando CHECK_INCLUDE_FILE_CXX que acepta como primer parámetro el nombre del archivo a incluir y, como segundo parámetro, una variable donde almacenar el resultado. De esta forma, utilizando un IF podemos comprobar que efectivamente se encuentra instalada la cabecera iostream.

Referencias