2012-01-01 21 views
8

he recopilado motor de base de datos sqlite3 de sqlite3.c con BCC 55 con el siguiente comando:sqlite3.obj Vinculación emite uunsatisfied hacia adelante declaraciones errores

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

se generó el fichero sqlite3.obj adecuada. Pero una vez que intenta vincular en mi aplicación Delphi como esto:

unit unt_SQLite3; 

interface 

uses 
    Windows; 

implementation 

{$LINK 'sqlite3.obj'} 
end. 

consigo los siguientes errores:

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

¿Por qué se necesita para implementar las funciones de tiempo de ejecución en Pascal pura Borland C++ (o asm)? ¿No se pueden enlazar directamente en el obj? Algunos de ellos ya están implementados en System.pas pero el compilador se queja?

La base científica de esta manera mysqlf en lugar de utilizar SynSQLite3 o DIXml es la siguiente:

  • SynSQLite3 apoya 3.7.8 (no veo las últimas 3.7.9)

  • pierde SynSQLite3 algunas declaraciones como sqlite3_trace, sqlite_open_v2, etc.

  • SynSQLite2 es de alrededor de 18 veces más lento que DIXml 2.4.0 en consiguientes 20 000 operaciones de paso

  • DISQLite3 se paga

  • DISQLite 2.4.0 es rápido hace 20000 operaciones de paso de 260ms, pero no es compatible con DXE2

  • DISQLite 3.0.0 y 3.1.0 hacerlo apoyo DXE2 pero son alrededor de 8 veces más lento de 2.4.0

  • Soy un tipo muy curioso y siempre trato de codificar lo más cerca posible del metal.

  • Felicitaciones a SynSQLite3 y DISQLite3 desarrolladores - muy buena doen trabajo hasta ahora

el tiempo me terminaron eligiendo SynSQLite3 porque:

  1. Es de código abierto

  2. Está muy bien documentado

  3. aprendí a recompilar sqlite3.obj mí mismo y dejar sólo los interruptores de compilación necesarios para las funciones que necesito

  4. que puede tener la versión actualizada 3.7.9 vinculado

  5. Con el ajuste fino última 3.7 .9 obj Logré la velocidad de DISQLite3

  6. El chico DISQLite3 no tiene ni siquiera una dirección de correo electrónico en su sitio para escribir (solo una lista de correo), donde los chicos de SynSQLite3 responden en SO en la misma hora.Esto tiene sentido al elegir una lib sobre otra. Rendimiento y precio no son todo.

SQLite3 Profile Results

P. S. Mi sqlite3.obj es provisoriamente disponible para su descarga y prueba here

+0

Enlazador. El compilador no se preocupa por eso, el enlazador sí. – OnTheFly

+0

@user no, este es el tiempo de compilación cuando se hace el dcu –

+0

@DavidHeffernan, falso. – OnTheFly

Respuesta

8

Eche un vistazo a nuestras bibliotecas de código abierto. Implementa la vinculación estática de sqlite3.obj, y se mantiene con la última versión del código oficial de SQLite3 (y características, es el único marco que permite el uso extendido de las tablas virtuales SQLite3, por ejemplo). Tienes un envoltorio. Pero más que eso.

Así es como se compila la fuente en el .obj (uno inclusing FTS3, el otro sin ella):

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 

A continuación, echar un vistazo a la unidad SynSQLite3.pas. Contiene una versión pascal o asm pura de los archivos externos necesarios.

Por ejemplo:

function _ftol: Int64; 
// Borland C++ float to integer (Int64) conversion 
asm 
    jmp [email protected] // FST(0) -> EDX:EAX, as expected by BCC32 compiler 
end; 

function _ftoul: Int64; 
// Borland C++ float to integer (Int64) conversion 
asm 
    jmp [email protected] // 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 [email protected]_lldiv 
end; 

procedure _lludiv; 
asm 
    jmp [email protected]_lludiv 
end; 

procedure _llmod; 
asm 
    jmp [email protected]_llmod 
end; 

procedure _llmul; 
asm 
    jmp [email protected]_llmul 
end; 

procedure _llumod; 
asm 
    jmp [email protected]_llumod 
end; 

procedure _llshl; 
asm 
    jmp [email protected]_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 [email protected]_llshr 
{$endif} 
end; 

procedure _llushr; 
asm 
    jmp [email protected]_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; 

que encontrará en esta unidad mucho más que un simple enlace estático de SQLite3. Tenga en cuenta que incluso si es utilizado por nuestro framework mORMot ORM Client-Server, este ORM es no requerido para usar las clases SQLite3. Ver this article for additional details.

Si está perdido en nuestro repositorio de código fuente (utilizando el gran proyecto FOSSIL), read this.

+0

+1 Mucho mejor usar el código existente donde cabe así como esto. –

+0

Eventualmente terminé recompilando el archivo sqlite3.c versión 3.7.9 y reemplazando el archivo 3.7.8 sqlite3.obj en SynSQLite3. Esto hizo que la ejecución fuera la misma que la versión DISQlite3 2.4.0. Captura de pantalla con el perfil adjunto en la pregunta. –

