[C++] probleem tijdens creëren statische lib

Pagina: 1
Acties:

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
Ik probeer een 'engine' die ik gebouwd heb om te toveren in een statische library.

Deze engine gebruikt onder andere SDL en openGL. Deze moeten dynamisch gelinkt worden, daar valt niks aan te veranderen.
Nu is het probleem dat wanneer ik de opgeleverde library include in een testproject, de linker lijkt te denken dat hij de openGL en SDL calls uit de door mij gecreëerde library moet halen, in plaats van de SDL en openGL libraries die ik meelink in het testproject.

Nu is de wereld van library-creatie nieuw voor mij, maar het lijkt mij toch mogelijk om mijn eigen code statisch te compileren terwijl de externe libraries ook extern blijven?

alvast bedankt!

oprecht vertrouwen wordt nooit geschaad


  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Beetje onduidelijk verhaal, staan die OpenGL/SDL calls nu in je programma of in je library? Als ze in je programma staan moet je zorgen dat je zowel statisch tegen je library alsmede dynamisch tegen OGL en SDL linkt, en anders dat je library zelf ook statisch tegen OGL/SDL gelinkt wordt (een static lib kan per definitie alleen statische references bevatten).

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
DroogKloot schreef op zondag 28 januari 2007 @ 00:54:
Beetje onduidelijk verhaal, staan die OpenGL/SDL calls nu in je programma of in je library? Als ze in je programma staan moet je zorgen dat je zowel statisch tegen je library alsmede dynamisch tegen OGL en SDL linkt, en anders dat je library zelf ook statisch tegen OGL/SDL gelinkt wordt (een static lib kan per definitie alleen statische references bevatten).
ja, ik vind het lastig uit te leggen wat ik precies bedoel, ik probeer het met een voorbeeld:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
lib A {
    blaat() { doetietscools; }
}

lib B { // deze is dynamisch gelinkt aan lib A
    aapje() { 
        blaat();
        doetnogietscoolers;
    }
}

programma C { // deze is statisch gelinkt aan lib B en dynamisch aan A
    aapje();
}


Het probleem dat nu dus ontstaat is dat de linker bij programma C niet snapt dat 'blaat' uit lib A komt en niet uit B.
Is dit probleem te verhelpen, of moet ik dan lib B ook dynamisch gaan linken?

oprecht vertrouwen wordt nooit geschaad


  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Ik neem aan dat A de OGL/SDL library voorstelt, en B je eigen engine lib? Het probleem ontstaat wanneer de linker bij de blaat() reference aankomt, die is namelijk niet op dat moment extern te resolven (omdat je B niet statisch tegen A linkt, maar B wel tot static lib compileert), waardoor 'blaat' als een undefined local symbol wordt gezien. Je kunt denk ik het beste van B zelf ook een dynamische library maken, dan heb je meteen het gratis voordeel dat je engine compleet modulair is.

