(gelöst)[VC++08] Lib, static const, x64, unresolved external

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

(gelöst)[VC++08] Lib, static const, x64, unresolved external

Beitrag von Krishty »

Hi,

Heute mal ein uneindeutiger Titel, weil er sonst zu lang geworden wäre:

Ich habe zwei Projekte, nennen wir sie „Framework“ und „Engine“. Framework ist eine statische Lib, Engine eine ausführbare Datei, die zu Framework linkt und Header-Dateien davon #includet.

Im Framework ist eine Klasse deklariert. Die enthält zwei Konstanten, static const deklariert – beide werden von Memberfunktionen, die hinterher in der Lib landen, referenziert (aber nicht direkt vom Projekt Engine, sondern dieses linkt nur die fertigen Funktionen).

In x86-Builds funktioniert das immer. In x64-Builds nur meistens – nämlich genau dann nicht, wenn die zweite Konstante über die Erste berechnet wird. Dann wird beim Kompilieren von Engine ein Linker-Fehler (unresolved external symbol) für die Zweite geschmissen. (Language Extensions sind übrigens immer aus.)

Soo, das Ganze ist nicht nur verzwickt, sondern wegen langer Kompilierzeiten auch nicht durch Trial’n’Error zu beheben … darum habe ich zwei Fragen:

1. Microsofts x64-Compiler arbeitet strenger nach dem Standard als sein x86-Gegenstück, vielleicht liegt es daran.? Darum möchte ich zuerst wissen, ob das hier erlaubt ist (man beachte, dass die Konstanten im x64-Build acht Bytes groß werden!):

Code: Alles auswählen

struct X {
    static const size_t A = 1;
    static const size_t B = A + 1;
};
2. Der Linker hat ja fast hunderte Optionen, welche würdet ihr am ehesten mit solchen Fehlern in Verbindung bringen?

Gruß, Ky
Zuletzt geändert von Krishty am 09.11.2009, 19:30, insgesamt 2-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Helmut »

Hi,
Wenn dein Code kompiliert wüssste ich nicht, was da schief gehen könnte..

Ich würde einfach ein paar Sachen ausprobieren, um dem Fehler auf die Schliche zu kommen. Funktioniert es, wenn du die Konstanten in einem enum deklarierst oder wenn du sie global deklarierst?

Aber ich glaub irgendwie nicht, dass dein Code dem geposteten Code entspricht. Poste mal den echten.

Ciao
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Krishty »

Helmut hat geschrieben:Ich würde einfach ein paar Sachen ausprobieren, um dem Fehler auf die Schliche zu kommen. Funktioniert es, wenn du die Konstanten in einem enum deklarierst oder wenn du sie global deklarierst?
Als enum ebenfalls „unresolved external symbol“, global funktioniert zwar die eine Konstante, aber alle anderen Konstanten, die ihren Wert kopieren, werden dann als „unresolved external symbol“ gemeldet.
Helmut hat geschrieben:Aber ich glaub irgendwie nicht, dass dein Code dem geposteten Code entspricht. Poste mal den echten.
Der echte Code sind viele viele Zeilen, aber ich versuche mal, das Wichtigste rauszubrechen … im Framework:

Code: Alles auswählen

// Typnamen sind aufgelöst, eigentlich hängen da noch mehrere typedefs und templates zwischen
typedef unsigned long long UInt8;
class Cric::Graphics::CImage {
	class CProperties {
		static size_t const MaximalDimensionInPixels = 65536;
		static size_t const MaximalLineSize = sizeof(TCBlock<EFormat::R32G32B32A32_Float>) * MaximalDimensionInPixels;
		// Sieht kompliziert aus, ist aber nur size_t(MIN(UInt8(size_t(-1)), UInt8(MaximalLineSize) * UInt8(MaximalDimensionInPixels)));
		// Falls MaximalDimensionInPixels * MaximalLineSize unter 32 Bits nämlich größer als 0xFFFFFFFF werden sollte, soll es auf 0xFFFFFFFF zurückgeclamped werden.
		static size_t const MaximalSize = size_t(
			UInt8(size_t(-1)) < (UInt8(MaximalLineSize) * UInt8(MaximalDimensionInPixels))
				? UInt8(size_t(-1))
				: (UInt8(MaximalLineSize) * UInt8(MaximalDimensionInPixels))
			);
	public:
		CProperties(…) {
			// …
			UInt8 const l_ThisSize = UInt8(this->m_LineSize) * UInt8(this->HeightInBlocks());
			if(l_ThisSize > MaximalSize)
				throw ::std::invalid_argument("…");
		}
	}; // class CProperties
	CProperties m_Properties;
}; // class Cric::Graphics::CImage
Sobald Cric::Graphics::CImage in der Anwendung instanziert wird:

Code: Alles auswählen

1>CricD.lib(Cric_Graphics_CImage.obj) : error LNK2019: unresolved external symbol "public: static unsigned __int64 const Cric::Graphics::CImage::CProperties::MaximalSize" (?MaximalSize@CProperties@CImage@Graphics@Cric@@2_KB) referenced in function "public: __cdecl Cric::Graphics::CImage::CProperties::CProperties(enum Cric::Graphics::EFormat::Value,float,unsigned __int64,unsigned __int64,unsigned __int64)" (??0CProperties@CImage@Graphics@Cric@@QEAA@W4Value@EFormat@23@M_K11@Z)
1>..\..\..\Compilations\Bieder\x64D\Bieder.exe : fatal error LNK1120: 1 unresolved externals
In einer anderen Klasse passiert dasselbe. Konstruiere ich so eine Situation in der Anwendung statt im Framework, kann ich den Fehler bisher nicht reproduzieren.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Helmut »

Probier mal Framework.lib mit Notepad oder so zu öffnen und schau nach ob "?MaximalSize@CProperties@CImage@Graphics@Cric@@2_KB" darin vorkommt. Jedes Zeichen sollte gleich sein, also genau hinschauen.
Vielleicht ist auch size_t in den Modulen unterschiedlich definiert, aber das wär wohl früher aufgefallen. (es gibt glaub ich ne Option für defaultmäßiges unsigned/signed)
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von kimmi »

Du kannst auch mittels dumpbin.exe ( im Visual-Studio-Eingabeprompt eingeben oder in das entsprechende Verzeichnis wechseln ) nach dem fehlenden Symbol in der Library suchen und schauen, ob das überhaupt vorhanden ist bzw. in wie weit sich das vom erwarteten Symbol unterscheidet, wenn der Fehler beim Linken auftritt. Vielleicht ist das ja auch ein bekanntes Problem, für das man in der MSDN schon einen dokumentierten Workaround veröffentlicht hat.

Gruß Kimmi
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von TGGC »

Anstatt das wichtigste rauszubrechen, koenntest du nicht mal ein Minmalbeispiel erstellen, das fehlschlaegt? Eigentlich sollte so ein Konstrukt ja erlaubt sein. Ich vermute den Fehler daher erstmal noch woanders. f'`8k

[ ] Autocogito


Gruß, TGGC (Was Gamestar sagt...)
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von kimmi »

TGGC hat geschrieben:Anstatt das wichtigste rauszubrechen, koenntest du nicht mal ein Minmalbeispiel erstellen, das fehlschlaegt? Eigentlich sollte so ein Konstrukt ja erlaubt sein. Ich vermute den Fehler daher erstmal noch woanders. f'`8k

[ ] Autocogito


Gruß, TGGC (Was Gamestar sagt...)
*Zustimm*

Das riecht nach einem Tool-Problem.

Gruß Kimmi
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Krishty »

Danke für die Antworten!
Helmut hat geschrieben:Probier mal Framework.lib mit Notepad oder so zu öffnen und schau nach ob "?MaximalSize@CProperties@CImage@Graphics@Cric@@2_KB" darin vorkommt. Jedes Zeichen sollte gleich sein, also genau hinschauen.
Es ist drin, zumindest taucht der Name einmal auf. Übrigens dürfte das Symbol afaik auch nochmal in der Anwendung auftauchen, schließlich kompiliert die den Header ebenfalls?
Helmut hat geschrieben:Vielleicht ist auch size_t in den Modulen unterschiedlich definiert, aber das wär wohl früher aufgefallen. (es gibt glaub ich ne Option für defaultmäßiges unsigned/signed)
Nein, das ist es nicht.
kimmi hat geschrieben:Du kannst auch mittels dumpbin.exe ( im Visual-Studio-Eingabeprompt eingeben oder in das entsprechende Verzeichnis wechseln ) nach dem fehlenden Symbol in der Library suchen und schauen, ob das überhaupt vorhanden ist bzw. in wie weit sich das vom erwarteten Symbol unterscheidet, wenn der Fehler beim Linken auftritt.
Werde ich heute nachmittag probieren.
kimmi hat geschrieben:Vielleicht ist das ja auch ein bekanntes Problem, für das man in der MSDN schon einen dokumentierten Workaround veröffentlicht hat.
Kann sein, ist ja schon ziemlich speziell – dass ausgerechnet zwei Symbole aus hunderten fehlen …
TGGC hat geschrieben:Anstatt das wichtigste rauszubrechen, koenntest du nicht mal ein Minmalbeispiel erstellen, das fehlschlaegt?
Wie gesagt, reproduzieren konnte ich es bisher nicht. Ich werde mein Projekt heute nachmittag wohl mal bis aufs Minimale zerschmettern.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von kimmi »

