Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: Stilgar - Gennaio 06, 2016, 12:03:12 pm

Titolo: Link librerie statiche
Inserito da: Stilgar - Gennaio 06, 2016, 12:03:12 pm
Ciao a tutti.
Mi chiedevo per poter "linkare" una libreria non dinamicamente (dll) come devo compilare la libreria.
Entrando del dettaglio, voglio fare il binding di "newton dynamics" ( http://newtondynamics.com (http://newtondynamics.com) ) per Lazarus, dinamico e statico.
La libreria è Open Source ( https://github.com/MADEAPPS/newton-dynamics/ (https://github.com/MADEAPPS/newton-dynamics/) ), quindi posso ricompilarmela come voglio
Vorrei poter eseguire entrambi i tipi di binding.
Arrivando al cuore del dubbio. Che compilatore devo usare (c/c++) per poter fare in modo che FPC linki correttamente?
Non continuo con i miei dubbi per non influenzarvi :p
Intanto continuo con il binding dinamico :D

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: nomorelogic - Gennaio 06, 2016, 01:00:37 pm
sotto linux non dovresti avere troppi problemi (l'ottimismo non è mai troppo :D) basta che usi strumenti (ld, as, make) della famiglia GNU. per win devi usare ming32.

credo però che prima dovresti leggerti bene questo
http://www.stack.nl/~marcov/buildfaq.pdf
quà troverai molte risposte

leggi poi anche questo thread che parla di come compilare sqllite in un binario fpc
http://forum.lazarus.freepascal.org/index.php/topic,15712.msg84781.html?PHPSESSID=2b185813402f5371265f404f46af9ebe#msg84781

buon lavoro e suprattutto facci sapere! ;)

Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 06, 2016, 01:01:52 pm
Inizio a studiare :D
Grazie Nomore ;)

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 06, 2016, 01:06:03 pm
Da una prima veloce lettura emerge che non si possono usare gli strumenti microsoft.

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: nomorelogic - Gennaio 06, 2016, 01:10:53 pm
già, solo GNU (o cygwin o ming)
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 06, 2016, 08:50:57 pm
Per il DS linko staticamente la librerie libnds e quelle del gcc. Per farlo basta usare la direttiva linklib:

Codice: [Seleziona]
{$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:

Codice: [Seleziona]
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ì:
Codice: [Seleziona]
function _memcpy(dest: pointer; src: pointer; n: integer): pointer; cdecl; external name 'memcpy';

Se hai bisogno di una mano fai un fischio. Buon lavoro! ;)
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 07, 2016, 05:01:48 pm
Grazie :D
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 07, 2016, 05:12:22 pm
na.lpr(18,1) Error: Multiple defined symbol __ZN5dgRefD1Ev

Mumble... versione link statico ... :(

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 07, 2016, 05:59:11 pm
Una curiosità ...
Sarà che le macro in c/c++ sono abituato ad usarle in un certo modo:

Definendo la macro

{$ifdef STATIC_BIND}
  {$define  NEWTON_API(apiName):=external name apiName}
  {$LinkLib libNewton}
{$else}
  {$define  NEWTON_API(apiName):=external ExternalLibrary apiName}
{$endif}     

Nell'uso il compilatore non si comporta come mi aspetterei. Mi sa semplicemente errore dicendo che NEWTON_API non è riconosciuto... :(

function NewtonAlloc(sizeInBytes: cint): pointer; cdecl; NEWTON_API('NewtonAlloc');
Titolo: Re:Link librerie statiche
Inserito da: nomorelogic - Gennaio 07, 2016, 06:05:01 pm
che apiname vada tra apici?
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 07, 2016, 07:24:18 pm
Il compilatore riporta questo errore :
 newtonlib.pas(1206,58) Fatal: Syntax error, "BEGIN" expected but "identifier NEWTON_API" found
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 07, 2016, 08:36:15 pm
Per librerie scritte in c++ le cose si complicano leggermente, perché devi "spianarle" e wrapparne metodi, costruttore e distruttore in funzioni.

Qua c'è un tutorial ben fatto:

http://gd.tuwien.ac.at/languages/pascal/fpc/docs-pdf/CinFreePascal.pdf
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 08, 2016, 04:27:09 am
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:
Codice: [Seleziona]
// 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
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 08, 2016, 11:24:25 am
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:

Codice: [Seleziona]
{$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
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 08, 2016, 11:45:26 am
Grande Legolas.
Hai trovato la strada giusta :D

L'orario non mi era d'aiuto ;)

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 08, 2016, 07:41:34 pm
Aggiornamento.
La libreria ".a" essendo scritta in c++ potrebbe avere qualche problema col linker?
Non so, sta di fatto che non ho capito come fare il bind statico.
Amen.
Nel controllare gli howto e demo di Newton-dynamics mi sono accorto che SDL per freepascal è abbastanza indietro ... :( 2013 per capirci. Ma SDL mi sembra sia un pochino più aggiornato. (Il repository controllato oggi mi dice 5 days ago   release-2.0.4 ...)
C'è qualche repository più aggiornato rispetto a quello jedy?

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 09, 2016, 12:15:08 pm
Ciao a tutti.
https://github.com/danpla/sdl2-fpc

Trovato questo :D

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: nomorelogic - Gennaio 09, 2016, 02:49:25 pm
dicci Stilgar, cosa bolle in pentola? :)
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 09, 2016, 02:52:19 pm
Niente.
Avevo tempo e non sapevo come impegnarlo :D


:p
Titolo: Re:Link librerie statiche
Inserito da: nomorelogic - Gennaio 09, 2016, 03:00:31 pm
non ci credo :D

tira fuori il progetto di esempio hahahahaah
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 10, 2016, 12:00:27 pm
La libreria ".a" essendo scritta in c++ potrebbe avere qualche problema col linker?
Non so, sta di fatto che non ho capito come fare il bind statico.

In teoria no, in pratica devi stare attento all'ordine in cui le librerie esterne vengono linkate nel tuo eseguibile, ma questo vale anche per librerie scritte in c. Se ti va di condividere in uno zippone il punto in cui ti sei bloccato, posso provare a darci uno sguardo :)
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 10, 2016, 03:45:28 pm
https://sourceforge.net/p/lazarusiug/liug/HEAD/tree/trunk/bindings/newtonApplication/

Ho già pubblicato lo stato attuale su sourceforge.
Se non sbaglio sei già amministratore come  "p4p3r0" .. :D
Non ti arrivano le notifiche per mail?

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 10, 2016, 05:00:37 pm
Uh... no, in effetti  :D

Devo vedere se mi vanno in spam o le ho disattivate sul profilo...

Comunque vedo di darci un'occhiata

EDIT: appunto, avevo le notifiche disattivate  ;D
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 15, 2016, 12:20:23 am
Mingw mi sta facendo impazzire.
Ho creato una macchina virtuale e ho installato debian.

Vediamo se sotto linux le cose vanno meglio :D

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 15, 2016, 10:30:13 am
Ok, ho avuto modo di giocareci un pochino per vedere come linkare staticamente la baracca.

La risposta è che non si può, almeno non direttamente. Provando a linkare la libreria statica libNewton.a, il linker non trova delle funzioni (_Z1vattelappesca). Quel prefisso _Z1 indica che si tratta di nomi di funzioni mangled, assegnate dal compilatore c++.

Per accedervi dal free pascal, come dicevo, bisognerebbe wrappare la libreria c++ in una c, compilarla con gcc e utilizzare la libreria ottenuta, nella quale non ci dovrebbero più essere nomi di funzioni mangled, per linkarla con il free pascal.

Si stava lavorando su una soluzione interna, che permette di dichiarare classi presenti in una libreria esterna in c++, ma al momento è tutto fermo. L'ho provata su una libreria semplicissima e sembra funzionare, ma ho paura che per una libreria complessa come newton non sia ancora pronta... In ogni caso, se vuoi darci un'occhiata:
http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/tests/test/cg/tcppcl1.pp (http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/tests/test/cg/tcppcl1.pp)
http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/tests/test/cg/tcppcl2.pp (http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/tests/test/cg/tcppcl2.pp)

PS. Che problemi ti da Mingw?
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 15, 2016, 01:16:29 pm
Gli stessi che hai appena spiegato tu :D
Speravo fosse una menata del porting per windows del GCC visto che la versione di Linux non introduce "_" prima del nome della funzione :D

Controllo i link che hai messo.

Grazie.

Stilgar
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 15, 2016, 01:32:23 pm
Legolas.
Se controlli i log del linker su Windows e quelli del linker su Linux sono abbastanza differenti.
Quello per Windows si incasina con i nomi e basta.
Quello per Linux mi indica problemi con le classi c++

Per questo dicevo che Mingw mi faceva impazzire ;)

Sembra che il linker si trovi a non trovare i simboli con "classe->metodo", ma in effetti sono le funzioni wrapper (newton le wrappa già per poter esporre funzioni semplici tramite dll) a chiamare le classi internamente. Quindi newton ha già "Spianto" le funzioni.
Riwrapparle non credo risolva il problema  :'(
 

(Si lo so.. mettere su una macchina virtuale con Linux per lanciare una compilazione è come asciugarsi i capelli con un turbo reattore per aerei, ma visto che c'ero mi sono preparato anche un macchina virtuale con haiku os, tanto per vedere il porting lazarus girare :D ).

Stilgar

PS:
Controllando le estensioni al linguaggio che stanno provando vedo i test, ma non il c++ che genera quelle classi.
Poi linkano classe per classe. quindi i ".o" e non la ".a"
Se al linker sotto Lazarus ci fosse un benedetto parametro per dirgli si smenare codice oggetto c++ e non c (o come lo interpreta lui ....)
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 15, 2016, 02:13:50 pm
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

Codice: [Seleziona]

int GetTypeId() {
    return dgRef.GetTypeId();
}


e un file h in cui viene esportata la funzione GetTypeId.
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 15, 2016, 02:52:01 pm
Si esiste quel metodo.

Codice: [Seleziona]
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:
Codice: [Seleziona]
// 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:

Codice: [Seleziona]

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
Titolo: Re:Link librerie statiche
Inserito da: Legolas - Gennaio 19, 2016, 10:51:28 am
Infatti, serviva solo per le chiamate esterne.

Però.

Qualche anno fa mi contattò Gilles Marcou, che stava scrivendo la guida (ftp://ftp.freepascal.org/fpc/docs-pdf/CinFreePascal.pdf) su come linkare in free pascal librerie in c\c+. Mi inviò un'anteprima del documento che stava scrivendo, per controllare se ci fossero inesattezze. Allora, (parlo di circa 10 anni fa!) provai a compilare i progetti di esempio e, se la memoria non mi fa difetto, filò tutto liscio, tant'è che poi la guida è stata pubblicata.  ;D

L'altro giorno ho provato a ricompilare gli esempi della guida e SBAM! sono usciti fuori gli errori che stiamo incontrando con Newton!  :o

Ora, di cose da 10 anni a questa parte ne sono cambiate, quindi è difficile dire con esattezza cosa può aver determinato gli errori in fase di linking...  ???

Nel frattempo credo che bisognerà accontentarsi di utilizzare la dll, oppure di "embeddarla" nell'eseguibile come risorsa...  :-\
Titolo: Re:Link librerie statiche
Inserito da: nomorelogic - Gennaio 19, 2016, 12:11:57 pm
questa pagina può essere utile?
http://www.saschawillems.de/?page_id=76 (http://www.saschawillems.de/?page_id=76)
Titolo: Re:Link librerie statiche
Inserito da: Stilgar - Gennaio 19, 2016, 01:03:54 pm
:D
Bella la demo che hanno fatto ;)