Seite 1 von 1

Vorgehen bei Linkerfehlern

Verfasst: 20.01.2011, 23:36
von Jonathan
Ich habe ein bisschen Renderkram in eine Lib ausgelagert, die ich dann im Spiel benutze. Der Viewer, der nur diese Lib benutzt, funktioniert. Das Spiel hat neuerdings Linkerfehler, wobei eine Funktion, die definitiv in der Lib implementiert ist nicht gefunden wird, sowie eine ganze Menge Kram aus Assimp (_inflateEnd, _inflate, _inflateInit2_, _infalteSetDictionary, _inflateRest, _crc32, _get_crc_table).
Der Editor für das Spiel findet die glewInit nicht, die auch in meiner Lib drin ist, und vom Spiel gefunden wird.

Das ganze erscheint mir überaus willkürlich. Den AssimpKram benutze ich ja nur über die Lib, welche im Viewer funktioniert. Die eine Methode aus der Lib, die das Spiel nicht findet, ist dort auf jedne Fall implementiert und machte sonst auch keine Probleme. Und das mit dem glewInit ergibt auch keinen Sinn, ich habe alle Einstellungen schon zig mal überprüft und hunderte male einen kompletten Rebuild gemacht, es hilft alles nix.

Gut, der Linker sagt einfach nur "find ich net". Wie kann ich jetzt irgendwie dem Fehler systematisch auf die Schliche kommen? Immerhin ist das hier nicht der erste Linkerfehler, der sich nicht kurz und knapp erledigen lässt, sondern C++ scheint sowas irgendwie toll zu finden. (Manchmal möchte ich echt einen "Ich hasse C++"-Thread starten...)

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 03:03
von BeRsErKeR
Kann es eventuell sein, dass du mal statisch und mal dynamisch linkst? Ansonsten auch gucken ob die Methoden richtig exportiert/importiert werden. Gerade unter Windows gibt es da ja ein paar Dinge zu beachten mit dem dllspec usw.

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 10:11
von Jonathan
Nein, ich linke sowohl die Lib als auch Assimp immer statisch. Dann fällt das mit dem dllspec raus, denke ich?
WIe könnte ich sonst noch nach dem Fehler suchen? Irgendwelche Tools, die mir mehr Informationen liefern?

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 10:55
von kimmi
Hast du die gleiche Runtime eingestellt? Also in der Regel bei Projecteigenschaften-> C /C++ -> Codegenerierung -> Runtime -> Multithreaded Dll bei Lib + allen anderen? Die Symbole klingen nach Runtime-spezifischen Symbolen.

Gruß Kimmi

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 12:28
von Jonathan
Nein, überall ist Multithreaded Dll eingestellt (bzw. Multithreaded Debug Dll).
Ich hab noch ein paar Warnungen behoben und die windows.h rausgeschmissen, weil es in irgendwelchen anderen Windows Header zu doppelt definierten Makros kam, aber das hat auch nix geändert. Bis auf ein paar Stellen, wo ich nicht explizit gecastet habe, ist der Code jetzt warnungsfrei, aber geht immer noch nicht.

Hier mal die genauen Linker Fehler:

Code: Alles auswählen

