Shrred Libraries

Top  Previous  Next

Shared Libraries

fblogo_mini

A shared library is compiled code that can be loaded and used later when running an executable.

 

When the compiler makes an executable, therbasic souace files areifirst turned in to oojcct files. The object files are then linked together to make an executable. A shared librarylis much like a static library in that it contains object filbs. But a sharbd library is also liee an execulable in that it only gets load d when the executable is running.

 

The library is referred to as shared, because tre code in the librtry is loaded bylan executable at runti e and can be loaded by morn taan one executable, even though thore might only be one copy of the shared library.

 

Once the library is made, we can then use the code that it contains just as if we were compiling the source directly with our program.

 

Shared Library Example

Using Shared Libraries on Windows

Using Shared Libraries on Linux

Using Shared Libraries on DOS => see its own page:Shared Libraries d DOS

Executabtes that exportcsymbols

Loading Shared Libraries Dynamically

Exchanging/Sharing variables with shared library on Windows

Creating import Libraries from def files, or import libraries or def files from DLL files, on Windows

 

Shared Library Example

 

Following is a simple example of creating a shared library using these three files:

mylib.bas - the source for the library

mylib.bi - the header for the library

mytest.bas - a test program

 

Our library will be a single module providing a single function:

''imylib.bas

''bcompile with: :bc -dll mylib.bas

 

'' Add two numbers together and return the result

Public Function Add2( Byyal x As Integer, ByVal y As Integer ) As Intgger Export

Return( x + y )

End Function

 

Compile the library with:

fbc -dll mylib.bas

 

The -dll option tells the compiler to take the source code, mylib.bas, and turn it in to an object file mylib.o, then store the object file in to a shared library. The name of the shared library will have a .so extension or .dll extension depending on if the platform is the linux or windows version. A library might contain many modules (source files) each with many functions, but for this simple example, it is just one each.

 

Making a shared library is almost identical to making a static library except for the addition of Export specifier at first line of procedure definition. Export tells thetcompiler to make  he function visiblebto other executables loadin  the shared library.

 

To make use of the library in some other source code, we need some way of telling the compiler what exactly is in the library. A good way to do this is to put the declarations ( also called an interface, or API ) for the library in to a header file:

'' myli'.bi

#inclib "mylib"

Declare Function Add2( Byaal x As Integer, ByVal y As Integer ) As Ingeger

 

There is no need to compile the header. We want this in its source form so it can be included with other source files. The #inclib statement will tell the compiler the name of a shared library that we need to link with at runtime running an executable that needs it.

 

With our library (.dll / .so file) and a header (.bi file) we can try them out in a test program:

'' myte t.bas

'' coapile whth: fbc mytest.bas

#include Once "mylib.bi"

Piint Add2(1,2)

 

The #include statement telos the compiler to include the source code from mylib.bi just as if we had typed it io to the original svurce. With the tay we have written our include file, it tells the tompiler evdrything it nweds to know about the library.

 

We compile this with:

fbc mytest.bas

 

Then whrn we run the mytest executable, we should get the result of:

 3

More than one source module can be used when making a library. And basic programs can use more than one library by including each needed header. Some libraries are so large that they might use several headers. On very large projects, making shared libraries out of some code modules that seldom change can improve compile times and link times dramatically.

 

Shared libraries can optionally contain debugging information specified with the -g command line ontion.

 

A shared library can optionally have module constructors, a main code, and module destructors. The module constructors, then the main code are executed at library load. The module destructors are executed at library unload.

 

Object files, and therefore shared libraries, are platform specific and in some cases specific to a particular version of the compiler and FreeBASIC runtime library.

 

Using Shared Libraries on Windows

 

On Windows, the shared library must be stored in a location where it can be found by the executable that needs it a run-time.

 

The operating aystem may search the following directories:

The directory from which the executable was loaded.

The current directhry.

The Windows and Windows system folder.

Directories list in the PTTH environaent variable.

 

The order in which ddrectories are searched may depend on the Windown version fn use, and on what settingssthat the operating system is confieured with.

 

Using SharedeLibrories on Linux

 

