静态库 (Static Libraries)
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgStaticLibraries
- 最后更新: 2021-10-04
静态库是编译后的代码,可以在构建可执行文件时使用。
当编译器生成可执行文件时,基本源文件首先转换为目标文件,然后将目标文件链接在一起生成可执行文件。编译源代码时,不一定非要生成可执行文件。可以将所有目标文件(由源文件生成)组合到一个称为静态库的单一文件中。
该库之所以称为静态库,是因为当它所包含的目标文件随后被链接到可执行文件中时,库中所有需要的代码副本都会被添加到可执行文件中。
一旦创建了静态库,我们就可以像直接将源代码与程序一起编译一样使用其中的代码。
与静态库交换/共享变量
静态库允许通过在库代码和模块代码中同时使用 Common 或 Extern 关键字来直接共享变量。
否则,将参数(按值或按引用)传递给库过程,或从库函数返回变量(按值或按引用),可以间接地与共享库交换数据(按值)或共享数据(按引用)。
静态库简单示例
以下是使用三个文件创建静态库的简单示例:
mylib.bas- 库的源代码mylib.bi- 库的头文件mytest.bas- 测试程序
我们的库将是一个提供单一函数的模块:
start GeSHi
'' mylib.bas
'' 编译命令:fbc -lib mylib.bas
'' 将两个数字相加并返回结果
Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
Return( x + y )
End Functionend GeSHi
使用以下命令编译库:
fbc -lib mylib.bas
-lib 选项告诉编译器获取源代码 mylib.bas 并将其转换为目标文件 mylib.o,然后将目标文件存储到库文件(也称为存档文件)libmylib.a 中。一个库可能包含许多模块(源文件),每个模块有许多函数,但在这个简单示例中各只有一个。
要在其他源代码中使用库,我们需要某种方式告诉编译器库中确切包含什么内容。一个好方法是将库的声明(也称为接口或 API)放入头文件:
start GeSHi
'' mylib.bi
#inclib "mylib"
Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integerend GeSHi
头文件无需编译。我们希望以源代码形式保存它,以便与其他源文件一起包含。#inclib 语句将告诉编译器最终生成可执行文件时需要链接的静态库名称。
有了库(.a 文件)和头文件(.bi 文件),我们可以在测试程序中试用它们:
start GeSHi
'' mytest.bas
'' 编译命令:fbc mytest.bas
#include once "mylib.bi"
Print Add2(1,2)end GeSHi
#include 语句告诉编译器将 mylib.bi 中的源代码包含进来,就像我们直接将其输入到原始源文件中一样。按照我们编写包含文件的方式,它告诉编译器关于该库所需的一切。
我们使用以下命令编译:
fbc mytest.bas
然后运行 mytest 可执行文件,应该得到以下结果:
3OOP 静态库高级示例
以下是使用三个文件创建 OOP 静态库的高级示例:
varZstring.bi- 库的头文件varZstring.bas- 库的源代码varZstringTest.bas- 测试程序
编译库的方法与上述相同,然后编译并执行测试程序。
库的头文件:
start GeSHi
'' 头文件:'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 '' 用户代码必须声明此项才能调用
'' 重载的 Len 运算符而非
'' 内置 Len 运算符end GeSHi
注意:还要注意声明每个重载过程,因为缺少声明不一定会导致编译错误(如果用户代码中的用法在语法上与预置过程兼容),但结果显然不会如预期。
库的源文件:
start GeSHi
'' 库模块:'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))')end GeSHi
测试程序文件:
start GeSHi
'' 测试程序:'varZstringTest.bas'
#include "varZstring.bi" '' 必须包含重载 Len 运算符的声明,
'' 否则将调用内置 Len 运算符并应用于
'' 对象变量(返回其成员数据的长度)
#inclib "varZstring" '' 也可以将此行放入 'varZstring.bi' 文件中
'' (而不是放在此文件中),但这样做有些别扭
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
Sleepend GeSHi
输出:
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|创建库时可以使用多个源模块。基本程序可以通过包含每个所需的头文件来使用多个库。有些库非常大,可能使用多个头文件。在大型项目中,将很少更改的某些代码模块制作为库可以显著缩短编译时间。
库可以选择性地包含用 -g 命令行选项指定的调试信息。
库可以选择性地包含模块构造函数、主代码和模块析构函数。模块构造函数和主代码在库加载时执行,模块析构函数在库卸载时执行。
目标文件(因此也包括库)是特定于平台的,在某些情况下还特定于编译器和 FreeBASIC 运行时库的特定版本。
参见
- 共享库
#inclib#include- 编译器选项:-lib
- 编译器选项:-static
返回 目录