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

发布于 2024-12-23 22:25:57 字数 3191 浏览 5 评论 0 原文

我使用以下命令从 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 速度快,可在 260 毫秒内执行 20000 步操作,但不支持 DXE2

  • DISQLite 3.0。 0 和 3.1.0 确实支持 DXE2,但速度比 DXE2 慢 8 倍左右2.4.0

  • 我是一个很好奇的人,总是尝试尽可能接近金属的代码。< /p>

  • 向 SynSQLite3 和 DISQLite3 开发人员致敬 - 迄今为止所做的工作非常出色

最终我选择了 SynSQLite3,因为

  1. 它是开源的

  2. 它有很好的文档记录

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

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

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

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

SQLite3 Profile Results

PS 我的 sqlite3.obj 暂时可供下载和测试 此处

I have compiled SQLIte3 database engine from sqlite3.c with BCC 55 using the following command:

bcc32.exe -jb -O2 -w- -K -c -6 -u- sqlite3.c

The proper sqlite3.obj file was generated. But once I try to link it in my Delphi application like this:

unit unt_SQLite3;

interface

uses
  Windows;

implementation

{$LINK 'sqlite3.obj'}
end.

I get the following errors:

[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'

Why is needed to implement the Borland C++ runtime functions in pure pascal(or asm)?
Can't those linked in the obj directly?
Some of them are already implemented in System.pas but yet the compiler complains?

The rational behind doing this mysqlf instead of using SynSQLite3 or DIXml is the following:

  • SynSQLite3 supports 3.7.8 (I do not see the latest 3.7.9)

  • SynSQLite3 misses some declarations like sqlite3_trace, sqlite_open_v2, etc.

  • SynSQLite2 is around 18 times slower than DIXml 2.4.0 in consequent 20 000 step operations

  • DISQLite3 is paid

  • DISQLite 2.4.0 is fast does 20000 step operations in 260ms but does not support DXE2

  • DISQLite 3.0.0 and 3.1.0 do support DXE2 but are around 8 times slower than 2.4.0

  • I am very curious guy and always try to code as close to the metal as possible.

  • Kudos to SynSQLite3 and DISQLite3 developers - really good work doen so far

Eventually I ended up choosing SynSQLite3 because:

  1. It is open source

  2. It is very well documented

  3. I learned how to recompile sqlite3.obj myself and leave just the needed compilation switches for the features I need

  4. I can have the updated 3.7.9 version linked

  5. With the fine tuned latest 3.7.9 obj I achieved the speed of DISQLite3

  6. The DISQLite3 guy does not have even an email address on his site to write to (just a mailing list), where the SynSQLite3 guys reply in SO on the same hour. This makes sense when choosing one lib over another. Performance and price is not everything.

SQLite3 Profile Results

P.S. My sqlite3.obj is temporaly available for download and test here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

撑一把青伞 2024-12-30 22:25:57

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

以下是我们如何将源代码编译为 .obj(一个包含 FTS3,另一个不包含 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 客户端-服务器框架使用它,该 ORM 也不是使用 SQLite3 类所必需的。请参阅本文了解更多详细信息

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

Take a look at our Open Source libraries. It implements static linking of sqlite3.obj, and is maintained with the latest version of SQLite3 official code (and features - it is the only framework allowing extended use of the SQLite3 Virtual Tables, for instance). You've got a wrapper. But more than that.

Here is how we compile the source into the .obj (one inclusing FTS3, the other without it):

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

Then take a look at the SynSQLite3.pas unit. It contains some pure pascal or asm version of the needed external files.

For instance:

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;

You'll find in this unit much more than just a static linking of SQLite3. Note that even if it is used by our mORMot ORM Client-Server framework, this ORM is not required to use the SQLite3 classes. See this article for additional details.

If you are lost into our source code repository (using the great FOSSIL project), read this.

初见终念 2024-12-30 22:25:57

更新:按照 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 函数,可以通过将 Windows 添加到 use 子句来轻松解决。

此时,您将面临以下问题:

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'

要解决这些问题,您需要执行以下任一操作:

  1. 链接另一个包含缺少依赖项的 .obj 文件。
  2. 在包含 $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 的动态链接更容易实现。

Update: You will be far better off with SynSQLite3.pas as suggested by Arnaud. However, I am leaving this answer here since it illustrates some of the tricks that can be used to resolve missing dependencies when static linking.


What is happening here is that the .obj file depends on various C runtime functions which need to be provided by you.

The first thing to do is to add crtl to the uses clause of the unit which contains the $LINK directive. The crtl unit contains implementations of a number of the C runtime library functions and is designed for just this purpose.

However, when you do this, whilst some missing dependencies are resolved, lots more appear.

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'

Many of these are simply Windows API functions and can easily be resolved by adding Windows to your uses clause.

At this point you are left with the following:

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'

To resolve these you need to either:

  1. Link another .obj file containing the missing dependency.
  2. Implement the missing dependency in Delphi code in the same unit that contains the $LINK.

I'm not actually sure what these functions do so you've got a bit more work ahead of you. My guess is that these functions are 64 bit integer arithmetic routines. You can probably reverse engineer this by writing short bits of C to perform various 64 bit arithmetic operations. Then compile with bcc32 and look at the output as asm. Presumably bcc32 has the capability to emit asm. Or your could just link to a Delphi unit and see which of the above functions corresponds to the operations you used in your C code.

You could pull localtime out of msvcrt.dll, always a useful fall-back option for missing C runtime functions. In fact, that's what the current implementation of the crtl unit does, so if you are going to use crtl you may as well get localtime the same way.


Borrowing some code from Arnaud, the following unit compiles successfully:

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.

Note that you don't need to provide parameter list, calling convention etc. for any of these functions since we are not implementing them here. In each case the code simply delegates the implementation.

However, this is still missing the code to declare the sqlite3 functions. What's more, I've not even attempted to test whether or not it works. Successful compilation is only the first step.

I strongly recommend that you use the code that Arnaud directs you towards if you wish to use static linking. This code clearly has had much use and testing and you may as well benefit from that.


Static linking makes for convenient deployment, but dynamic linking against a DLL is much simpler to achieve.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文