¡Buen camino a todos!
La entrada anterior, de presentación de Rad Studio 10.2 Tokyo, nos permitía compartir esa primera toma de contacto con la ultima version de Delphi (y C++ Builder): pudimos aprender aspectos muy básicos para preparar nuestro servidor Linux, en esos temas de configuración; y también aprendimos qué pasos había que dar para conectarse mediante PASserver, de forma que habilitábamos la vía para importar el sdk de nuestro servidor al ambiente de desarrollo e igualmente, servía de forma bi-direccional, para tener éxito en el resto de procesos, compilación, depuración y deploy. Pudimos ver ejecutarse el típico «Hola Mundo» y por supuesto, recomendamos enlaces que podían ayudar en esos primeros pasos.

En general, todos los compañeros que compartimos la comunidad y que hemos tenido acceso a Tokyo, «andamos» peleando cada uno en sus cuitas y afanes. Hay quienes se han volcado mas en los aspectos del par Linux-DataSnap, y evalúan proyectos que tienen en mente o que han desplegado anteriormente en Windows, de cara a esa futura migración a la plataforma abierta. Creo que esa parte descubre gran interés.
En mi caso concreto, que ha veces gusto de parar en los detalles, centré mi semana en el aprendizaje de algo que despertaba mi curiosidad. ¿Como podría añadir la funcionalidad de bibliotecas Linux a mis desarrollos en este sistema operativo? ¿Sería fácil o difícil…? Era algo que me preguntaba y que a la par había compartido en el grupo de MVPs hispanos.
Y ni corto ni perezoso, me puse a investigar dando la «vara» a mis compañeros y sobrecargando de preguntas al pobre Luis Felipe, que sufre de mis ataques de curiosidad.
¿Podré añadir nuevas bibliotecas a nuestro proyecto compilado para Linux…?
Respuesta: Sí… Por supuesto… Por un lado, era evidente que lo habían hecho… lo puedes descubrir en muchas unidades del código fuente. Pero claro… reconozcamos que no es lo mismo que otros lo hayan hecho a que tenga uno que rascarse la cabeza, porque necesita utilizar una función que no se ha importado previamente.
Ahora bien, frente a lo que puedas pensar, no es mas difícil de lo que era parte homónima de Windows. El trabajo de esta semana me ha dejado esa impresión. Sí… existirán parecidos problemas, en cuanto a la correspondencia de tipos de datos, pero no hay nada mejor que llevar a la certeza de que algo es asequible que encontrar en uno la capacidad para hacerlo.
🙂
De eso va este video.
Mi plan de ataque…
Abordar cualquier problema supone (para la mayoría de nosotros), poner en práctica ese buen habito de descomponer/transformar la tarea en problemas mas pequeños que llegan a ser resolubles… Así pues, si inicialmente pensé en alguna función destacada del sdk, mas compleja, por eso del relumbre, y acabé pensando que lo mas sencillo y didáctico era crear una biblioteca propia con una sola función, de forma que la traducción de tipos, que en algún caso puede ser mas «farragosa» y distraernos del propósito real, quedara para otro momento posterior y centrarme así, exclusivamente, en la declaración de una función contenida en una librería dinámica. Ni mas. Ni menos. A fin de cuentas, si podíamos utilizar una librería creada por nosotros también podríamos hacer lo propio con otra cualquiera.
Elegí una función al azar: «Calcular el area de una esfera a partir de su radio». Como todo el mundo sabe, ese valor depende del cuadrado de su radio multiplicado por 4 Pi. Por lo tanto, debía declarar una función que tuviera como retorno un valor real, que nos devolvía su area calculada, y como parámetro de entrada su radio (un valor entero).
Así que nuestro siguiente paso, sería crear esa librería en Linux y para ello, podía usar el compilador de ese sistema operativo, por excelencia GCC, para C.
Estos son los pasos que seguí: -omito leer, leer y leer… y desempolvar algún que otro libro-
Crear la cabecera que definía el método (llamé a mi fichero «milibreria.h»).
Y seguidamente, crear el cuerpo de la función, donde se implementa el método. Nuevamente edité mediante nano, el archivo «milibreria.c».
No hay mucho que decir al respecto. Incluimos la cabecera <math.h> para poder invocar el método pow( ), que calcula el valor de un numero elevado a una potencia. Nosotros lo usamos para calcular el cuadrado del radio. PI queda definido como una constante con valor 3.1416 para simplificar.
Estoy tan acostumbrado en nuestra herramienta, a la personalidad de Delphi, a mi querido object pascal, que me resulta extraño visualizar el modulo en los dos ficheros distintos, algo inherente a otros lenguajes.
Y finalmente, nos queda el paso compilar el código objeto asociado a la unidad y su posterior enlace como librería dinámica (el atributo -shared nos advierte de este punto).
La primera llamada utiliza la opción -c que avisa al compilador de que no debe crear el fichero ejecutable sino que deseamos el fichero objeto, omitiendo el paso del enlazado. La opción -o <fichero> especifica el archivo de salida. Y -fPIC tuve que añadirla finalmente tras una advertencia inicial del compilador. Tenia una relación directa con la obtención posterior de la librería.
La segunda llamada utiliza [ld] y básicamente le estas indicando el nombre de la librería dinámica, seguida de todas los ficheros compilados obtenidos anteriormente, mas la opción -shared que le está indicando al enlazador (linker) que deseamos una librería y no un ejecutable. Por convención, las librerías dinámicas finalizan su nombre de fichero (que no extension porque este concepto no es aplicable en linux) en el sufijo [.so]. Por el contrario, utilizamos [.a] para identificar las librerías estáticas.
¡YA TENEMOS NUESTRA LIBRERIA DINAMICA: libareas.so!
¿Y ahora que…?
Para probar nuestra libreria, tal y como hicimos anteriormente, vamos a crear una aplicación de consola. Menu superior del IDE, File, Nuevo y Other. Del cuadro de dialogo semejante al de la imagen siguiente, elegiremos el tipo de proyecto Console Application o aplicación de consola.
Al aceptar creará por nosotros la estructura de la aplicación por defecto.
A esas lineas vamos a añadir algo de código. Apuntad:
program dinlibs; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; function area_esfera(radio: Integer): Double; cdecl; external 'libareas.so'; var f: Double; i: Integer; begin try { TODO -oUser -cConsole Main : Insert code here } i:= 0; WriteLn('Introduce un valor entero del radio de la Esfera...'); ReadLn(i); f:= area_esfera(i); WriteLn('El valor del area de la esfera es ' + f.ToString()); ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.
Estoy seguro que, a la vista de este código, y después de haber visto en el video que acompaña la entrada, donde se muestra que se compila y ejecuta sin problemas, no os parecerá algo complicado. Tenéis que utilizar el convenio de llamada cdecl para que los parámetros de llamada se invoquen en el orden esperado y la opción «external» + <nombre de la libreria> para indicarle al compilador donde va a enlazar la función.
Y el uso que le hemos dado, tampoco plantea demasiadas dudas. Esperamos que el usuario teclee un valor entero que haremos corresponder al radio de la esfera. Y la invocación de la función importada, area_esfera, nos devuelve el valor calculado de la area, mostrándolo finalmente.
Consideraciones…
Intentad ejecutar el código… ¡ahhhhh! ¡Genera un error!
En la parte de compilación, Delphi nos avisará que no encuentra area_esfera, dado que todavía no le hemos indicado donde tiene que buscar la librería.
Para solucionar este problema, basta añadir en el area de configuración del sdk, la ruta local al servidor Linux. Usaremos el asterisco (*) para indicar que deseamos todo el contenido de esa carpeta y finalmente, hacemos check si deseamos incluir subdirectorios.
Y click en Update Local File Cache, para que se actualice la cache local de nuestro ambiente de desarrollo. En la imagen posterior podéis ver estos detalles.
A partir de ese momento, nuestro compilador encontrará la librería y podrá compilar.
La parte de la ejecución también necesita una consideración previa. Ya no tenemos el error de compilación pero… si intentaremos ejecutar la aplicación recibiríamos una advertencia similar a esta:
El motivo es que, aunque es capaz de compilar, la librería es enlazada dinámicamente y por lo tanto, si no la encuentra en el destino, emergerá un error advirtiendo de este problema. En la imagen, el terminar de nuestro server nos dice que no encuentra la librería «libareas.so«.
Y aquí entra en juego el deployment o deploy. Delphi nos lo hace fácil. Menu superior, Project, Deployment y visualizaremos una ventana acoplada donde se nos muestra que archivos deben ser sincronizados en destino.
Le indicamos la ruta actual de nuestra librería en la columna LocalPath (hace referencia a su ubicación en windows), e indicamos, igualmente donde debe copiarla en la maquina remota (Remote Path), identificado con el [.\] que se muestra en la imagen, y que identifica la carpeta que va a ser creada dentro de [scratch-dir], ligada a la estructura de PAServer en nuestro servidor.
Ejecutamos ahora la aplicación y deberíamos ver, en la zona de mensajes inferior, la ejecución de las lineas que mostrará en el terminal, pidiendo que se introduzca el valor del radio de la esfera. Y para acabar, simplemente recordar que en función del tipo de librería, o modulo añadido, si ésta ya está instalada en el sistema o si no lo está, si es localizable porque ha existido previamente una instalación mediante paquetes, deberemos hacer uso del deploy y seleccionar adecuadamente la ruta remota. No siempre va a ser necesario.
Espero que os haya gustado la entrada y me despido deseando que paséis una buena semana de Pascua.
Sed felices.
Excelente artículo, muy detallado el manual, de hecho servirá a muchas personas con deseos de aprender.
Me gustaMe gusta
Interesante….aun cuando se pudo escribir el códico de «milibreria» en pascal ….y ahorrarnos todo el tema de c….verdad?
Me gustaMe gusta