Las librerías de programación son herramientas para hacer que el desarrollo de software sea más eficiente. Proporcionan fragmentos de código reutilizables que los desarrolladores pueden utilizar para programar de forma rápida y sencilla.
En Windows son los famosos archivos que tiene por extensión .DLL, en Linux suelen terminar su nombre en .so
Una biblioteca escrita en C, tiene un archivo de cabecera (archivo con extensión .h) el cual contiene la definición de las funciones, tipos de datos, etc. que se definen en esta librería.
Desde Free Pascal, es sencillo o relativamente sencillo hacer uso de estas bibliotecas, si se escribe un archivo de cabecera pero usando el lenguaje y la sintaxis de Free Pascal.
Contenido
Introducción
Personalmente he escrito varias cabeceras para diversas bibliotecas. Para ello me he apoyado en la Wiki de pascal, en las siguientes entradas:
Además del foro de Lazarus y Free Pascal.
Además, con lo aprendido he ido haciendo notas, que me han ayudado.
Definiendo la biblioteca.
El nombre de la librería externa se debe definir como una constante, y usar los condicionantes de compilación, por ejemplo:
1 2 3 4 5 6 7 |
const {$IFDEF MSWINDOWS} REALSENSE_DLL='realsense2.dll'; {$ENDIF} {$IFDEF LINUX} REALSENSE_DLL='realsense2.so'; {$ENDIF} |
Funciones void
Las funciones void (que no retornan nada).
1 |
void rs2_delete_context(rs2_context* context); |
Se declaran en Free Pascal como procedimientos (procedure)
1 |
procedure rs2_delete_context(context: prs2_context); cdecl; external REALSENSE_DLL; |
1 2 3 |
Las bibliotecas son declaradas como externa (<em>external</em>) y el tipo de llamada cdecl por convención. |
Funciones que retornan un puntero
Una función que retorna un punto como la siguiente:
1 |
rs2_context* rs2_create_context(int api_version, rs2_error** error); |
Es declarada como una función que devuelve un puntero.
1 2 3 4 5 6 |
type rs2_context = record end; prs2_context = ^rs2_context; (...) function rs2_create_context(api_version: integer; aerror: Pointer): prs2_context;cdecl; external REALSENSE_DLL; |
El puntero debe apuntar a un tipo de dato o estructura conocida. Pero hay veces que no es posible como la definición anterior.
Cuando la función retorna un estructura desconocida u opaca
Algunas declaraciones en C devuelve una estructura que no es conocida, o puede ser diferente dependiendo de la situación. Por ejemplo:
1 |
typedef struct rs2_context rs2_context; |
Esto, en Free Pascal, se denomina una estructura opaca, de acuerdo con el post: https://forum.lazarus.freepascal.org/index.php/topic,61311.0.html
Se declaran así:
1 2 3 4 |
type rs2_context = record end; prs2_context = ^rs2_context; |
1 |
Otra opción es usar un punto opaco. |
1 2 |
Type prs2_context=POpaqueData; |
Más información en la ayuda de Free Pascal:
- https://www.freepascal.org/docs-html/rtl/system/popaquedata.html
- https://www.freepascal.org/docs-html/rtl/system/topaquedata.html
Cuando una función es un callback
La siguiente declaración es un callback en C.
1 2 3 |
typedef struct rs2_devices_changed_callback rs2_devices_changed_callback; typedef void (*rs2_devices_changed_callback_ptr)(rs2_device_list*, rs2_device_list*, void*); |
En Pascal se debe definir de la siguiente manera:
1 2 3 4 5 |
type pRS2_devices_changed_callback = ^RS2_devices_changed_callback; RS2_devices_changed_callback = procedure (DeviceList1: pRS2_Device_List; DeviceList2: pRS2_Device_List);cdecl;external REALSENSE_DLL; |
1 2 |
Estructura con una rutina en la declaración
La siguiente estructura en C
1 2 3 4 5 6 7 8 9 10 11 12 |
typedef struct rs2_software_video_frame { void* pixels; void(*deleter)(void*); int stride; int bpp; rs2_time_t timestamp; rs2_timestamp_domain domain; int frame_number; const rs2_stream_profile* profile; float depth_units; } rs2_software_video_frame; |
En Free Pascal sería:
1 2 3 4 5 6 7 8 9 10 11 |
type Trs2_software_video_frame = record pixels: pvoid; deleter: TDeleterProc; stride: integer; timestamp: Trs2_time_t; domain: Trs2_timestamp_domain; frame_number: integer; profile: pRS2_stream_profile; depth_units: single; end; |
La línea siguiente, sería un puntero a procedimiento
1 |
void(*deleter)(void*); |
Su conversión sería:
1 2 3 |
type TDeleterProc = procedure(arg: Pointer); cdecl;external REALSENSE_DLL; |
Conversión de tipos de datos
C | Pascal | Bits |
---|---|---|
char | char | 8 bits(ascci) |
signed char | shortint | 8 bits con signo |
unsigned char | byte | 8 bits sin signo |
char | pchar | 32 bit (puntero a null-terminated string) |
short int | smalint | 16 bits con signo |
unsigned short int | word | 16 sin signo |
int | integer | 16 (o 32) bits (genérico) con signo |
unsigned int | cardinal | 16 (o 32) bits (genérico) sin signo |
float | single | 32 bits con signo |
long long int | Int64 | 64 bits con signo |
double | double | 64 bits con signo |
unsigned long long int | uInt64 | 64 sin signo |