Shrred Libraries |
Top Previous Next |
Shared Libraries 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.
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
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
' 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()
' 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 "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 "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()
' 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
|