+0

Los archivos sqlite3.obj suministrados en la versión actual ya están en 3.7.9. Ver [el enlace que proporcioné] (http://synopse.info/fossil/wiki?name=Get+the+source) al final de mi respuesta. Descarga directa [desde aquí] (http://synopse.info/files/sqlite3obj.7z). Esta es la versión instantánea: el 1.15 oficial sigue usando 3.7.8. ¡Muchas gracias por su interés en Open Source! Eres bienvenido en nuestros foros si deseas unirte al proyecto y comprometes algún código para mejorar la unidad. –

4

actualización: Va a ser mucho mejor con SynSQLite3.pas como se sugiere por Arnaud. Sin embargo, dejo esta respuesta aquí ya que ilustra algunos de los trucos que se pueden usar para resolver las dependencias faltantes cuando se establece un enlace estático.


Lo que ocurre aquí es que el archivo .obj depende de funciones C en tiempo de ejecución que deben ser proporcionada por usted.

Lo primero que debe hacer es agregar crtl a la cláusula uses de la unidad que contiene la directiva $LINK. La unidad crtl contiene implementaciones de varias de las funciones de la biblioteca C runtime y está diseñada para este propósito.

Sin embargo, cuando hace esto, mientras se resuelven algunas dependencias que faltan, aparecen muchas más.

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' 

Muchos de estos son simplemente funciones API de Windows y puede ser fácilmente resuelto mediante la adición de Windows a su cláusula de usos.

En este punto, lo que queda es la siguiente:

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' 

Para resolver estos lo que necesita, ya sea:

  1. Enlace otro archivo .obj que contiene la dependencia faltante.
  2. Implemente la dependencia faltante en el código Delphi en la misma unidad que contiene el $LINK.

No estoy seguro de qué hacen estas funciones, así que tiene un poco más de trabajo por delante. Creo que estas funciones son rutinas aritméticas enteras de 64 bits. Probablemente pueda realizar una ingeniería inversa mediante la escritura de bits cortos de C para realizar varias operaciones aritméticas de 64 bits. Luego compile con bcc32 y mire la salida como asm. Es de suponer que bcc32 tiene la capacidad de emitir asm. O puede vincularse a una unidad Delphi y ver cuál de las funciones anteriores corresponde a las operaciones que utilizó en su código C.

Puede extraer localtime de msvcrt.dll, siempre es una opción útil de recuperación para las funciones de tiempo de ejecución de C faltadas. De hecho, eso es lo que hace la implementación actual de la unidad crtl, por lo que si va a utilizar crtl, también puede obtener localtime de la misma manera.


Tomando prestado algo de código de Arnaud, la siguiente unidad se compila correctamente:

unit sqlite3; 

interface 

implementation 

uses 
    crtl, Windows; 

{$L c:\desktop\sqlite3.obj} 

procedure _lldiv; 
asm 
    jmp [email protected]_lldiv 
end; 

procedure _llmod; 
asm 
    jmp [email protected]_llmod 
end; 

procedure _llmul; 
asm 
    jmp [email protected]_llmul 
end; 

procedure _llumod; 
asm 
    jmp [email protected]_llumod 
end; 

procedure _lludiv; 
asm 
    jmp [email protected]_lludiv 
end; 

procedure _llshl; 
asm 
    jmp [email protected]_llshl 
end; 

procedure _llushr; 
asm 
    jmp [email protected]_llushr 
end; 

procedure localtime; cdecl; external 'msvcrt.dll'; 

end. 

Tenga en cuenta que no es necesario proporcionar la lista de parámetros, etc. convención de llamada para cualquiera de estas funciones, ya que estamos no implementarlos aquí. En cada caso, el código simplemente delega la implementación.

Sin embargo, todavía falta el código para declarar las funciones de sqlite3. Además, ni siquiera intenté probar si funciona o no. La compilación exitosa es solo el primer paso.

Recomiendo encarecidamente que utilice el código que Arnaud le indica si desea utilizar enlaces estáticos. Es claro que este código ha tenido mucho uso y pruebas, y también puede beneficiarse de eso.


La vinculación estática hace una implementación conveniente, pero la vinculación dinámica contra una DLL es mucho más simple de lograr.

+0

Esas funciones son auxiliares para enteros de 64 bits (firmados y "firmados").En sistemas gcc, tales funciones están en libgcc. Posiblemente necesite estar enlazado estáticamente desde un archivo de objeto msvc. –

+0

Es posible que haya desvalorizado el voto negativo de su respuesta por accidente. Si fuera yo, por favor, avíseme para corregir. Si no fui yo, elimine este comentario. –

+1

Hay una pequeña unidad de comentarios disponible con el nombre System.Win.Crtl.pas en Delphi XE2 y también está disponible con el código fuente en C: \ Archivos de programa \ Embarcadero \ RAD Studio \ 9.0 \ source \ rtl \ common si está predeterminado la ruta de instalación es usada. En la versión anterior de XE, solo estaba disponible como crtl.dcu. –

Cuestiones relacionadas