[ Voor 4% gewijzigd door DroogKloot op 28-01-2007 15:30 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
Ongeacht of B nu wel of niet een dynamische library is; bij het linken moet je alle benodigde libraries opgeven, dus zowel jou library als de OpenGL en SDL libraries. Voor statisch/dynamisch linken maakt het allemaal niets uit; je kunt prima jouw library statisch linken en de overigen dynamisch.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Dat laatste is niet helemaal waar met nieuwere Visual Studio's; daar kun je opgeven dat de linker ook dependencies uit de meegelinkte libraries meeneemt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
Windows is sowieso wat anders omdat je daar altijd de import libraries van je dynamische libraries moet linken, toch? Vanuit dat oogpunt moet je dus altijd met alle libraries (ofwel de statische, ofwel de import libraries) linken, ook al kan Visual Studio voor een deel uitzoeken welke libraries je moet hebben.

[ Voor 45% gewijzigd door Soultaker op 28-01-2007 18:01 ]


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
Soultaker schreef op zondag 28 januari 2007 @ 16:01:
Ongeacht of B nu wel of niet een dynamische library is; bij het linken moet je alle benodigde libraries opgeven, dus zowel jou library als de OpenGL en SDL libraries. Voor statisch/dynamisch linken maakt het allemaal niets uit; je kunt prima jouw library statisch linken en de overigen dynamisch.
Dat is dus raar, want dat probeer ik en dat gaat mis :)
MSalters schreef op zondag 28 januari 2007 @ 17:41:
Dat laatste is niet helemaal waar met nieuwere Visual Studio's; daar kun je opgeven dat de linker ook dependencies uit de meegelinkte libraries meeneemt.
is dat ook te doen voor gcc/mingw ?
Soultaker schreef op zondag 28 januari 2007 @ 18:00:
Windows is sowieso wat anders omdat je daar altijd de import libraries van je dynamische libraries moet linken, toch? Vanuit dat oogpunt moet je dus altijd met alle libraries (ofwel de statische, ofwel de import libraries) linken, ook al kan Visual Studio voor een deel uitzoeken welke libraries je moet hebben.
even googlen op import libraries, het is ook een optie die codeblocks aanbiedt:
Afbeeldingslocatie: http://www.arjanhouben.nl/capture.jpg

oprecht vertrouwen wordt nooit geschaad


  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Nogmaals: je kunt een statische library ( B ) niet linken tegen een dynamische ( A ), net zomin als je een dynamische library kunt linken tegen een statische. :) Anders gezegd, code in een static lib kan *alleen* verwijzen naar code in andere static libs, en code in een dynamic lib kan *alleen* verwijzen naar code in andere dynamic libs. Daar gaat het hier om.

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
DroogKloot schreef op zondag 28 januari 2007 @ 20:49:
Nogmaals: je kunt een statische library ( B ) niet linken tegen een dynamische ( A ), net zomin als je een dynamische library kunt linken tegen een statische. :) Anders gezegd, code in een static lib kan *alleen* verwijzen naar code in andere static libs, en code in een dynamic lib kan *alleen* verwijzen naar code in andere dynamic libs. Daar gaat het hier om.
Het is nu inderdaad gelukt, door te linken aan de dll's
Wel zonde dat het niet mogelijk is om dynamisch en statisch te combineren

oprecht vertrouwen wordt nooit geschaad


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
DroogKloot schreef op zondag 28 januari 2007 @ 20:49:
Nogmaals: je kunt een statische library ( B ) niet linken tegen een dynamische ( A ), net zomin als je een dynamische library kunt linken tegen een statische. :)
Sorry, maar dit is echt onzin. Dat kan allemaal. Een statische library is niet meer dan een verzameling object files. Je zou dus net zo goed de source code van je statische library naar je applicatiedirectory kunnen kopiëren en meecompileren -- het effect is het zelfde. En toch zou je in die tweede situatie wél dynamisch kunnen linken, en in de eerste niet?

Andersom gaat het ook niet op: je kunt prima statische code in een dynamische library linken. Wederom is dit equivalent aan de broncode van de statische library kopiëren naar je library code.

(Geen gemuggezift over incompatible runtimes e.d. alsjeblieft; er zijn tientallen dingen die mis kunnen gaan bij het linken, maar maak de zaken niet nodeloos ingewikkeld.)

On topic: ik begrijp dat Atgast werkt met GCC onder Windows. Compileer de sources van je library tot objects. Stop ze in een library archives (.a file) met ar ("ar -r engine.a *.o"). Link vervolgens je applicatie tegen engine.a, en de import libraries van de dynamische libraries die je applicatie en/of je library gebruikt.

edit:
Oh ja! Bij ouderwetse single-pass linkers zoals GNU ld maakt de volgorde waarin je te linken objecten opgeeft uit! In elke library wordt alleen gekeken welke openstaande symbols gedefinieerd worden, dus als object x een symbol gebruikt die object y definieert, dan moet x voor y komen op de command line! In jouw geval is het dus iets als "ld *.o engine.a opengl.a sdl.a" (want jouw engine bevat symbols voor jouw applicatie, en OpenGL en SDL bevatten symbols voor je engine).

