viernes, 28 de septiembre de 2012

Compilación y bibliotecas (parte 5): crear bibliotecas con ZinjaI

En los cuatro posts anteriores de esta serie Compilación y Bibliotecas hablé un poco en general del proceso de compilación y el uso de bibliotecas externas, para explicar finalmente en el cuarto cómo utilizar un biblioteca X en un proyecto de ZinjaI. En la última entrega de la serie, vamos a ver un caso mucho menos frecuente, pero igualmente interesante: vamos a ver cómo crear nuestras propias bibliotecas con ZinjaI.

Desde hace ya unas cuantas versiones, ZinjaI presenta en el cuadro de diálogo de Opciones de Compilación y Ejecución de Proyecto, una pestaña titulada "Biblioteca". Esta pestaña sirve para crear una biblioteca a partir de una parte del proyecto. Sabemos ya que una biblioteca por sí misma no se puede ejecutar, sino que requiere de un programa cliente. Cuando uno desarrolla una biblioteca va desarrollando al mismo tiempo uno o más programas clientes para probar su funcionamiento.  Entonces, la idea es que en el proyecto de ZinjaI tendremos un conjunto de archivos que conforman los fuentes de una o más bibliotecas, y otro conjunto de archivos que conforman el programa cliente. En la pestaña "Biblioteca" es donde decimos qué bibliotecas generar y con qué archivos. También se puede indicar allí mediante un checkbox que el proyecto solo generará una biblioteca, y no habrá programa cliente si así se quisiera, pero creo que no es lo normal durante el desarrollo, aunque puede ser útil en los perfiles para release.


El proceso es simple, hay un botón "Agregar" para añadir una nueva biblioteca, y otro "Editar" para editar una existente. Se puede tener tantas bibliotecas como se quiera. Agregar una biblioteca es en realidad decir que se va a generar un archivo .so, .dll, .a o .lib (dependiendo del tipo de biblioteca) aclarando cuales fuentes deben compilarse para conformar el mismo. El cuadro de configuración que aparece al hacer click en "Agregar" o en "Editar", tiene los siguientes campos:
  • Nombre: permite establecer el nombre de la biblioteca, que será el nombre del archivo agregando el prefijo "lib" y la extensión que corresponda.
  • Directorio de salida: la ubicación donde será generado el binario de la biblioteca (una carpeta generalmente relativa a la carpeta de proyecto).
  • Archivo de salida: este campo no es editable, sino que muestra cual será la ruta y el nombre del archivo final según la configuración ingresada en los otros campos.
  • Opciones de enlazado: permite definir argumentos adicionales (además de los ya definidos en la pestaña "Enlazado") para pasar al linker para la construcción de esa biblioteca sin afectar las otras llamadas al enlazador (las que se harán para construir otras bibliotecas, o la que se utiliza para construir el ejecutable final).
  • Tipo de biblioteca: permite elegir entre "Estática" y "Dinámica", y de esto (y del sistema operativo) dependerá la extensión del archivo binario.
  • Fuentes a incluir/excluir: permite elegir cuáles fuentes (un subconjunto de archivos .cpp del proyecto, no cabeceras) serán compilados y enlazados para conformar la biblioteca. Cada fuente del proyecto puede pertener a una o ninguna biblioteca. Debajo hay una opción más "Biblioteca por defecto" que hará que los nuevos fuentes que se creen o agreguen al proyecto se asocien directamente a esa biblioteca.

Una vez configurada la biblioteca, el flujo de trabajo en ZinjaI será el habitual. Al presionar F9 (ejecutar) ZinjaI compilará todos los fuentes, enlazará algunos de ellos en las bibliotecas, y tomará los binarios de las bibliotecas más los objetos de los fuentes restantes para construir el ejecutable final. El proceso de compilación se ve alterado entonces de dos formas. Por una lado, los fuentes que se compilan para una biblioteca requieren generalmente de un parámetro de compilación adicional (-fpic) que ZinjaI insertará automáticamente. Por otro lado, estos fuentes no se enlazan directamente en el ejecutable, sino que se enlazan en la biblioteca (un paso nuevo en el proceso de compilación del proyecto), y es la biblioteca la que se enlaza luego en el ejecutable de la misma forma que cualquier biblioteca externa. En el proceso de ejecución también hay un paso adicional en algunos casos, ya que ZinjaI modificará de ser necesario las variables PATH o LD_LIBRARY_PATH (explicadas en el tercer post de la serie) para que el ejecutable encuentre los archivos necesarios si la biblioteca generada es dinámica.

Para quien le interese el detalle, para compilar una biblioteca dinámica se utiliza gcc con el argumento "-shared", lo cual general el .dll o el .so. Muchas veces en una biblioteca dinámica vemos dos archivos, por ejemplo un .dll (con la real implementación de la biblioteca) y un .a o .lib muy pequeño que se utiliza para enlazar dentro del ejecutable, y que se encarga de la carga dinámica. En el caso de gcc/mingw no es necesario este segundo archivo ya que es capaz de tomar como entrada para el enlazado directamente al archivo .dll. Si se requiere igual , se debe utilizar un argumento adicional en el enlazado ("--out-implib,libejemplo_dll.a"), o se puede generar más tarde con la herramienta dlltool. Para generar bibliotecas estáticas no se utiliza el comando gcc, sino "ar", que lo único que hace es empaquetar como zip varios .o en un único archivo .lib o .a. Se puede construir un proyecto con ZinjaI, y luego hacer click derecho en panel de Resultados de la Compilación para obtener el conjunto exacto de instrucciones ejecutadas para construir el proyecto y la salida completa de cada una de ellas.

En la imagen, el proyecto consta de 4 archivos .cpp. La compilación se realiza en 6 pasos, uno para cada .cpp,
 uno para el enlazado de la biblioteca, y otro para el enlazado del ejecutable.

De esta forma, pueden generar su biblioteca y luego llevarla a otro proyecto para reutilizarla, tomando los archivos de cabecera que sean necesarios y ese archivo .dll, .so, .a o .lib que ZinjaI generará en la compilación. Para utilizar la biblioteca desde otro proyecto con estos archivos simplemente se siguen los pasos explicados en el post anterior.

Este post es continuación de Compilación y bibliotecas (parte 4): utilizar bibliotecas desde ZinjaI

1 comentario: