草庐IT

delphi - 链接 sqlite3.object 发出不满意的前向声明错误

coder 2023-07-20 原文

我使用以下命令使用 BCC 55 从 sqlite3.c 编译了 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,但比 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。在选择一个库而不是另一个库时,这是有道理的。性能和价格不是一切。

附言我的 sqlite3.obj 暂时可供下载和测试 here

最佳答案

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

以下是我们如何将源代码编译成 .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 客户端-服务器框架使用,这个 ORM 也不是使用 SQLite3 类所必需的。参见 this article for additional details .

如果您迷失在我们的源代码存储库中(使用伟大的 FOSSIL 项目),read this .

关于delphi - 链接 sqlite3.object 发出不满意的前向声明错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8694846/

有关delphi - 链接 sqlite3.object 发出不满意的前向声明错误的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  3. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  6. ruby-on-rails - Prawn - 表格单元格内的链接 - 2

    我正在尝试用Prawn生成PDF。在我的PDF模板中,我有带单元格的表格。在其中一个单元格中,我有一个电子邮件地址:cell_email=pdf.make_cell(:content=>booking.user_email,:border_width=>0)我想让电子邮件链接到“mailto”链接。我知道我可以这样链接:pdf.formatted_text([{:text=>booking.user_email,:link=>"mailto:#{booking.user_email}"}])但是将这两行组合起来(将格式化文本作为内容)不起作用:cell_email=pdf.make_c

  7. python - 是否可以使用 Ruby 或 Python 禁用 anchor /引用来发出有效的 YAML? - 2

    是否可以在PyYAML或Ruby的Psych引擎中禁用创建anchor和引用(并有效地显式列出冗余数据)?也许我在网上搜索时遗漏了一些东西,但在Psych中似乎没有太多可用的选项,而且我也无法确定PyYAML是否允许这样做.基本原理是我必须序列化一些数据并将其以可读的形式传递给一个不是真正的技术同事进行手动验证。有些数据是多余的,但我需要以最明确的方式列出它们以提高可读性(anchor和引用是提高效率的好概念,但不是人类可读性)。Ruby和Python是我选择的工具,但如果有其他一些相当简单的方法来“展开”YAML文档,它可能就可以了。 最佳答案

  8. objective-c - 在设置 Cocoa Pods 和安装 Ruby 更新时出错 - 2

    我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U

  9. ruby - 你会如何在 Ruby 中表达成语 "with this object, if it exists, do this"? - 2

    在Ruby(尤其是Rails)中,您经常需要检查某物是否存在,然后对其执行操作,例如:if@objects.any?puts"Wehavetheseobjects:"@objects.each{|o|puts"hello:#{o}"end这是最短的,一切都很好,但是如果你有@objects.some_association.something.hit_database.process而不是@objects呢?我将不得不在if表达式中重复两次,如果我不知道实现细节并且方法调用很昂贵怎么办?显而易见的选择是创建一个变量,然后测试它,然后处理它,但是你必须想出一个变量名(呃),它也会在内存中

  10. ruby - 在 Ruby 中,为什么 Array.new(size, object) 创建一个由对同一对象的多个引用组成的数组? - 2

    如thisanswer中所述,Array.new(size,object)创建一个数组,其中size引用相同的object。hash=Hash.newa=Array.new(2,hash)a[0]['cat']='feline'a#=>[{"cat"=>"feline"},{"cat"=>"feline"}]a[1]['cat']='Felix'a#=>[{"cat"=>"Felix"},{"cat"=>"Felix"}]为什么Ruby会这样做,而不是对object进行dup或clone? 最佳答案 因为那是thedocumenta

随机推荐