Yes, what the compiler and linker does.
I meant runtime resolving.
You misunderstand. If you structure things correctly then you can either present the library as a unit for static linkage (i.e. resolved by the compiler and linker) or as an object for dynamic linkage (with the library location as a parameter when the object is instantiated).
The syntax at the point of invocation is identical.
Sorry, but i do not understand, what do you mean by correctly structured. I think i will illustrate my setup and then you can pinpoint the error in my approach.
First, the original C unit,
example.c, which is also the C library:
#ifndef _EXAMPLE_C
#define _EXAMPLE_C
int example(int whatever)
{
return whatever + 1;
}
#endif
Then, it's Pascal equivalent,
example.pas:
unit example;
{$mode objfpc}{$H+}
interface
function example(whatever: integer): integer;
implementation
function example(whatever: integer): integer;
begin
result := whatever + 1;
end;
end.
Then, the C header file for
libexample.so (compiled from
example.c),
example.h:
#ifndef _EXAMPLE_H
#define _EXAMPLE_H
#ifdef LIBEXAMPLE_MANUAL_LINKING
#include <dlfcn.h>
#include <stdlib.h>
#endif
#ifdef LIBEXAMPLE_MANUAL_LINKING
#define LIBEXAMPLE_EBADPTR 1
#define LIBEXAMPLE_EDLOPEN 2
#define LIBEXAMPLE_EDLSYM 3
typedef int (*example_t)(int);
example_t example;
int open_libexample(void **libhnd_out)
{
void *libhnd;
if (libhnd_out == NULL)
{
return LIBEXAMPLE_EBADPTR;
}
libhnd = dlopen("libexample.so", RTLD_NOW | RTLD_GLOBAL);
if (libhnd == NULL)
{
return LIBEXAMPLE_EDLOPEN;
}
example = (example_t)dlsym(libhnd, "example");
if ((example == NULL))
{
dlclose(libhnd);
return LIBEXAMPLE_EDLSYM;
}
*libhnd_out = libhnd;
return 0;
}
#else
extern int example(int whatever);
#endif
#endif
And finally, the Pascal unit for the library (roughly the equivalent of the C header),
example.pp:
unit example;
{$mode objfpc}{$H+}
interface
{$ifdef LIBEXAMPLE_MANUAL_LINKING}
type
PLibHandle = ^TLibHandle;
const
LIBEXAMPLE_EBADPTR = 1;
LIBEXAMPLE_EDLOPEN = 2;
LIBEXAMPLE_EDLSYM = 3;
type
Texample = function (whatever: integer): integer; cdecl;
var
example: Texample;
function open_libexample(libhnd_out: PLibHandle): integer;
{$else}
{$LinkLib c}
function example(whatever: integer): integer; cdecl; external 'libconfparse';
{$endif}
implementation
{$ifdef LIBEXAMPLE_MANUAL_LINKING}
uses DynLibs;
function open_libexample(libhnd_out: PLibHandle): integer;
var libhnd: TLibHandle;
begin
if (libhnd_out = nil) then
begin
result := LIBEXAMPLE_EBADPTR;
exit;
end;
libhnd := LoadLibrary('libexample.so');
if (libhnd = DynLibs.NilHandle) then
begin
result := LIBEXAMPLE_EDLOPEN;
exit;
end;
example := Texample(GetProcedureAddress(libhnd, 'example'));
if ((example = nil)) then
begin
FreeLibrary(libhnd);
result := LIBEXAMPLE_EDLSYM;
exit;
end;
libhnd_out^ := libhnd;
result := 0;
exit;
end;
{$endif}
end.
I link the program using the header/library unit by dynamically linking to the library. Either by manually (
-DLIBEXAMPLE_MANUAL_LINKING/
-dLIBEXAMPLE_MANUAL_LINKING), or automatically (
-lexample for C and Pascal does the job for me).
The original Pascal unit is usable, as the procedure will not collide with the unit. The for-library version on the other hand do (at least in the case of manual linking), because the procedure there is defined as a variable to make it possible to resolve it manually. And this was solved by TRon's suggestion (thanks again), to rename the variable to
example_wrap, resolve that and provide a wrapper function:
function example(whatever: integer): integer;
begin
result := example_wrap(whatever);
end;
What would you do differently?