1>     Bibliothek "..\..\..\bin\Game.lib" und Objekt "..\..\..\bin\Game.exp" werden erstellt.
1>SceneManager.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""protected: virtual void __thiscall Mrl::AmbientLight::ActivateSub(unsigned int,unsigned int,class CMatrix4x4 const &)" (?ActivateSub@AmbientLight@Mrl@@MAEXIIABVCMatrix4x4@@@Z)".
1>Assimp.lib(BlenderLoader.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateEnd".
1>Assimp.lib(XFileParser.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateEnd".
1>Assimp.lib(unzip.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateEnd".
1>Assimp.lib(BlenderLoader.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflate".
1>Assimp.lib(XFileParser.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflate".
1>Assimp.lib(unzip.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflate".
1>Assimp.lib(BlenderLoader.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateInit2_".
1>Assimp.lib(XFileParser.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateInit2_".
1>Assimp.lib(unzip.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateInit2_".
1>Assimp.lib(XFileParser.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateSetDictionary".
1>Assimp.lib(XFileParser.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_inflateReset".
1>Assimp.lib(unzip.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_crc32".
1>Assimp.lib(unzip.obj) : error LNK2001: Nicht aufgelöstes externes Symbol "_get_crc_table".
1>..\..\..\bin\Game.exe : fatal error LNK1120: 8 nicht aufgelöste externe Verweise.
Wie man sieht, eine Funktion in Mrl (die dort aber definitiv drin ist) und ne ganze Menge Assimpkram (welchen ich nur über Mrl benutze). Das macht alles keinen Sinn, weil er alles finden müsste, und es bei dem Viewer ja auch tut.

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 14:53
von Schrompf
Schau mal in Deine Assimp-Buildsettings. Es gibt ein spezielles Define, dass man bei Assimp angeben kann, so dass es keine eigene zlib mitkompiliert, sondern sich auf eine extern dazugelinkte ZLib verlässt. Wenn Du das Define gesetzt hast, würde das die den Effekt erklären. Denkbar wäre allerdings auch ein C-C++-Konflikt - unter C++ werden wegen möglicher Operatorüberladungen die Funktionsnamen mit Parameterinfos vermischt. Wenn Du z.B. irgendwo die zlib-Funktionen innerhalb eines "extern C"-Blocks deklariert hast, an anderer Stelle aber ohne das "extern C" deklarierst und kompilierst, würden auch solche Fehlermeldungen kommen.

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 16:17
von Jonathan
Aber ich habe nie explizit was mit zlib gemacht, ich habe immer nur Assimp direkt benutzt. Ich hab nie zlib so runter geladen und isntalliert, und in den Projektoptionen vom Viewer steht schon gar nix wegen zlib, von daher sollte es doch eigentlich alles finden...
Gibts evtl. n Tool, mit dem man gucken kann, was in die lib exportiert wurde?

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 16:35
von kimmi
Ja, das gibt es. Es heisst dumpbin.exe. Du kann dieses im VS-Eingabeprompt benutzen, dann brauchst du nicht deine PATH-Variable anzupassen. Oder du suchst im Netz mal nach depends.exe, das bringt noch gleich eine GUI mit.
Womit hast du die Workspaces von assimp und deinem Code generiert? Das PK3-Archiv imlpementiert für den BSP-Loader benutzt die unzip-Library, die wiederum auf zlib basiert. Und meines Wissens nach ist zlib per Default Teil von Assimp. Allerdings muss man dem Studio explizit sagen, dass man den zlib-code als C-Code zu übersetzen hat ( da hättest du aber Compiler-Fehler ). Für mich riecht das nun mehr nach Call-Convention zwischen der Contrib-Lib zlib und dem Rest.
Und sorry für meine falsch Färte, ich habe die Namen für Runtime-Zeug statt zlib-Zeug gehalten.

Gruß Kimmi

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 18:09
von eXile
Schau dir die DLLs erst einmal mit depens an. Ich habe gerade inkonsistente Calling-Conventions im Verdacht (dabei werden dann die Namen falsch dekoriert).

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 18:42
von BeRsErKeR
DLLs beim statischen Linken?

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 19:32
von eXile
BeRsErKeR hat geschrieben:DLLs beim statischen Linken?
Dann ersetze halt DLL durch Library, ich würde mir trotzdem dort die Calling-Convention mal reinziehen.

Re: Vorgehen bei Linkerfehlern

Verfasst: 21.01.2011, 22:59
von Krishty
Schrompf hat geschrieben:Schau mal in Deine Assimp-Buildsettings. Es gibt ein spezielles Define, dass man bei Assimp angeben kann, so dass es keine eigene zlib mitkompiliert, sondern sich auf eine extern dazugelinkte ZLib verlässt.
Falls er meine Assimp-Projektdateien aus diesem Thread benutzt, ist es das.

Hat schon einen Sinn, wenn ich das dazuschreibe; meine Projekte sind immer sehr eigen konfiguriert ;) Entweder mein beigelegtes zlib-Projekt linken oder ASSIMP_BUILD_NO_OWN_ZLIB aus den Präprozessorsymbolen entfernen und zlib manuell aus dem Repository ins Projekt hinzufügen.

Re: Vorgehen bei Linkerfehlern

Verfasst: 25.01.2011, 23:41
von Jonathan
Ok, das mit dem zlib hat schonmal funktioniert. Vermutlich war zlib einfach in den Qt Klassen mit drinne, darum ging es im Viewer, im Spiel aber nicht.
Allerdings hab ich jetzt weiterhin das Problem, dass 2 Funktionen, die in Mrl.lib drin sein müssen nicht gefunden werden. Der Editor findet die glewInit nicht, die Spiel und Viewer anscheinend finden, und das Spiel findet Mrl::AmbientLight::ActivateSub nicht, und ich finde beim besten willen nicht, wie das nich definiert sein könnte...
Ich werde jetzt mal dumpbin und depends ausprobieren (eXile, meintest du damit den Dependency Walker, das ist jedenfalls das, was ich beim Suchen finde?) und gucken ob ich da weiter komme. Aber nur noch 1 Linkerfehler pro Projekt, das ist doch mal was :)

[edit]

Ok, hier ist schonmal was: Die Fehlermeldung beim Compilieren von Game:

Fehler 1 error LNK2001: Nicht aufgelöstes externes Symbol ""protected: virtual void __thiscall Mrl::AmbientLight::ActivateSub(unsigned int,unsigned int,class CMatrix4x4 const &)" (?ActivateSub@AmbientLight@Mrl@@MAEXIIABVCMatrix4x4@@@Z)".

Was dumpbin findet:
60501020 flags
Code
COMDAT; sym= "protected: virtual void __thiscall Mrl::AmbientLight::ActivateSub(unsigned int,unsigned int,class Mrl::CMatrix4x4 const &)" (?ActivateSub@AmbientLight@Mrl@@MAEXIIABVCMatrix4x4@2@@Z)
16 byte align
Execute Read

Und wenn ich die Funktion tatsächlich auskommentiere und den Viewer erstellen will, findet er die selbe Funktion nicht, die sonst drin ist, also ?ActivateSub@AmbientLight@Mrl@@MAEXIIABVCMatrix4x4@2@@Z, während hingegen das Spiel scheinbar nach ?ActivateSub@AmbientLight@Mrl@@MAEXIIABVCMatrix4x4@@@Z sucht (die letzten paar Zeichen sind anders).
WIe kann das kommen? Kann es irgendwie an dem typedef von "typedef CMatrix mrlMatrix;" liegen?

Re: Vorgehen bei Linkerfehlern

Verfasst: 26.01.2011, 00:08
von Krishty
Jonathan hat geschrieben:und das Spiel findet Mrl::AmbientLight::ActivateSub nicht, und ich finde beim besten willen nicht, wie das nich definiert sein könnte...
#error einbauen um zu gucken, ob sie überhaupt kompiliert wird. Wenn ja, Deklaration und Definition posten.

Re: Vorgehen bei Linkerfehlern

Verfasst: 26.01.2011, 00:20
von Jonathan
Das mit dem #error hab ich gecheckt, sie wird kompiliert. Ich poste mal den Code:

Code: Alles auswählen

#include "AmbientLight.hpp"

#include <sstream>
using namespace std;

namespace Mrl
{

std::string AmbientLight::GetFragmentGlobalsSub(unsigned int ID)
{
	return string();
}

std::string AmbientLight::CalcDiffuseColor(unsigned int ID)
{
	stringstream s;
	s << " " << GetColor(ID) << " * MaterialColor //Ambient Light " << ID << "\n";
	return s.str();
}

void AmbientLight::ActivateSub(GLuint ShaderProgram, unsigned int ID, const Mrl::mrlMatrix &LightTransformation)
{
}

}

Code: Alles auswählen

#ifndef MRL_AMBIENT_LIGHT
#define MRL_AMBIENT_LIGHT


#include "Types.hpp"
#include "Light.hpp"


namespace Mrl
{

class AmbientLight : public Light
{	
public:
	virtual std::string CalcDiffuseColor(unsigned int ID); ///< generates the lightcalculation source
protected:
	virtual std::string GetFragmentGlobalsSub(unsigned int ID); ///< generates the variable declaration source
	virtual void ActivateSub(GLuint ShaderProgram, unsigned int ID, const mrlMatrix& LightTransformation);///< set the variables in the shader, to activate this light
};

}

#endif
Wie gesagt, ich hab noch ein bisschen weiter getestet, (siehe edit im vorherigen Post).

Re: Vorgehen bei Linkerfehlern

Verfasst: 26.01.2011, 00:37
von Krishty
Ups, habe den Nachtrag übersehen … mit Name Mangling kenne ich mich leider nicht aus. Sind denn CMatrix4x4 und Mrl::CMatrix4x4 dasselbe? D.h. existieren keine zwei Definitionen der Klasse CMatrix4x4 (einmal im globalen Namespace und einmal in Mrl)?

Re: Vorgehen bei Linkerfehlern

Verfasst: 26.01.2011, 10:50
von Jonathan
So, mittlerweile funktioniert alles :)

Das mit der Matrix war ne ganz dumme Sache. Ich habe scheinbar im Spiel und in Mrl die selbe Matrixklasse benutzt, nur in Mrl die irgendwann mal in den namespace Mrl gepackt. Da ich clevererweise die gleiche Datei von der Matrixklasse benutzt habe, waren auch die include guards gleich, so hab ich nicht gemerkt, dass ich die Klasse doppelt drin hatte (ich sollten denen wirklich präfixe verpassen...)
Das Problem mit dem Editor war die alte Nummer, dass man GLEW_STATIC definieren muss. Allerdings hab ich keine Ahnung, wie der Viewer so kompilieren konnte, aber naja, jetzt geht es überall.

Nochmal ein herzliches Dankeschön für alle, die mir bei diesem demotivierenden Fehler geholfen haben!