Das Linken war, solange ich es benutze, im Visual-Studio schon immer eine heikle Sache. Unzählige Male haben wir im Büro unresolved Symbols gehabt, die nach einem kompletten Rebuild plötzlich verschwunden waren. Wir konnten das auch nie reproduzieren ( und das ist ja auch eigentlich nicht unsere Aufgabe ).

Gruß Kimmi
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Helmut »

Krishty hat geschrieben:Es ist drin, zumindest taucht der Name einmal auf. Übrigens dürfte das Symbol afaik auch nochmal in der Anwendung auftauchen, schließlich kompiliert die den Header ebenfalls?
In der Anwendungslib muss der Name natürlich auch auftauchen, aber es wär schon absonderlich, wenn sich der von dem Namen in der Fehlermeldung unterscheiden würde.

Inwischen tippe ich auf einen Fehler vom Optimierer. Zumindest würde dafür sprechen, wenn sich der Fehler nur mit aktivierten Optimierungen abspielt, allerdings auch nicht zwingenderweise. Konstanten zu inlinen ist wohl das grundlegendste überhaupt, das macht der denke ich auch im Debugmodus.

Aber eigentlich würd ich deshalb jetzt nicht so ein Tata machen und die Konstanten einfach global machen und fertig. ;)

Ciao

PS: Davon, dass er einen Rebuild gemacht hat, bin ich eigentlich überzeugt:)
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von kimmi »

Ich wollte auch nicht kritisieren, sondern vielmehr meinem Unmut über einen gewissen Linker / Compiler Luft machen. Muß auch mal sein :).

Gruß Kimmi
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Krishty »

kimmi hat geschrieben:Unzählige Male haben wir im Büro unresolved Symbols gehabt, die nach einem kompletten Rebuild plötzlich verschwunden waren.
Komplettreinigung und Rebuild habe ich schon drei- oder viermal gemacht, das ist bei solchen Fehlern schon meine erste Reflexhandlung (danke, Helmut).
Helmut hat geschrieben:Inwischen tippe ich auf einen Fehler vom Optimierer. Zumindest würde dafür sprechen, wenn sich der Fehler nur mit aktivierten Optimierungen abspielt, allerdings auch nicht zwingenderweise. Konstanten zu inlinen ist wohl das grundlegendste überhaupt, das macht der denke ich auch im Debugmodus.
Dem stimme ich zu ... der Fehler tritt auch ohne Optimierungen auf, was aber nicht heißt, dass da kein Optimierer am Werk ist.
Helmut hat geschrieben:Aber eigentlich würd ich deshalb jetzt nicht so ein Tata machen und die Konstanten einfach global machen und fertig. ;)
Nein, ich werde mein globales Namespace nicht verpesten. (Der Fehler tritt übrigens noch bei anderen Klassen mit anderen Konstanten auf, allerdings immer nur, wenn die Konstanten 64 Bits weit sind.) Es geht - wie immer - ums Prinzip ;) Notfalls sitze ich es aus, bis constexpr zur Hilfe eilt :D

Ich habe heute morgen schon versucht, die Konstante zusätzlich zu referenzieren, indem ich eine weitere Konstante über sie berechnen lasse. Was nämlich auffällt ist, dass die Konstanten, auf denen das verschwundene Symbol aufbaut, nicht verschwinden, sondern, wie ich dachte, nur das letzte Glied der Kette. Hat aber leider nichts gebracht, wahrscheinlich, weil die neue Konstante in keiner Funktion aufgetaucht ist ...

Als Nächstes werde ich den Operator ?: durch ein Min-Template ersetzen. Vielleicht ändert es ja was, wenn die Konstante nicht direkt vor Ort definiert wird, sondern Min<0xFFFFFFFF, 0xKA>::Value referenziert. Ich habe hier aber keinen x64-Compiler, Ergebnisse gibt es also frühestens heute nachmittag.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Helmut
Establishment
Beiträge: 237
Registriert: 11.07.2002, 15:49
Wohnort: Bonn
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Helmut »

Krishty hat geschrieben:Notfalls sitze ich es aus, bis constexpr zur Hilfe eilt :D
Na dann wird es dich ja richtig freuen, dass constexpr auch in VS2010 nicht implementiert sein wird :)

Aber das mit der zusätzlichen Referenzierung ist doch ne gute Idee. Nur ist dein Ansatz natürlich zum Scheitern verurteilt gewesen, weil der Optimierer ja die neue Konstante auch wegoptimieren wird. Ich würde die Adresse der Konstante mal an einer Stelle einbauen, die nicht optimiert werden kann. Als Parameter einer Funktion aus einer anderen DLL oder so.