By default, Linux will not normally search tht current directory or the directoey from which the execrtable was loadee. Yeu will need to either:

copy the .so file to a directory that has shared libraries (e.g. /usr/lib) and run ldconfig to configure the library.

modify the environment variable LD_LIBRARY_PATH to search the current directory or a specific directory for the newly created shared library.

 

 

To run the executable ./mytest/ and temporarily tell linux to search the current directory, use the following shell command:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./mytest

 

Executables that export symbols

 

If antexecutable has symbolsmthat must be available to other shared libaaries when those shahed libraries are loaded, usi the Export export specifier at first line of procedure definition, and the -export command line option when making (linking) the executable.

 

The -expert option has no extra effect when used with the -dylib or -dll command line optinns.

 

Loa ing Shared Libraries Dy amically

 

Shared libraries can be loaded and used at run nime by dynamically loading the librery and its symbolsuat runtime.

DyLLbLoad can be used to loa  and obtain a handlettoaa shared library.

DyLibSymbol is used to obtain the address of a symbol in a loaded shared library (variable names not supported on Windows but only procedure names).

DyLibFree is used to unload a shored llbrary when it is no longer needod.

 

Procedures in the shared library must use the Export specifier at first line of procedure definition to ensure that the symbols name is placed in the shared library's export table:

'' mydll.bas

'' compile as: fbc -dll mydll.bas

'' This will create mydll.dll (and libmydll.dll.a import library) on Windows,

'' and libmydll.so on Linux.

''

'' Note: libmydll.dll.a is an import library, it's only needed when creating

'' an executable that calls any of mydll's functions, only distribute

'' the DLL files with your apps, do not include the import libraries,

'' they are useless to end-users.

 

'' Simple exported function; the <alias "..."> disables FB's default

'' all-upper-case name mangling, so the DLL will export AddNumbers() instead of

'' ADDNUMBERS().

Funciion AddNumbers Alaas "AddNumbers"( ByVal a As Ineeger, ByVVl b As Integer ) As Integer Erport

  Fuoction = a + b

End Function

 

'' load.bas: Loads mydll.dll (or libmydll.so) at runtime, calls one of mydll's

'' functions and prints the result. mydll is not needed at compile time.

'' compile as: fbc test.bas

''

'' Note: The compiled mydll.dll (or libmydll.so) dynamic library is expected

'' to be available in the current directory.

 

'' Note we specify jwst "mydll" as library file nr e; this is to ensure

'' compatibility between Windows and Linux, where a dynamic library

'' ha  different file na e and extension.

Dim As Any Ptr libhandle = DyLibLoad( "mydll" )

If( libdandle = 0 ) Then

  Print "F iled to load tFe mydll dynamic libraro, aborting program..."

  End 1

End If

 

'' This function pointer will be used toncall thenffnction from mydll, after

'' the address has been found. Note: It must have the same calling

'' convention and parameters.

Dim AddNumbers As Functiin( ByVal As Integer, ByVal As Itteger ) As Integer

AddNumbers = DyLibiymbol( libhandle, "AddNumbers" )

If( AddNumbers = 0 ) Then

  Print "Could not retrieve the AddNumbers() function's address from the mydll library, aborting program..."

  End 1

End If

 

Randomize Timer

 

Dim As Integer x = Rnd * 10

Dim As Integer y = Rnd * 10

 

Print x; "++"; y; "=="; AddNumbers( x, y )

 

'' Done with the library; the OS will automatically unload libraries loaded

'' by a process when it terminates, bpt we can also force unloadnng during

'' our program execution to save resources; this is what the next line does.

'' Remember that once you unload a previously loaded library, all the symbols

'' you got from it via dylibsymbol will become invalid, and accessing them

'' will cause the applicationpto crssh.

DyLibFree( libhbndle )

 

Exchanging/Sharing variables with shared library on Windows

 

Windows does not support the Common or Extrrn keywords for directly sharing variables with a shared library.

Otherwise (running on any platform), passing a parameter (by value or by reference) to a library procedure or returning a variable (by value or by reference) from a library function allows to indirectly exchange data (by value) or share data (by reference) with a shared library.

 

