我使用以下命令从sqlite3.c和BCC 55编译了SQLIte3数据库引擎:
bcc32.exe -jb -O2 -w- -K -c -6 -u- sqlite3.c
生成了正确的sqlite3.obj文件。但是一旦我尝试在我的Delphi应用程序中链接它,就像这样:
unit unt_SQLite3;
interface
uses
Windows;
implementation
{$LINK 'sqlite3.obj'}
end.
我收到以下错误:
[DCC Error] E2065 Unsatisfied forward or external declaration: '__ftol'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__lldiv'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__llmod'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_localtime'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_strncmp'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_memset'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__llmul'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_malloc'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_free'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_realloc'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_memcpy'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__llumod'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__lludiv'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_memmove'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_memcmp'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__llshl'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__llshr'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_atol'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_strlen'
[DCC Error] E2065 Unsatisfied forward or external declaration: '_qsort'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__llushr'
[DCC Error] E2065 Unsatisfied forward or external declaration: '__turboFloat'
为什么需要在纯pascal(或asm)中实现Borland C ++运行时函数? 不能直接在obj中链接那些? 其中一些已经在System.pas中实现,但编译器抱怨了吗?
执行此mysqlf而不是使用SynSQLite3或DIXml的理由如下:
SynSQLite3支持3.7.8(我没看到最新的3.7.9)
SynSQLite3错过了一些声明,如sqlite3_trace,sqlite_open_v2等。
在随后的20 000步操作中,SynSQLite2比DIXml 2.4.0慢约18倍
支付DISQLite3
DISQLite 2.4.0在260ms内快速完成20000步操作但不支持DXE2
DISQLite 3.0.0和3.1.0支持DXE2但比2.4.0慢8倍
我是一个非常好奇的家伙,并且总是试着尽可能接近金属编码。
对SynSQLite3和DISQLite3开发人员的称赞 - 到目前为止工作真的很好
最终我选择了SynSQLite3,因为:
这是开源
记录很清楚
我学会了如何自己重新编译sqlite3.obj,并为我需要的功能留下所需的编译开关
我可以将更新的3.7.9版本链接
随着微调最新的3.7.9 obj我达到了DISQLite3的速度
DISQLite3家伙甚至没有在他的网站上写一个电子邮件地址(只是一个邮件列表),其中SynSQLite3家伙在同一时间回复SO。选择一个lib而不是另一个lib时这是有意义的。性能和价格并非一切。
P.S。我的sqlite3.obj暂时可供下载和测试here
答案 0 :(得分:8)
看看我们的开源库。它实现了sqlite3.obj的静态链接,并使用最新版本的SQLite3官方代码进行维护(和功能 - 它是唯一允许扩展使用SQLite3虚拟表的框架)。你有一个包装器。但更重要的是。
以下是我们如何将源代码编译成.obj(一个包含FTS3,另一个没有它):
del sqlite3.obj
\dev\bcc\bin\bcc32 -6 -O2 -c -d -DSQLITE_ENABLE_FTS3 -u- sqlite3.c
copy sqlite3.obj sqlite3fts3.obj
\dev\bcc\bin\bcc32 -6 -O2 -c -d -u- sqlite3.c
然后看一下SynSQLite3.pas单元。它包含一些所需外部文件的纯pascal或asm版本。
例如:
function _ftol: Int64;
// Borland C++ float to integer (Int64) conversion
asm
jmp System.@Trunc // FST(0) -> EDX:EAX, as expected by BCC32 compiler
end;
function _ftoul: Int64;
// Borland C++ float to integer (Int64) conversion
asm
jmp System.@Trunc // FST(0) -> EDX:EAX, as expected by BCC32 compiler
end;
function malloc(size: cardinal): Pointer; cdecl; { always cdecl }
// the SQLite3 database engine will use the FastMM4/SynScaleMM fast heap manager
begin
GetMem(Result, size);
end;
procedure free(P: Pointer); cdecl; { always cdecl }
// the SQLite3 database engine will use the FastMM4 very fast heap manager
begin
FreeMem(P);
end;
function realloc(P: Pointer; Size: Integer): Pointer; cdecl; { always cdecl }
// the SQLite3 database engine will use the FastMM4/SynScaleMM very fast heap manager
begin
result := P;
ReallocMem(result,Size);
end;
function memset(P: Pointer; B: Integer; count: Integer): pointer; cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
begin
result := P;
FillChar(P^, count, B);
end;
procedure memmove(dest, source: pointer; count: Integer); cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
begin
Move(source^, dest^, count); // move() is overlapping-friendly
end;
procedure memcpy(dest, source: Pointer; count: Integer); cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
begin
Move(source^, dest^, count);
end;
function atol(P: pointer): integer; cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
begin
result := GetInteger(P);
end;
var __turbofloat: word; { not used, but must be present for linking }
// Borland C++ and Delphi share the same low level Int64 _ll*() functions:
procedure _lldiv;
asm
jmp System.@_lldiv
end;
procedure _lludiv;
asm
jmp System.@_lludiv
end;
procedure _llmod;
asm
jmp System.@_llmod
end;
procedure _llmul;
asm
jmp System.@_llmul
end;
procedure _llumod;
asm
jmp System.@_llumod
end;
procedure _llshl;
asm
jmp System.@_llshl
end;
procedure _llshr;
asm
{$ifndef ENHANCEDRTL} // need this code for Borland/CodeGear default System.pas
shrd eax, edx, cl
sar edx, cl
cmp cl, 32
jl @@Done
cmp cl, 64
jge @@RetSign
mov eax, edx
sar edx, 31
ret
@@RetSign:
sar edx, 31
mov eax, edx
@@Done:
{$else}
// our customized System.pas didn't forget to put _llshr in its interface :)
jmp System.@_llshr
{$endif}
end;
procedure _llushr;
asm
jmp System.@_llushr
end;
function strlen(p: PAnsiChar): integer; cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
begin // called only by some obscure FTS3 functions (normal code use dedicated functions)
result := SynCommons.StrLen(pointer(p));
end;
function memcmp(p1, p2: pByte; Size: integer): integer; cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
begin
if (p1<>p2) and (Size<>0) then
if p1<>nil then
if p2<>nil then begin
repeat
if p1^<>p2^ then begin
result := p1^-p2^;
exit;
end;
dec(Size);
inc(p1);
inc(p2);
until Size=0;
result := 0;
end else
result := 1 else
result := -1 else
result := 0;
end;
function strncmp(p1, p2: PByte; Size: integer): integer; cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
var i: integer;
begin
for i := 1 to Size do begin
result := p1^-p2^;
if (result<>0) or (p1^=0) then
exit;
inc(p1);
inc(p2);
end;
result := 0;
end;
function localtime(t: PCardinal): pointer; cdecl; { always cdecl }
// a fast full pascal version of the standard C library function
var uTm: TFileTime;
lTm: TFileTime;
S: TSystemTime;
begin
Int64(uTm) := (Int64(t^) + 11644473600)*10000000; // unix time to dos file time
FileTimeToLocalFileTime(uTM,lTM);
FileTimeToSystemTime(lTM,S);
with atm do begin
tm_sec := S.wSecond;
tm_min := S.wMinute;
tm_hour := S.wHour;
tm_mday := S.wDay;
tm_mon := S.wMonth-1;
tm_year := S.wYear-1900;
tm_wday := S.wDayOfWeek;
end;
result := @atm;
end;
你会发现这个单元不仅仅是SQLite3的静态链接。请注意,即使我们的mORMot ORM客户端 - 服务器框架使用它,使用SQLite3类也不需要 。请参阅this article for additional details。
如果您迷失在我们的源代码存储库中(使用优秀的FOSSIL项目),read this。
答案 1 :(得分:4)
更新:根据Arnaud的建议,您将会更好地使用SynSQLite3.pas
。但是,我在这里留下这个答案,因为它说明了一些可以用来解决静态链接时缺少依赖关系的技巧。
这里发生的是.obj文件依赖于您需要提供的各种C运行时函数。
要做的第一件事是将crtl
添加到包含uses
指令的单元的$LINK
子句中。 crtl
单元包含许多C运行时库函数的实现,专门用于此目的。
然而,当你这样做时,虽然解决了一些缺失的依赖关系,但还会出现更多依赖关系。
Unsatisfied forward or external declaration: '_lldiv'
Unsatisfied forward or external declaration: '_llmod'
Unsatisfied forward or external declaration: 'localtime'
Unsatisfied forward or external declaration: '_llmul'
Unsatisfied forward or external declaration: 'InterlockedCompareExchange'
Unsatisfied forward or external declaration: 'InitializeCriticalSection'
Unsatisfied forward or external declaration: 'Sleep'
Unsatisfied forward or external declaration: 'DeleteCriticalSection'
Unsatisfied forward or external declaration: 'EnterCriticalSection'
Unsatisfied forward or external declaration: 'LeaveCriticalSection'
Unsatisfied forward or external declaration: '_llumod'
Unsatisfied forward or external declaration: '_lludiv'
Unsatisfied forward or external declaration: 'GetVersionExA'
Unsatisfied forward or external declaration: 'MultiByteToWideChar'
Unsatisfied forward or external declaration: 'WideCharToMultiByte'
Unsatisfied forward or external declaration: 'AreFileApisANSI'
Unsatisfied forward or external declaration: 'FormatMessageW'
Unsatisfied forward or external declaration: 'LocalFree'
Unsatisfied forward or external declaration: 'FormatMessageA'
Unsatisfied forward or external declaration: 'SetFilePointer'
Unsatisfied forward or external declaration: 'CloseHandle'
Unsatisfied forward or external declaration: 'ReadFile'
Unsatisfied forward or external declaration: 'WriteFile'
Unsatisfied forward or external declaration: 'SetEndOfFile'
Unsatisfied forward or external declaration: 'FlushFileBuffers'
Unsatisfied forward or external declaration: 'GetFileSize'
Unsatisfied forward or external declaration: 'LockFileEx'
Unsatisfied forward or external declaration: 'LockFile'
Unsatisfied forward or external declaration: 'UnlockFile'
Unsatisfied forward or external declaration: 'UnlockFileEx'
Unsatisfied forward or external declaration: 'UnmapViewOfFile'
Unsatisfied forward or external declaration: 'CreateFileMappingA'
Unsatisfied forward or external declaration: 'MapViewOfFile'
Unsatisfied forward or external declaration: 'GetTempPathW'
Unsatisfied forward or external declaration: 'GetTempPathA'
Unsatisfied forward or external declaration: 'CreateFileW'
Unsatisfied forward or external declaration: 'CreateFileA'
Unsatisfied forward or external declaration: 'GetFileAttributesW'
Unsatisfied forward or external declaration: 'DeleteFileW'
Unsatisfied forward or external declaration: 'GetFileAttributesA'
Unsatisfied forward or external declaration: 'DeleteFileA'
Unsatisfied forward or external declaration: 'GetFileAttributesExW'
Unsatisfied forward or external declaration: 'GetFullPathNameW'
Unsatisfied forward or external declaration: 'GetFullPathNameA'
Unsatisfied forward or external declaration: 'GetDiskFreeSpaceW'
Unsatisfied forward or external declaration: 'GetDiskFreeSpaceA'
Unsatisfied forward or external declaration: 'LoadLibraryW'
Unsatisfied forward or external declaration: 'LoadLibraryA'
Unsatisfied forward or external declaration: 'GetProcAddress'
Unsatisfied forward or external declaration: 'FreeLibrary'
Unsatisfied forward or external declaration: 'GetSystemTime'
Unsatisfied forward or external declaration: 'GetCurrentProcessId'
Unsatisfied forward or external declaration: 'GetTickCount'
Unsatisfied forward or external declaration: 'QueryPerformanceCounter'
Unsatisfied forward or external declaration: 'GetSystemTimeAsFileTime'
Unsatisfied forward or external declaration: 'GetSystemInfo'
Unsatisfied forward or external declaration: '_llshl'
Unsatisfied forward or external declaration: '_llushr'
其中许多只是Windows API函数,可以通过将Windows
添加到您的uses子句中轻松解决。
此时,您将获得以下内容:
Unsatisfied forward or external declaration: '_lldiv'
Unsatisfied forward or external declaration: '_llmod'
Unsatisfied forward or external declaration: 'localtime'
Unsatisfied forward or external declaration: '_llmul'
Unsatisfied forward or external declaration: '_llumod'
Unsatisfied forward or external declaration: '_lludiv'
Unsatisfied forward or external declaration: '_llshl'
Unsatisfied forward or external declaration: '_llushr'
要解决这些问题,您需要:
$LINK
。我实际上并不确定这些功能是做什么的,所以你需要做更多的工作。我的猜测是这些函数是64位整数运算例程。您可以通过写入C的短位来执行各种64位算术运算来对此进行反向工程。然后使用bcc32进行编译,并将输出视为asm
。据推测bcc32
有能力发出asm
。或者你可以直接链接到Delphi单元,看看上面哪些函数对应于你在C代码中使用的操作。
你可以从localtime
中提取msvcrt.dll
,这对于缺少C运行时函数来说总是一个有用的后备选项。实际上,这就是crtl
单元当前实现的内容,因此如果您要使用crtl
,您也可以采用相同的方式localtime
。
借用Arnaud的一些代码,以下单元成功编译:
unit sqlite3;
interface
implementation
uses
crtl, Windows;
{$L c:\desktop\sqlite3.obj}
procedure _lldiv;
asm
jmp System.@_lldiv
end;
procedure _llmod;
asm
jmp System.@_llmod
end;
procedure _llmul;
asm
jmp System.@_llmul
end;
procedure _llumod;
asm
jmp System.@_llumod
end;
procedure _lludiv;
asm
jmp System.@_lludiv
end;
procedure _llshl;
asm
jmp System.@_llshl
end;
procedure _llushr;
asm
jmp System.@_llushr
end;
procedure localtime; cdecl; external 'msvcrt.dll';
end.
请注意,您不需要为任何这些函数提供参数列表,调用约定等,因为我们没有在此处实现它们。在每种情况下,代码都只是委托实现。
但是,这仍然缺少声明sqlite3函数的代码。更重要的是,我甚至没有试图测试它是否有效。成功的编译只是第一步。
如果您希望使用静态链接,我强烈建议您使用Arnaud指示您的代码。这段代码显然有很多用途和测试,你也可以从中受益。
静态链接可以方便地部署,但是对DLL的动态链接要简单得多。