(Overigens mogen libraries ook best meerdere keren voorkomen, wat noodzakelijk is om cyclische dependencies te resolven.)

[ Voor 18% gewijzigd door Soultaker op 28-01-2007 21:41 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op zondag 28 januari 2007 @ 21:36:
[...]

Sorry, maar dit is echt onzin. Dat kan allemaal.
Idd.
Oh ja! Bij ouderwetse single-pass linkers zoals GNU ld maakt de volgorde waarin je te linken objecten opgeeft uit!
Je hebt het over ouderwets, betekent dat dat ld nog steeds zo werkt? Ik heb het nooit begrepen. Theoretisch kan het dus voorkomen dat je twee libraries een miljoen keer moet opgeven door crossdependencies (a/1.o refereert naar b/1.o, die weer naar a/2.o refereert, die weer naar b/2.o refereert, etc.)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
Soultaker schreef op zondag 28 januari 2007 @ 21:36:
[...]
edit:
Oh ja! Bij ouderwetse single-pass linkers zoals GNU ld maakt de volgorde waarin je te linken objecten opgeeft uit! In elke library wordt alleen gekeken welke openstaande symbols gedefinieerd worden, dus als object x een symbol gebruikt die object y definieert, dan moet x voor y komen op de command line! In jouw geval is het dus iets als "ld *.o engine.a opengl.a sdl.a" (want jouw engine bevat symbols voor jouw applicatie, en OpenGL en SDL bevatten symbols voor je engine).
[...]
en daar bleek de truc te zitten :)

volgorde aangepast en nu krijg ik het geheel ook statisch gelinkt!

iedereen bedankt!

oprecht vertrouwen wordt nooit geschaad


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
.oisyn schreef op zondag 28 januari 2007 @ 21:58:
Je hebt het over ouderwets, betekent dat dat ld nog steeds zo werkt?
Yep, werkt nog steeds zo.
Theoretisch kan het dus voorkomen dat je twee libraries een miljoen keer moet opgeven door crossdependencies (a/1.o refereert naar b/1.o, die weer naar a/2.o refereert, die weer naar b/2.o refereert, etc.)
Nee, voor twee libraries hoef je maximaal drie files op de command line te geven: a, b, a. Sterker nog, je hoeft altijd maximaal 2n - 1 files op te geven; voor tien libraries is het misschien: a b c d e f g h i h g f e d c b a maar dan ben je er ook: elke library x die een symbol nodig heeft uit library y, moet er een keer vóór staan.

Het is wel een archaïsch gedoe natuurlijk, en nogal verwarrend voor beginnende gebruikers. Overigens werkt het alleen zo voor libraries; als ik twee objects heb die recursieve dependencies hebben, kan ik ze wel elk één keer opgeven.

[ Voor 7% gewijzigd door Soultaker op 28-01-2007 22:13 ]


  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

Topicstarter
Soultaker schreef op zondag 28 januari 2007 @ 22:12:
[...]

Yep, werkt nog steeds zo.


[...]

Nee, voor twee libraries hoef je maximaal drie files op de command line te geven: a, b, a. Sterker nog, je hoeft altijd maximaal 2n - 1 files op te geven; voor tien libraries is het misschien: a b c d e f g h i h g f e d c b a maar dan ben je er ook: elke library x die een symbol nodig heeft uit library y, moet er een keer vóór staan.

Het is wel een archaïsch gedoe natuurlijk, en nogal verwarrend voor beginnende gebruikers. Overigens werkt het alleen zo voor libraries; als ik twee objects heb die recursieve dependencies hebben, kan ik ze wel elk één keer opgeven.
als het toch 'niet uitmaakt' snap ik niet dat een editor als codeblocks niet een scriptje gebruikt om precies dat te doen wat je daar schetst, scheelt een hoop ellende voor de beginnende/gemiddelde gebruiker.

