链接sqlite3.obj会发出不满意的前向声明错误

Ive*_*aev 8 delphi sqlite linker delphi-xe

我使用以下命令从sqlite3.c和BCC 55编译了SQLIte3数据库引擎:

bcc32.exe -jb -O2 -w- -K -c -6 -u- sqlite3.c
Run Code Online (Sandbox Code Playgroud)

生成了正确的sqlite3.obj文件.但是,一旦我尝试在我的Delphi应用程序中链接它,如下所示:

unit unt_SQLite3;

interface

uses
  Windows;

implementation

{$LINK 'sqlite3.obj'}
end.
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

[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'
Run Code Online (Sandbox Code Playgroud)

为什么需要在纯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,因为:

  1. 它是开源的

  2. 它有很好的记录

  3. 我学会了如何自己重新编译sqlite3.obj,并为我需要的功能留下所需的编译开关

  4. 我可以链接更新的3.7.9版本

  5. 通过微调最新的3.7.9 obj,我达到了DISQLite3的速度

  6. DISQLite3的家伙甚至没有在他的网站上写一个电子邮件地址(只是一个邮件列表),其中SynSQLite3家伙在同一时间回复SO.选择一个lib而不是另一个lib时这是有意义的.性能和价格并非一切.

SQLite3配置文件结果

PS我sqlite3.obj是temporaly可供下载和测试在这里

Arn*_*hez 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
Run Code Online (Sandbox Code Playgroud)

然后看看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;
Run Code Online (Sandbox Code Playgroud)

你会发现这个单元不仅仅是SQLite3的静态链接.请注意,即使我们的mORMot ORM客户端 - 服务器框架使用它,也不需要使用此ORM 来使用SQLite3类.请参见本文的其他细节.

如果您迷失在我们的源代码存储库中(使用伟大的FOSSIL项目),请阅读此内容.

  • 很高兴看到我自己的关于SQLite3静态链接的代码在`FireDac`库中被重用(当然没有版权说明!) - 现在包含在某些版本的Delphi中!所有上述代码几乎都是这样集成的,甚至是我优化的QuickSort()版本.:)如果他们确实根据许可条款的要求对Synopse进行了引用...... :( (2认同)