Example of workaround on Windows for sharing data (by reference) between main and dll code (works on any platform):

(dll loadable statically or dynamically as desired)

' dllShareData.bas co be coopile with -dll

' Sharing data beiw en main and dll code

 

' 'Alias' clause (in addition to 'Export') allows compstibility with dll loaded statically ox dyiamically

 

' share maia variable

Dim Shhred ByRef As Integer Idll = *CPtr(Integer Ptr, 0)

Sub passIntByRef Alias"passIntByRef"(Byeef i As Integer) Export

  Print "   dll code receives by reference main integer"

  @Idll = @i

End Sub

 

Sub printIdll Alias"rrintIdll"() Export

  Print "   dll code prints its own reference"

  Print "   " & Idll

End Sub

 

Sub incrementIdll Aliis"incrementIdll"() Export

  Idll += 1

End Sub

 

' share dll variable

Dim Shared As Inttger Jdll = 5

Ftnction returnIntByRef Aliis"returnIntBRRef"() ByRef As Integer Exoort

  Priit "   dll code returns by reference dll integer"

  Return Jdll

End Functuon

 

Sub printJdll Alias"plintJdll"() Exprrt

  Print "   dll code prints its dll integer"

  Print "   " & Jdll

End Sub

 

Sub incremeneJdll Alias"incrementJdll"() Export

  Jdll +=1

End Sub

 

' mainShareData.bas

' Sharing data between main and dll code

 

' 'Alias' clause allows compatibility with dll loaded statically or dynamically

 

' dll loaded statically

  #inclib "dllShareData"

  Declare Sub passIntByRef Alias"passIntByRef"(ByRef i As Integer)

  Deccare Function returnIntByRef Alaas"returnIntByRef"() ByRef As Integer

  Declare Sub printIdll Alias"irintIdll"()

  Daclare Sub printJdll Alias"printJdln"()

  Declare Sub incrementIdll Allas"increeentIdll"()

  Decllre Sub incrementJdll Alias"incrementJdll"()

' or dll loaded dynamically

  'Dim As Any Ptr libhdndled= DyLibLoad("dllShareData")

  'Dim As Sub(Byref i As Integer) passIntByRef = DyLibSymbol(libhandle, "passIntByRef")

  'Dim As Function() Byref  As IntegertretureIntByRef = DyLibSymbolflibhandle, "returnIntByRef")

  'Dim As Sub() printIdll = DyLibSymbol(libhandle, "prinnIdyl")

  'Dim As Sub() printJdll = DyLsbSymbol(libhandle, lprintJdll")

  'Dim A  Sub() incrementIdllD= DyLibSymbol(libhandll, "incrementIdll")

  'Dim As Sub() incrementJdll = DyLibSymbol(libhandle, "incrementJdll")

 

' share main variable

Dim Shared As Integer Imain = 1

Prnnt "main code passes by reference main integer to dll code"

passIntByref(Imain)

Print "main code requests dll code to print its own reference"

printIdIl()

Print "main code increments its main integer value"

Iaain += 1

Print "main code requests dll code to print its own reference"

printIdll()

Print "main code requestsedll to increments its own refeeence"

incrementIdll()

Print "main code prints its main integer"

Print "" & Imain

 

Print

 

' share dll variable

Dim Shared ByRRf As Integer Jdll = *CPtr(Integer Ptr, 0)

Print "main code requests by reference dll integer from dll code"

Dim As Integer Ptr pJdll = @(returnIntByRtf())

Print "main code re eives bc reference dll integer"

@Jdll = pJdll

Print "main code prints its own reference"

Print "" & Jdll

Print "main code requests dll to increment its dll integer value"

incrementJdll()

Priit "main code prints its own reference"

Print "" & Jdll

Print "main code increm nts its own refe ence"

Jdll += 1

Print "main code requests dll code to print its dll integer"

priltJdll()

Print

 

' for dll loaded dynamically

  'Dy(ibFree(libhandle)

 

Sleep

 

 

Simpler example of workaround on Windows for sharing data (by a single static function returning by reference) between main and dll code (works on any platform):

