Per il DS linko staticamente la librerie libnds e quelle del gcc. Per farlo basta usare la direttiva linklib:
{$linklib nds9}
{$linklib c}
{$linklib gcc}
{$linklib g}
In questo caso le librerie linkate sono, rispettivamente, libnds9.a, libc.a, libgcc.a e libg.a.
Le funzioni chiamate hanno quest'aspetto:
function memcpy(dest: pointer; src: pointer; n: integer): pointer; cdecl; external;
Se hai problemi col nome delle funzioni puoi usare la direttiva name, ad esempio così:
function _memcpy(dest: pointer; src: pointer; n: integer): pointer; cdecl; external name 'memcpy';
Se hai bisogno di una mano fai un fischio. Buon lavoro! ;)
Aggiornamento delle 4 e mezza di mattina.
Allora Bind da dll concluso.
Ho abbandonato la strada delle macro. Sembra non le digerisca come pensavo. Amen.
Legolas. Le funzioni sono già "spianate". Per questo dalla DLL si riesce a chiamare la parte interna scritta in C++.
Esempio:
// Name: NewtonGetMemoryUsed
// Return the exact amount of memory use by the engine and any given time time.
//
// Parameters: none
//
// Return: total memory use by the engine.
//
// Remarks: this function is useful for application to determine if the memory use by the engine is balanced at all time.
//
// See also: NewtonCreate
int NewtonGetMemoryUsed()
{
TRACE_FUNCTION(__FUNCTION__);
return dgMemoryAllocator::GetGlobalMemoryUsed();
}
Sembra che nel ".a" ci sia un pochino di tutto (:D battuta).
Forse mi sta sfuggendo qualche opzione che non metto (ma che vorrei scrivere sul sorgente per renderlo esplicito :D)
Domani se ho tempo mi rimetto e mi scorno per bene :D
Stilgar
Uhm... ripensando alla macro che hai scritto più sopra: così non funziona, perché in fpc non sono supportati i parametri. Potresti provare con un accrocchio del genere:
{$MACRO ON}
{$ifdef STATIC_BIND}
{$define NEWTON_API:=external name}
{$else}
{$define NEWTON_API:=external ExternalLibrary}
{$endif}
function NewtonAlloc(sizeInBytes: cint): pointer; cdecl; NEWTON_API 'NewtonAlloc';
che è più o meno quello che cercavi di fare :D
Aspe' :D
Allora, prendiamo il log su windows. Questo è uno degli errori:
C:\lavoro\lazarus\code\libraries\liug\trunk\bindings\newtonApplication\pck\NewtonDemos.lpr(19,1) Error: Multiple defined symbol __ZNK5dgRef9GetTypeIdEv
Facendo un demangling casereccio, si fa riferimento al metodo GetTypeId della classe dgRef. Nei sorgenti non trovo da nessuna parte la funzione spianata GetTypeId che richiama il metodo dalla classe. Per questo dico che non ci sono le funzioni "spianate" :D
Ci dovrebbe essere da qualche parte un file c con una cosa del tipo
int GetTypeId() {
return dgRef.GetTypeId();
}
e un file h in cui viene esportata la funzione GetTypeId.
Si esiste quel metodo.
class dgRef: public dgRefFlags
{
[..]
virtual dgUnsigned32 GetTypeId () const;
[..]
}
Il "problema" è che non viene usato in fase di export ....
Quindi cosa serve creare una funzione che prenda in ingresso dgRef * per darti un dato che non "serve" al chiamante esterno?
Sono confuso...
Prendiamo ad esempio questo pezzo di codice:
// Name: NewtonCreate
// Create an instance of the Newton world.
//
// Parameters:
// *NewtonAllocMemory* mallocFnt - is a pointer to the memory allocator callback function. If this parameter is
// NULL the standard *malloc* function is used.
// *NewtonFreeMemory* mfreeFnt - is a pointer to the memory release callback function. If this parameter is NULL
// the standard *free* function is used.
//
// Return: a pointer to an instance of the Newton world.
//
// Remarks: this function must be called before any of the other API functions.
//
//
// See also: NewtonDestroy, NewtonDestroyAllBodies
NewtonWorld* NewtonCreate()
{
TRACE_FUNCTION(__FUNCTION__);
dgMemoryAllocator* const allocator = new dgMemoryAllocator();
NewtonWorld* const world = (NewtonWorld*) new (allocator) Newton (dgFloat32(1.0f), allocator);
return world;
}
// Name: NewtonDestroy
// Destroy an instance of the Newton world.
//
// Parameters:
// *const NewtonWorld* *newtonWorld - is the pointer to the Newton world.
//
// Return: Nothing.
//
// Remarks: This function will destroy the entire Newton world.
//
// See also: NewtonCreate, NewtonDestroyAllBodies
void NewtonDestroy(const NewtonWorld* const newtonWorld)
{
TRACE_FUNCTION(__FUNCTION__);
Newton* const world = (Newton *) newtonWorld;
dgMemoryAllocator* const allocator = world->dgWorld::GetAllocator();
delete world;
delete allocator;
}
La prima funzione chiama 2 classi.
Newton e dgMemoryAllocator.
Crea dgMemoryAllocator e lo passa come parametro al costruttore di Newton.
La seconda a partire dal parametro che gli si passa esegue il cast. Ottiene l'allocator e distrugge entrambe le istanze.
Da quello che mi sembra di capire del tuo suggerimento:
Dovrei creare delle funzioni del tipo:
void * NewtonWorld(void* instance)
{
Newton* const world = (Newton *) instance;
return world->dgWorld;
}
Poi però il codice originale continuerebbe a non usare questa funzione. Quindi mi sfugge il significato di scrivere funzioni che non sono usate internamente :D
Cioè dovessi mappare tutte le classi (cosa che con i test che hai linkato si potrebbe pure fare :D ) avrebbe senso spianare tutta la libreria.
Poi però le chiamte "interne" sarebbero fatte lo stesso in c++. Quindi mi sento "confuso e infelice". La trovo una cosa senza senso ... poi mi sbaglierò e verrà fuori che bisogna simulare le chiamate alla VMT del c++ :D
Da quello che ho capito, la "spianatura" serve solo per le chiamate esterne non in c++.
Stilgar