oprecht vertrouwen wordt nooit geschaad


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op zondag 28 januari 2007 @ 22:12:
Nee, voor twee libraries hoef je maximaal drie files op de command line te geven: a, b, a. Sterker nog, je hoeft altijd maximaal 2n - 1 files op te geven; voor tien libraries is het misschien: a b c d e f g h i h g f e d c b a maar dan ben je er ook: elke library x die een symbol nodig heeft uit library y, moet er een keer vóór staan.
Hij pakt toch alleen maar de object files uit de library die daadwerkelijk nodig zijn? En dus ook alleen maar de external symbols die in zo'n object staan?

Stel nou dat library a de volgende object files bevat: a1.o, a2.o, a3.o, a4.o, ..., en library b bestaat uit de files b1.o, b2.o, b3.o, b4.o, ..., en verder refereert elke aN.o naar een symbol uit bN.o, en elke bN.o refereert naar een symbol uit a[N+1].o

Verder is er nog een app.o van de hoofdapplicatie zelf die naar een symbol uit a1.o refereert. Als je app.o niet meelinkt kun je a en b naar hartelust opgeven, het zal echter geen invloed hebben (je kan alleen a opgeven, of alleen b, of beide helemaal niet), want er is immers geen referentie naar een symbol uit een van de libraries. Maar als je app.o wel meelinkt, dan heb je dus 1 unresolved external symbol. Stel dat de linkvolgorde { app.o; a.a; b.a; a.a } is. Met die ene unresolved symbol komt ie in library a. Daar staat hij in, dus hij linkt met a1.o. Er is nu alleen nog maar een unresolved symbol uit a1.o over (die in b1.o is gedefinieerd), en verder worden er geen objects uit a gebruikt, dus de linker gaat door naar de volgende lib: b. Daar staat het symbol in, namelijk in b1.o. Maar, b1.o introduceert weer een niew unresolved symbol, en uit b is niets meer nodig, dus weer op naar de volgende. Library a weer, want die was nog een keer opgegeven op de command-line. En weer een match, het symbol staat in a2.o. Tevens heeft deze wederom een unresolved symbol, maar nu zijn er verder geen libraries meer om te doorzoeken. Een mooie link error dus, voor een unresolved external symbol dat in b2.o staat maar de linker nergens kan vinden.

Zo werkt ld toch? Als de linker bij a2.o wel snapt dat hij nog een keer in library b moet kijken, waarom moet je library a dan 2x opgeven? Want dan snapt hij ook dat hij bij b1.o weer in a moet kijken. En als ie dat snapt, dan maakt het dus ook niet uit in welke volgorde je de libraries opgeeft, want op een gegeven moment heeft hij ze allemaal gehad en dus kan hij dan ook de rest resolven. Maar dat is helemaal niet zo, dus het is imho ook niet zo dat je maar max 2n-1 files op hoeft te geven.

Dit vraagt om een test :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

En ik had gelijk:

code:
1
2
3
4
oisyn@server:~/linktest$ g++ app.cpp a.a b.a a.a
a.a(a2.o)(.text+0x7): In function `a2()':
: undefined reference to `b2()'
collect2: ld returned 1 exit status


code:
1
2
3
4
oisyn@server:~/linktest$ g++ app.cpp a.a b.a a.a b.a
b.a(b2.o)(.text+0x7): In function `b2()':
: undefined reference to `a3()'
collect2: ld returned 1 exit status

[ Voor 32% gewijzigd door .oisyn op 30-01-2007 12:33 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
Je hebt gelijk; ik had er niet goed over nagedacht.

In de praktijk komt het overigens zelden voor dat je een library meer dan eens moet opgeven, want dependencies werken meestal maar één kant op. Je hoeft ze dan alleen in de goede volgorde te zetten.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

I know
.oisyn schreef op zondag 28 januari 2007 @ 21:58:
Theoretisch kan het dus voorkomen
;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1