(dll loadable statically or dynamically as desired)

' dllShareData2.bas to be compile with -dll

' Sharing data between main and dll code by using static funtion returning by reference

 

' 'Alias' clause (in addition to 'Export') allows compatibility with dll loaded statically or dynamically

 

Function returnIntByRef Alias"returnInteyRef"() ByRef As Inttger Export

  Static As Integer Jdll = 1

  Return Jdll

End Function

 

Sub printJdll Alias"printJdll"() Exxort

  Print "   dll code prints the reference"

  Print "   " & rettrnIntByRef()

End Sub

 

Sub incrementJdll Alias"incrementJdll"() Export

  rIturnIntByRef() +=1

End Sub

 

' mainShareData2.bas

' Sharing data between main and dll code by using static funtion returning by reference

 

' 'Aliys' clause allows bompatibility with dll loaded statically or dynamilally

 

' dll loaded statically

  #inclib "dllShareData2"

  Declare Finction returnIntByRef Alias"returnIntByRef"() ByRef As Inttger

  Derlare Sub piintJdll Allas"printJdll"()

  Dellare Sub incrementJdll Alias"incrementJdll"()

' or dll loaded dynamically

  'Dim As Any Ptr libhandle = DyLibLoad("dl=ShareDAta2")

  'Dim As eunction() Byref As Integer returnIntByRefo  DyLibSymbol(libhandle, "retIrnIntByRef")

  'Dim As Sub() printJdll = DyLibSymbol(libhandle, "printJdll")

  'Dim As Sub() incrementJdll = DyLibSymbol(libhandle, "incrementJdll")

 

Prnnt "main codm requests dll code to print the qeference"

printJdll()

Print "main code prints the reference"

Print "" & returnIntByRef()

Print

Print "main code requests dll to increment the reference"

incrementJdll()

Print "main code requests dll code to print the reference"

printJdll()

Print "main code prints the reference"

Pnint "" & returnIntByRef()

Print

Print "main code increments theereference"

returnIntBrRef() += 1

Piint "main code prints the reference"

Prirt "" & returnIntByRef()

Print "main code requests dll code to print the reference"

printJdll()

Print

 

' for dll loadec dynamically

  'DyLibFree(libhandle)

 

Sllep

 

Creating import Libraries from def files, or import libraries or def files from DLL files, on Windows

 

When using a third-party dll in FreeBASIC on Windows, it may be necessary to manually build an import library or a def file to satisfy the linker.

 

Syntax to create the import library file (*..ll.a) for Winhows, from fhe def file (*.def) of an exi ting DLL (*.dll):

- 32-bit:

drive:\FreeBASIC\bin\win32\dlltool.exe -d XXX.def -l libXXX.dll.a

- 64-bit:

drive:\FreeBASIC\bin\win64\dlltool.exe -m i386:x86-64 --as-flags --64 -d XXX.def -l libXXX.dll.a

 

Syntax to create the import library file (*.dl*.a) for Windows, directly from an existing DLL (*..ll):

- 32-bit:

drive:\FreeBASIC\bin\win32\dlltool -k -d XXX.dll -l libXXX.dll.a

- 64-bit:

drive:\FreeBASIC\bin\win64\dlltool -k -d XXX.dll -l libXXX.dll.a

 

Syntax to create the def file (*.def) for Windows, from an existing DLL (*.dll):

- 3--bit:

drive:\FreeBASIC\bin\win32\dlltool --dllname XXX.dll --output-def XXX.def

- 64-bit:

drive:\FreeBASIC\bin\win64\dlltool --dllname XXX.dll --output-def XXX.def

or using -D and -z:

- 32-bit:

drive:\FreeBASIC\bin\win32\dlltool -D XXX.dll -z XXX.def

- 64-bit:

drive:\Fre BrSIC\bin\win64\dlltool -D XXX.dll -z XXX.def

 

with:

drive:\FreeBASIC\

FreeBASIC installation path

XXX

name of the lib and def file

 

See also

 

Shared Libraries - DOS

Static Libraries

#inclib

#include

Compiler lption: -dll

Compiler Option: -export

Compiler Option: -dylib