共享库是编译代码,可以在运行可执行文件时稍后加载和使用。
当编译器生成可执行文件时,首先将基本源文件转换为对象文件。然后将对象文件链接在一起以生成可执行文件。一个共享库就像一个静态库,它包含对象文件。但是共享库也是一个可执行文件,它只在可执行文件运行时才被加载。
该库被称为共享,因为库中的代码在运行时由可执行文件加载,并且可以由多个可执行文件加载,即使可能只有一个共享库的副本。
图书馆制作完成后,我们可以使用它所包含的代码,就像我们直接使用我们的程序编译源代码一样。
共享库示例
在Windows上使用共享库
在Linux上使用共享库
导出符号的可执行文件
动态加载共享库
共享库示例
以下是使用这三个文件创建共享库的简单示例:
- mylib.bas - 图书馆的来源
- mylib.bi - 库的标题
- mytest.bas - 一个测试程序
我们的库将是提供单一功能的单个模块:
'' mylib.bas
'' compile with: fbc -dll mylib.bas
'' Add two numbers together and return the result
Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer Export
Return( x + y )
End Function
使用以下方式编译库:
fbc -dll mylib.bas
-dll选项指示编译器使用源代码
mylib.bas,并将其转换为对象文件
mylib.o,然后将对象文件存储到共享库中。共享库的名称将具有
.so扩展名或
.dll扩展名,具体取决于该平台是linux还是windows版本。一个库可能包含许多具有许多功能的模块(源文件),但是对于这个简单的例子,它只是一个。
制作一个共享库与添加
Export声明说明符之外的静态库几乎相同。
Export告诉编译器使该函数对其他可执行文件加载共享库可见。
为了在某??些其他源代码中使用库,我们需要一些告诉编译器在库中究竟是什么的方法。一个很好的方法是将库的声明(也称为接口或API)放入头文件中。
'' mylib.bi
#inclib "mylib"
Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
没有必要编译头文件。我们希望它的源代码,所以它可以包含在其他源文件。
#inclib语句将告诉编译器需要在运行时运行可执行文件时需要链接的共享库的名称。
使用我们的库(.dll / .so文件)和一个标题(.bi文件),我们可以在测试程序中尝试:
'' mytest.bas
'' compile with: fbc mytest.bas
#include once "mylib.bi"
Print Add2(1,2)
#include语句告诉编译器将来自
mylib.bi的源代码,就好像我们已经将其输入原始源。通过我们编写我们的包含文件的方式,它告诉编译器需要知道的关于库的一切。
我们用:
fbc mytest.bas
那么当我们运行
mytest可执行文件时,我们应该得到以下结果:
3
制作库时可以使用多个源模块。并且基本程序可以通过包括每个所需的标题来使用多个库。一些库是如此之大,以至于可能使用几个标题。在非常大的项目中,使得很少变更的代码模块中的共享库可以大大提高编译时间和链接时间。
共享库可以选择包含使用
-g 命令行选项指定的调试信息。
对象文件,因此共享库是特定于平台的,在某些情况下特定于编译器和FreeBASIC运行时库的特定版本。
在Windows上使用共享库
在Windows上,共享库必须存储在需要运行时的可执行文件所在的位置。
操作系统可以搜索以下目录:
- 加载可执行文件的目录。
- 当前目录。
- Windows和Windows系统文件夹。
- 目录列表中的PATH环境变量。
搜索目录的顺序可能取决于所使用的Windows版本以及操作系统配置的设置。
在Linux上使用共享库
默认情况下,Linux通常不会搜索当前目录或可执行文件所在的目录。您将需要:
- 将.so文件复制到具有共享库的目录(例如,/usr/lib),并运行ldconfig配置库。
- 修改环境变量LD_LIBRARY_PATH以搜索当前目录或新创建的共享库的特定目录。
要运行可执行文件
./mytest/并临时告诉linux搜索当前目录,请使用以下shell命令:
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./mytest
导出符号的可执行文件
动态加载共享库
可以在运行时通过在运行时动态加载库及其符号来加载和使用共享库。
共享库中的过程必须使用
Export说明符来确保符号名称位于共享库的导出表中。
'' 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().
Function AddNumbers Alias "AddNumbers"( ByVal a As Integer, ByVal b As Integer ) As Integer Export
Function = 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 just "mydll" as library file name; this is to ensure
'' compatibility between Windows and Linux, where a dynamic library
'' has different file name and extension.
Dim As Any Ptr library = DyLibLoad( "mydll" )
If( library = 0 ) Then
Print "Failed to load the mydll dynamic library, aborting program..."
End 1
End If
'' This function pointer will be used to call the function from mydll, after
'' the address has been found. Note: It must have the same calling
'' convention and parameters.
Dim AddNumbers As Function( ByVal As Integer, ByVal As Integer ) As Integer
AddNumbers = DyLibSymbol( library, "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, but we can also force unloading 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 application to crash.
DyLibFree( library )
参考