sábado, 23 de noviembre de 2013

Creación de complementos. Paso 1: relatividad

En el post anterior conté algo sobre algunos problemas que aparecían al querer utilizar bibliotecas externas en un proyecto de ZinjaI, y expliqué la solución a un ejemplo paso por paso. El ejemplo se basaba en la biblioteca OpenCV en su versión para Windows. Si siguieron más o menos esos lineamientos, deberían poder compilar un programa básico con OpenCV y verlo corriendo. En ese caso tuvimos que, además de configurar el proyecto, compilar la biblioteca.

En este segundo post vamos a reacomodar esos archivos de la biblioteca, para tener lo justo y necesario en una sola carpeta, carpeta que estará dentro de la carpeta de instalación de ZinjaI para evitar andar desparramando más archivos por el sistema, y para que además podamos llevarla a cualquier otra PC y sin importar dónde se halla instalado ZinjaI en esa otra PC, el proyecto compile igual sin cambios. Todavía se podrán ajustar más detalles muy útiles (como el autocompletado por ejemplo) antes de tener todo listo para armar finalmente la plantilla y el complemento, pero eso quedará para una tercera parte.

El primer paso será entonces seleccionar de entre los muchos archivos de la biblioteca lo mínimo que necesitamos para trabajar con ella desde un programa cliente. En general serán tres cosas: las cabeceras (para los #includes), los binarios .lib o .a (para el enlazado), y, si está compilada para utilizarse como biblioteca dinámica, los .dll (para poder ejecutar el resultado). En el ejemplo asumí por simplicidad que descomprimíamos OpenCV en el raiz del disco C. Esto es muy cómodo pero poco recomendable, y no a todos les simpatizará esa ubicación. En general entonces la plantilla de un proyecto no debería depender de rutas fijas (como lo es "c:\opencv" en este caso). Lo mejor es usar rutas relativas. Y si estamos haciendo un complemento para ZinjaI, las rutas serán relativas a la carpeta de instalación de ZinjaI o a alguna configuración del mismo.

Así es que en una instalación estándar de ZinjaI en Windows, los archivos del compilador (ejecutables, cabeceras, binarios de bibliotecas, etc.) están todos organizados en una estructura de directorios estilo Unix dentro de una carpeta MinGW, y esta carpeta está en donde sea que se instaló ZinjaI. Pueden configurar luego otra carpeta si quieren, por ejemplo, para compartir un mismo MinGW entre varios IDEs; pero si no tocaron nada todo estará probablemente en "C:\Archivos de Programa (x86)\zinjai\MinGW". Allí tendrán subcarpetas como bin para ejecutables (archivos .exe y sus dlls), lib para binaros de bibliotecas (.lib y .a), include para cabeceras (.h), y doc para documentación (manuales, referencias). En las configuraciones de ZinjaI, pueden referirse a esta carpeta como "${MINGW_DIR}". Donde escriban eso ZinjaI lo reemplazará por la verdadera ruta que corresponda a la instalación y configuración real cada vez que lo necesite.

Pero para evitar mezclar en estas carpetas archivos de diferentes bibliotecas y también para tener las cosas un poco más prolijas, lo que suelo hacer es una subcarpeta con el nombre de la biblioteca, y reproducir la estructura de directorios allí dentro. Siguiendo con el ejemplo de OpenCV, entonces:
  1. Hay que crear una nueva subcarpeta "OpenCV" dentro de "MinGW".
  2. Allí dentro crear una "lib" para copiar los archivos .lib que había en "C:\OpenCV\booga\lib"
  3. Crear una segunda carpeta "bin" para los .dlls y copiar allí los que había en "C:\OpenCV\booga\bin". Esto no es necesario para poder compilar un proyecto, pero puede serlo para ejecutarlo, y copiarlos siempre aquí es una forma de saber siempre donde ir a buscarlos si se necesitan.
  4. Una carpeta más "include" para los headers. Hay que aclarar que es importante mantener la estructura de directorios que tenga la carpeta include de la biblioteca y reproducirla exáctamente dentro de esta nueva carpeta include. Es decir, no copien los .h directamente en include, sino que copien las carpetas "opencv" y "opencv2" que ven en "C:\OpenCV\build\include".
  5. Si tuviesemos una documentación de la biblioteca que sabemos que vamos a necesitar la copiaríamos en una nueva subcarpeta "doc". La clase de documentación que suelo considerar para esto son las referencias, preferiblemente en formato HTML para poder buscar más fácilmente. La idea es tener la documentación de consulta rápida. En el caso de OpenCV esta documentación está online, pero no encontré ningún link para descargarla en HTML (solo en pdf, pero creo que es mucho más cómodo en HTML).
  6. Abrir el proyecto de ZinjaI, ir a las opciones de compilación y cambiar por todos lados donde diga "C:\OpenCV\Booga" por "${MINGW_DIR}".
  7. Eliminar los .dlls de la carpeta del proyecto y en las opciones de compilación, en el campo "Variables de entorno"  de la pestaña "General", ingresar "PATH+=;${MINGW_DIR}\OpenCV\bin"

El paso 7 es nuevo, hay un detalle que no mencioné en el post anterior porque todavía no estaba implementado, pero ahora sí (lo verán en breve cuando publique la próxima versión). Por simplicidad, en el ejemplo habíamos copiado todos los .dll de la biblioteca a la carpeta del proyecto, pero dado que son varios y ocupan lo suyo, tal vez sería mejor no ponerlos allí. Desde la próxima versión de ZinjaI, podrán definir en el perfil de configuración y ejecución del proyecto variables de entorno. La variable que dice dónde buscar dlls en Windows es PATH (en GNU/Linux es LD_LIBRARY_PATH). Podremos ir a las opciones del proyecto, y en la pestaña "General" buscar este nuevo campo ("Variables de entorno") y escribir allí "PATH=${MINGW_DIR}\OpenCV\bin" para asignarle el valor a la variable. Pero está variable ya tendrá algunas carpetas (pues también se usa para buscar exes) y será mejor conservarlas y solo agregarle la nueva (separándola con ;). Para esto, ponemos "PATH+=;..." en lugar de "PATH=..." (+=; en lugar de +), y así ZinjaI agregará ese contenido al contenido original de la variable.

Ahora notemos que cada proyecto creado con la plantilla básica trae por defecto dos perfiles de compilación, uno Debug y uno Release. Debería aplicar estas configuraciones en ambos perfiles, y renombrarlos a algo como "Debug-Win32" y "Release-Win32". Por otro lado sería bueno agregar un par de perfiles similares pero para GNU/Linux. Para ello utilicen el botón Nuevo que hay junto al nombre del perfil en el cuadro de configuración del mismo. El nuevo perfil se crea copiando el que tengan seleccionado. Normalmente, luego solo hay que configurar la lista de bibliotecas a enlazar (y las macros si fuese necesario), ya que los binarios en GNU/Linux no se instalan con ZinjaI, sino que siempre se instalan en el sistema mediante el gestor de paquetes. De esta forma usualmente el compilador los encuentra sin problemas y sin requerir ayuda. Cuando no es así, podemos echar mano a pkg-config (como expliqué en este otro post). En este caso tendremos que hacer eso, poniendo "`pkg-config --cppflags opencv`" en el campo de "Parámetros extra para la compilación" y "`pkg-config --libs opencv`" en el campo de "Parámetros extra para el enlazado". Lo ideal entonces para que el proyecto quede completo y listo para compilar donde sea es hacer todo esto (y si pueden hacer los perfiles para Mac mejor todavía). Que el nombre del perfil diga Win, Windows, Linux, Lnx o Mac le sirve a ZinjaI para deducir para qué sistema son, y seleccionar por defecto automáticamente uno que corresponda al sistema en el que lo usan al abrir el proyecto.


Ahora ya podemos llevarnos el proyecto a otra PC, y simplemente necesitaremos copiar la carpeta OpenCV desde un MinGW al otro, sin desparramar nada más por el sistema, ni depender de ruta fijas. En conclusión, sin importar dónde se instaló ZinjaI el proyecto funcionará igual. Ahora sí, está casi todo listo para armar el complemento. En el próximo post puliremos algunos detalles y obtendremos finalmente el archivo .zcp.

Este post es continuación de Creación de complementos. Paso 0: configurar un proyecto y sigue en Creación de complementos. Paso 2: extras.

No hay comentarios:

Publicar un comentario