Static Libraries
A static library is compiled code that can be later used when building an executable.
When the compiler makes an executable, the basic source files are first turned in to object files. The object files are then linked together to make an executable. When we compile source code, we don't necessarily have to make an executable. We could instead group all of the object files (made from sources) in to a single file called a static library.
The library is referred to as static, because when the object files which it contains are later linked in to an executable, a copy of all the needed code in the library is added to the executable.
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.
Exchanging/Sharing variables with static library
A static library allows the direct sharing of variables by using the Common or Extern keyword, both in library code and module code.
Otherwise, 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.
Otherwise, 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.
Simple example of static library
Following is a simple example of creating a static library using these three files:
- mylib.bas - the source for the library
- mylib.bi - the header for the library
- mytest.bas - a test program
'' mylib.bas
'' compile with: fbc -lib mylib.bas
'' Add two numbers together and return the result
Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
Return( x + y )
End Function
'' compile with: fbc -lib mylib.bas
'' Add two numbers together and return the result
Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
Return( x + y )
End Function
Compile the library with:
fbc -lib mylib.bas
The -lib 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 library file, also called an archive, libmylib.a. A library might contain many modules (source files) each with many functions, but for this simple example, it is just one each.'' mylib.bi
#inclib "mylib"
Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
#inclib "mylib"
Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
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 static library that we need to link with when eventually making an executable.
'' mytest.bas
'' compile with: fbc mytest.bas
#include once "mylib.bi"
Print Add2(1,2)
'' compile with: fbc mytest.bas
#include once "mylib.bi"
Print Add2(1,2)
The #include statement tells the compiler to include the source code from mylib.bi just as if we had typed it in to the original source. With the way we have written our include file, it tells the compiler everything it needs to know about the library.
We compile this with:
fbc mytest.bas
Then when we run the mytest executable, we should get the result of:3
Following is an advanced example of creating an OOP static library using these three files:
- varZstring.bi - the header for the library
- varZstring.bas - the source for the library
- varZstringTest.bas - a test program
Header file for the library:
'' header file: 'varZstring.bi'
Type varZstring Extends ZString
Public:
Declare Constructor (ByRef z As Const ZString)
Declare Operator Cast () ByRef As ZString
Declare Operator Let (ByRef z As Const ZString)
Declare Property allocated () As Integer
Declare Destructor ()
Private:
Dim As ZString Ptr _p
Dim As UInteger _allocated
End Type
Declare Operator Len (ByRef v As varZstring) As Integer '' mandatory for the user code to call
'' the overload Len operator and
'' not the prebuilt-in Len operator
Note: Take care to declare also each overload procedure, because the absence of declaration will not necessarily lead to a compilation error if its usage in the user code is syntactically compatible with the pre-built in procedure, but the result will obviously not be as expected.Type varZstring Extends ZString
Public:
Declare Constructor (ByRef z As Const ZString)
Declare Operator Cast () ByRef As ZString
Declare Operator Let (ByRef z As Const ZString)
Declare Property allocated () As Integer
Declare Destructor ()
Private:
Dim As ZString Ptr _p
Dim As UInteger _allocated
End Type
Declare Operator Len (ByRef v As varZstring) As Integer '' mandatory for the user code to call
'' the overload Len operator and
'' not the prebuilt-in Len operator
'' library module: 'varZstring.bas'
#include "varZstring.bi"
Constructor varZstring (ByRef z As Const ZString)
If This._p <> 0 Then
Deallocate(This._p)
End If
This._allocated = Len(z) + 1
This._p = CAllocate(This._allocated, SizeOf(ZString))
*This._p = z
End Constructor
Operator varZstring.Cast () ByRef As ZString
Return *This._p
End Operator
Operator varZstring.Let (ByRef z As Const ZString)
If This._allocated < Len(z) + 1 Then
Deallocate(This._p)
This._allocated = Len(z) + 1
This._p = CAllocate(This._allocated, SizeOf(ZString))
End If
*This._p = z
End Operator
Property varZstring.allocated () As Integer
Return This._allocated
End Property
Destructor varZstring ()
Deallocate(This._p)
This._p = 0
End Destructor
Operator Len (ByRef v As varZstring) As Integer
Return Len(Type<String>(v)) '' found nothing better than this
End Operator '' (or: 'Return Len(Str(v))')
#include "varZstring.bi"
Constructor varZstring (ByRef z As Const ZString)
If This._p <> 0 Then
Deallocate(This._p)
End If
This._allocated = Len(z) + 1
This._p = CAllocate(This._allocated, SizeOf(ZString))
*This._p = z
End Constructor
Operator varZstring.Cast () ByRef As ZString
Return *This._p
End Operator
Operator varZstring.Let (ByRef z As Const ZString)
If This._allocated < Len(z) + 1 Then
Deallocate(This._p)
This._allocated = Len(z) + 1
This._p = CAllocate(This._allocated, SizeOf(ZString))
End If
*This._p = z
End Operator
Property varZstring.allocated () As Integer
Return This._allocated
End Property
Destructor varZstring ()
Deallocate(This._p)
This._p = 0
End Destructor
Operator Len (ByRef v As varZstring) As Integer
Return Len(Type<String>(v)) '' found nothing better than this
End Operator '' (or: 'Return Len(Str(v))')
'' test program: 'varZstringTest.bas'
#include "varZstring.bi" '' must contain also the overload Len operator declaration,
'' otherwise the prebuilt-in Len operator is called and applied
'' on the object variable (providing the length of its member data)
#inclib "varZstring" '' one can also put this line in the 'varZstring.bi' file
'' (and not in this file), but it seems a bit crooked
Print "VARIABLE",,, "| LEN| SIZEOF|"
Print "------------------------------------------|--------|--------|"
Dim As varZstring v = "FreeBASIC" '' adjusts memory allocation to minimum
Print "varZstring v:", "'" & v & "'",, "|"; Using "########|"; Len(v); v.allocated
Dim As ZString * 256 z
z = v
Print "Zstring z:", "'" & z & "'",, "|"; Using "########|"; Len(z); SizeOf(z)
v = z & " & SourceForge" '' only increases memory allocation if necessazy
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
v = z & " & Wiki" '' only increases memory allocation if necessazy
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
v.Constructor(v) '' readjusts memory allocation to minimum
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
Sleep
#include "varZstring.bi" '' must contain also the overload Len operator declaration,
'' otherwise the prebuilt-in Len operator is called and applied
'' on the object variable (providing the length of its member data)
#inclib "varZstring" '' one can also put this line in the 'varZstring.bi' file
'' (and not in this file), but it seems a bit crooked
Print "VARIABLE",,, "| LEN| SIZEOF|"
Print "------------------------------------------|--------|--------|"
Dim As varZstring v = "FreeBASIC" '' adjusts memory allocation to minimum
Print "varZstring v:", "'" & v & "'",, "|"; Using "########|"; Len(v); v.allocated
Dim As ZString * 256 z
z = v
Print "Zstring z:", "'" & z & "'",, "|"; Using "########|"; Len(z); SizeOf(z)
v = z & " & SourceForge" '' only increases memory allocation if necessazy
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
v = z & " & Wiki" '' only increases memory allocation if necessazy
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
v.Constructor(v) '' readjusts memory allocation to minimum
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
Sleep
Output:
VARIABLE | LEN| SIZEOF| ------------------------------------------|--------|--------| varZstring v: 'FreeBASIC' | 9| 10| Zstring z: 'FreeBASIC' | 9| 256| varZstring v: 'FreeBASIC & SourceForge' | 23| 24| varZstring v: 'FreeBASIC & Wiki' | 16| 24| varZstring v: 'FreeBASIC & Wiki' | 16| 17|
Libraries can optionally contain debugging information specified with the -g command line option.
A 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 libraries, are platform specific and in some cases specific to a particular version of the compiler and FreeBASIC runtime library.
See also:
Back to Programmer's Guide