Delphi 链接sqlite3.obj会发出未满足的前向声明错误

Delphi 链接sqlite3.obj会发出未满足的前向声明错误,delphi,sqlite,linker,delphi-xe,Delphi,Sqlite,Linker,Delphi Xe,我使用以下命令从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]

我使用以下命令从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的原因如下:

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'
  • SynSQLite3支持3.7.8(我没有看到最新的3.7.9)

  • SynSQLite3遗漏了一些声明,如sqlite3\u跟踪、sqlite\u open\u v2等

  • 在随后的20000步操作中,SynSQLite2的速度大约是dixml2.4.0的18倍

  • DISQLite3是付费的

  • DISQLite 2.4.0是fast,以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的家伙在同一个小时回复。当选择一个库而不是另一个库时,这是有意义的。性能和价格不是一切


  • 另外,My sqlite3.obj暂时可供下载和测试

    更新:按照Arnaud的建议,使用
    SynSQLite3.pas会更好。然而,我将这个答案留在这里,因为它说明了一些技巧,可以用来解决静态链接时丢失的依赖项


    这里发生的事情是,.obj文件依赖于需要您提供的各种C运行时函数

    首先要做的是将
    crtl
    添加到包含
    $LINK
    指令的单元的
    uses
    子句中。
    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函数,可以通过在uses子句中添加
    Windows
    轻松解决

    此时,您只剩下以下内容:

    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'
    
    要解决这些问题,您需要:

  • 链接另一个包含缺少依赖项的.obj文件
  • 在包含
    $LINK
    的同一单元中实现Delphi代码中缺少的依赖项
  • 实际上我不确定这些函数是做什么的,所以你还有更多的工作要做。我猜这些函数是64位整数算术例程。您可能可以通过编写C的短位来执行各种64位算术运算,从而对其进行反向工程。然后使用bcc32编译,并将输出视为
    asm
    。据推测,
    bcc32
    具有发出
    asm
    的能力。或者您可以链接到一个Delphi单元,看看上面的哪些函数与您在C代码中使用的操作相对应

    您可以从
    msvcrt.dll
    中拉出
    localtime
    ,这对于缺少的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的动态链接更容易实现。

    看看我们的开源库。它实现sqlite3.obj的静态链接,并使用最新版本的sqlite3官方代码进行维护(和功能—例如,它是唯一允许扩展使用sqlite3虚拟表的框架)。你有包装纸。但不仅仅如此

    下面是我们如何将源代码编译成.obj(一个包含FTS3,另一个不包含FTS3):

    然后看看这个单元。它包含一些纯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;
    
    函数_ftol:Int64;
    //Borland C++浮到整数(It64)转换
    asm
    jmp系统。@Trunc//FST(0)->EDX:EAX,正如BCC32编译器所期望的那样
    结束;
    函数_ftoul:Int64;
    //Borland C++浮到整数(It64)转换
    asm
    jmp系统。@Trunc//FST(0)->EDX:EAX,正如BCC32编译器所期望的那样
    结束;
    函数malloc(大小:基数):指针;cdecl;{始终是cdecl}
    //SQLite3数据库引擎将使用FastMM4/