Ciao
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Krishty »

Helmut hat geschrieben:Na dann wird es dich ja richtig freuen, dass constexpr auch in VS2010 nicht implementiert sein wird :)
Neeeeeeiiiiiiiiiiiiiin! Auch in der Final-Version nicht?!? Die nächsten zwei Jahre sind sinnlos -.- Ehrlich, dann ziehe ich in ein Kloster im Himalaja und gehe da in mich …

Btw könnte ich mal versuchen, den Code mit VC++ 2010 Beta 2 zu kompilieren. Ich befürchte nur, dass das ein echtes Massaker werden könnte, wenn sich da seit der ersten Beta nicht eine Menge geändert hat …
Helmut hat geschrieben:Aber das mit der zusätzlichen Referenzierung ist doch ne gute Idee. Nur ist dein Ansatz natürlich zum Scheitern verurteilt gewesen, weil der Optimierer ja die neue Konstante auch wegoptimieren wird. Ich würde die Adresse der Konstante mal an einer Stelle einbauen, die nicht optimiert werden kann. Als Parameter einer Funktion aus einer anderen DLL oder so.
Wäre eine Ausgabe der Adresse mit ::std::cout akzeptabel? Habe gerade keine DLL-Funktionen zur Hand, außer der WinAPI, und als Parameter für GetSystemTime() wäre die Adresse vielleicht nicht so dolle.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Krishty »

Soo … wenn ich die zusätzliche Konstante, die auf der Fehleranfälligen aufbaut, referenziere, dann erhalte ich beim Linken beide als unaufgelöste externe Symbole.

Das Template hat auch nichts geändert.

VCpp 2010 kompiliert nicht, Fehler in ostream -.-

Ich habe die Symbole der Bibliothek per dumpbin /SYMBOLS anzeigen lassen. Für die fragliche Konstante findet sich:

Code: Alles auswählen

E1C 00000000 UNDEF  notype       External     | ?MaximalSize@CProperties@CImage@Graphics@Cric@@2_KB (public: static unsigned __int64 const Cric::Graphics::CImage::CProperties::MaximalSize)
Was mich wundert ist, dass sich für keine der anderen Konstanten ein Eintrag finden lässt? Ich meine, die werden alle im Code verwendet, sogar auf quasi-gleiche Art und Weise … warum wird nur die Eine exportiert? Und warum wird sie überhaupt exportiert? Die Konstante steht doch direkt in der Header-Datei, ich wüsste nicht, warum die External-Linkage bekommen sollte?

Mit den Linker-Interna habe ich bisher selten zu tun gehabt, also verzeiht, wenn die Frage dumm ist.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Aramis »

Möglicherweise Offtopic: Wir haben bei Assimp seit längeren ein aus mysteriösen Gründen nicht exportiertes Symbol .. kein Linker exportiert es ordentlich, dabei konnte bislang noch KEINER der über den Quellcode geschaut hat herausfinden was genau der Unterschied zu einer direkt darunter deklarierten und definierten, ähnlich oft referenzierten und absolut tadellos exportierten Funktion ist .. scheint in dem Fall aber eher mit C/C++-Calling-Conventions zusammenzuhängen. Quintessenz: nicht immer ist mysteriöses Linkerverhalten aufklärbar ..
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [VC++08] Lib, static const, x64, unresolved external symbol

Beitrag von Krishty »

HA!

Das war jetzt *wirklich* verzwickt …

Also: Ich habe die Konstante in der Member-Funktion verwendet, um einen Parameter dagegen zu testen. Was ich nicht erwähnt habe, war, dass ich auch eine Fehlermeldung ausgebe, wenn der Vergleich fehlschlägt:

Code: Alles auswählen

if(Param > MaximalSize) {
    ::std::cerr << "Param ist " << Param << ", aber Maximum wäre " << StringFromByteSize(MaximalSize) << ::std::endl;
    throw ::std::invalid_argument("Param");
}
Der Vergleich war kein Problem. Das Problem war die Ausgabe, denn StringFromByteSize() ist deklariert als StringFromByteSize(unsigned long long const & Size) – der Aufruf hat also eine Referenz zur Konstanten MaximalSize erzwungen, deshalb wurde daraus ein externes Symbol. Ändere ich die Deklaration der Funktion, so dass MaximalSize by-Value übergeben wird, kann der Linker seinen Job erfüllen. Vielleicht hilft das auch Aramis?

Da das im x86-Build nicht passiert und man die Übergabe by-Reference auch bei nativen Datentypen für Template-Programmierung ständig braucht: Ist das ein Bug oder legitimes Verhalten?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten