При связывании sqlite3.obj выдаются ошибки неудовлетворенного прямого объявления - PullRequest
8 голосов
/ 01 января 2012

Я скомпилировал ядро ​​базы данных SQLIte3 из sqlite3.c с BCC 55, используя следующую команду:

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'

Зачем нужно реализовывать функции времени исполнения Borland C ++ в чистом паскале (или asm)? Не могут ли те, которые связаны в объекте напрямую? Некоторые из них уже реализованы в System.pas, но компилятор жалуется?

Рациональное выполнение этого mysqlf вместо использования SynSQLite3 или DIXml заключается в следующем:

  • SynSQLite3 поддерживает 3.7.8 (я не вижу последнюю версию 3.7.9)

  • SynSQLite3 пропускает некоторые объявления, такие как sqlite3_trace, sqlite_open_v2 и т. Д.

  • SynSQLite2 примерно в 18 раз медленнее, чем DIXml 2.4.0, в последующих 20 000 пошаговых операциях

  • Оплачивается DISQLite3

  • DISQLite 2.4.0 быстро выполняет 20000 шагов за 260 мс, но не поддерживает DXE2

  • DISQLite 3.0.0 и 3.1.0 поддерживают DXE2, но примерно в 8 раз медленнее, чем 2.4.0

  • Я очень любопытный парень и всегда стараюсь писать как можно ближе к металлу.

  • Благодарность разработчикам 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

P.S. Мой sqlite3.obj временно доступен для загрузки и тестирования здесь

Ответы [ 2 ]

8 голосов
/ 01 января 2012

Взгляните на наши библиотеки с открытым исходным кодом. Он реализует статическое связывание 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 . Он содержит некоторую версию необходимых внешних файлов на паскале или 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), прочитайте это .

4 голосов
/ 01 января 2012

Обновление : вам будет гораздо лучше с 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 к вашему предложению использования.

На данный момент у вас осталось следующее:

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. Реализация отсутствующей зависимости в коде Delphi в том же модуле, который содержит $LINK.

На самом деле я не уверен, что делают эти функции, поэтому у вас впереди еще немного работы. Я предполагаю, что эти функции являются 64-битными целочисленными арифметическими процедурами. Вероятно, вы можете перепроектировать это, написав короткие биты C для выполнения различных 64-битных арифметических операций. Затем скомпилируйте с bcc32 и посмотрите на вывод как asm. Предположительно bcc32 обладает способностью излучать asm. Или вы можете просто связаться с модулем Delphi и посмотреть, какая из вышеперечисленных функций соответствует операциям, которые вы использовали в своем коде C.

Вы можете извлечь localtime из msvcrt.dll, всегда полезный запасной вариант для отсутствующих функций времени выполнения C. Фактически, это то, что делает текущая реализация модуля crtl, поэтому, если вы собираетесь использовать crtl, вы также можете получить localtime таким же образом.


Заимствуя некоторый код у Арно, следующий модуль успешно компилируется:

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 по-прежнему отсутствует код. Более того, я даже не пытался проверить, работает ли он. Успешная компиляция - это только первый шаг.

Я настоятельно рекомендую вам использовать код, на который направляет вас Арно, если вы хотите использовать статическое связывание. Этот код явно использовался и тестировался, и вы также можете извлечь из этого пользу.


Статическое связывание обеспечивает удобное развертывание, но динамическое связывание с DLL намного проще.

...