Ich stelle ein C++ - Projekt auf Ubuntu x64 mit Eclipse-CDT ein. Ich mache im Grunde eine Hallo-Welt und verlinke mich zu einer kommerziellen Drittanbieter-Bibliothek.
Ich habe die Header-Dateien eingefügt, die mit ihren Bibliotheken verknüpft sind, aber ich erhalte immer noch Linker-Fehler. Gibt es hier andere mögliche Probleme als die offensichtlichen (z. B. bin ich zu 99% sicher, dass ich auf die richtige Bibliothek verlinke).
Eclipse sagt:
Erstellen des Ziels: LinkProblem Aufruf: GCC C++ Linker G ++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o "LinkProblem" ./src/LinkProblem.o - lsomelib1 -lpthread -lsomelib2 -lsomelib3 ./src/LinkProblem.o: In der Funktion `main ': /home/notroot/workspace/LinkProblem/Debug /../ src/LinkProblem.cpp: 17: undefined Verweis auf `SomeClass :: close () ' ./src/LinkProblem.o: In der Funktion' SomeOtherClass ': /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h : 148: nicht definierter Verweis auf `SomeClass :: SomeClass () ' /Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 148: nicht definierter Verweis auf` vtable for SomeOtherClass' /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: undefinierter Verweis auf `SomeClass :: ~ SomeClass () ' ./src/LinkProblem.o: In Funktion` ~ SomeOtherClass ': /Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140: nicht definierter Verweis auf `vtable für SomeOtherClass' /Home/notroot/workspace/somelib- 3/somelib/include/sql/somefile.h: 140: nicht definierter Verweis auf `SomeClass :: ~ SomeClass () ' /Home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140: undefinierter Verweis auf `SomeClass :: ~ SomeClass () ' Collect2: ld gab den Status 1 zurück Make: *** [LinkProblem] Fehler 1
Angenommen, diese Methoden befinden sich in einer der Bibliotheken, es sieht aus wie ein Problem mit der Reihenfolge.
Wenn Sie Bibliotheken in eine ausführbare Datei verlinken, werden sie in der Reihenfolge ausgeführt, in der sie deklariert sind.
.__ Der Linker verwendet nur die Methoden/Funktionen, die erforderlich sind, um derzeit ausstehende Abhängigkeiten aufzulösen. Wenn eine nachfolgende Bibliothek dann Methoden/Funktionen verwendet, die ursprünglich nicht für die Objekte erforderlich waren, fehlen Abhängigkeiten.
Wie es funktioniert:
Beispiel:
Objekte erfordert:
Lib 1 bietet:
Lib 2 bietet
Wenn so verlinkt:
gcc -o plop plop.o -l1 -l2
Dann löst der Linker die Lese- und Schreibsymbole nicht auf.
Aber wenn ich die Anwendung so verlinke:
gcc -o plop plop.o -l2 -l1
Dann wird es richtig verlinkt. Da l2 die BatchRead- und BatchWrite-Abhängigkeiten auflöst, fügt sie jedoch zwei neue hinzu (Lesen und Schreiben). Wenn wir uns mit l1 verbinden, werden alle vier Abhängigkeiten aufgelöst.
Dieser Linker-Fehler bedeutet normalerweise (meiner Erfahrung nach), dass Sie eine virtuelle Funktion in einer untergeordneten Klasse mit einer Deklaration überschrieben haben, jedoch keine Definition für die Methode angegeben haben. Zum Beispiel:
class Base
{
virtual void f() = 0;
}
class Derived : public Base
{
void f();
}
Aber Sie haben nicht die Definition von f gegeben. Wenn Sie die Klasse verwenden, wird der Linker-Fehler angezeigt. Ähnlich wie bei einem normalen Linker-Fehler, weil der Compiler wusste, worüber Sie sprachen, der Linker jedoch keine Definition fand. Es ist nur eine sehr schwer verständliche Botschaft.
Qt C++ zeigt diesen Fehler an, wenn Sie eine Klasse so ändern, dass sie jetzt von QObject erbt (dh, dass sie jetzt Signale/Slots verwenden kann). Das Ausführen von qmake -r ruft moc auf und behebt dieses Problem.
Wenn Sie über eine Art Versionskontrolle mit anderen Personen arbeiten, sollten Sie einige Änderungen an Ihrer .pro-Datei vornehmen (z. B. eine leere Zeile hinzufügen oder entfernen). Wenn alle anderen Ihre Änderungen erhalten und ausgeführt werden, stellt make fest, dass sich die .pro-Datei geändert hat, und führt automatisch qmake aus. Dies wird Ihre Teamkollegen davon abhalten, Ihre Frustration zu wiederholen.
Das Problem stellte sich für mich als ziemlich dunkel heraus. Meine Klasse sah so aus:
//-----------------------------------------
// libbase.h
class base {
public:
base() { }
virtual ~base() { }
virtual int foo() { return 0; }
};
//-----------------------------------------
//-----------------------------------------
// libbase.cpp
#include "libbase.h"
//-----------------------------------------
//-----------------------------------------
// main.h
class derived : public base {
public:
virtual int foo() ;
};
//-----------------------------------------
//-----------------------------------------
// main.cpp
int main () {
derived d;
}
//-----------------------------------------
Das Problem liegt im Linker. Meine Header-Datei befand sich irgendwo in einer Bibliothek, aber alle virtuellen Funktionen wurden in der Klassendeklaration als "Inline" deklariert. Da es noch keinen Code gab, der die virtuellen Funktionen verwendete, versäumte der Compiler oder Linker, die eigentlichen Funktionskörper zu implementieren. Die vtable konnte auch nicht erstellt werden.
In meinem Hauptcode, den ich aus dieser Klasse ableitete, versuchte der Linker, meine Klasse mit der Basisklasse und seiner Vtable zu verbinden. Der Tisch war jedoch verworfen worden.
Die Lösung bestand darin, mindestens einen Körper der virtuellen Funktionen außerhalb der Klassendeklaration zu deklarieren:
//-----------------------------------------
// libbase.h
class base {
public:
base() { }
virtual ~base() ; //-- No longer declared 'inline'
virtual int foo() { return 0; }
};
//-----------------------------------------
//-----------------------------------------
// libbase.cpp
#include "libbase.h"
base::~base()
{
}
//-----------------------------------------
Bei Problemen mit Qt4 konnte ich die oben erwähnte Option "qmake moc" nicht verwenden. Aber das war sowieso nicht das Problem. Ich hatte den folgenden Code in der Klassendefinition:
class ScreenWidget : public QGLWidget
{
Q_OBJECT // must include this if you use Qt signals/slots
...
};
Ich musste die Zeile "Q_OBJECT" entfernen, da ich keine Signale oder Slots definiert hatte.
Ich hatte diese Fehlermeldung. Das Problem war, dass ich in der Header-Datei einen virtuellen Destruktor deklariert habe, der Körper der virtuellen Funktionen jedoch nicht implementiert wurde.
Dieser Fehler tritt auch auf, wenn wir einfach eine virtuelle Funktion ohne Definition in der Basisklasse deklarieren.
Zum Beispiel:
class Base
{
virtual void method1(); // throws undefined reference error.
}
Ändern Sie die obige Deklaration in die unten stehende, es funktioniert einwandfrei.
class Base
{
virtual void method1()
{
}
}
In meinem Fall trat das Problem auf, als ich vergaß, in einer reinen virtuellen Klasse = 0 für eine Funktion hinzuzufügen. Es wurde behoben, als die 0 hinzugefügt wurde. Das gleiche wie für Frank oben.
class ISettings
{
public:
virtual ~ISettings() {};
virtual void OKFunction() =0;
virtual void ProblemFunction(); // missing =0
};
class Settings : ISettings
{
virtual ~Settings() {};
void OKFunction();
void ProblemFunction();
};
void Settings::OKFunction()
{
//stuff
}
void Settings::ProblemFunction()
{
//stuff
}
Ich bin jetzt auch über das Thema gestolpert. Die Anwendung definierte eine reine virtuelle Schnittstellenklasse, und eine über eine gemeinsam genutzte Bibliothek bereitgestellte benutzerdefinierte Klasse sollte die Schnittstelle implementieren. Beim Verknüpfen der Anwendung beklagte sich der Linker, dass die gemeinsam genutzte Bibliothek weder vtable und type_info für die Basisklasse bereitstellt noch anderweitig gefunden werden kann. Es stellte sich heraus, dass ich einfach vergessen habe, eine der Methoden des Interfaces rein virtuell zu machen (dh das "= 0" am Ende der Deklaration weggelassen. Sehr rudimentär, immer noch leicht zu übersehen und rätselhaft, wenn Sie den Linker nicht verbinden können Diagnose zur Ursache.
Wenn Sie eine Basisklasse mit einer reinen virtuellen Funktion haben, stellen Sie sicher, dass der Konstruktor und der Destruktor der Basisklasse über einen Body verfügen, ansonsten schlägt der Linker fehl.
Ich lege dies für zukünftige Besucher an:
wenn Sie beim Erstellen eines Exception
-Objekts den Fehler erhalten, liegt die Ursache wahrscheinlich darin, dass die virtuelle Funktion what()
nicht definiert wurde.
Ich hatte diese Fehlermeldung, als ich "Hallo Welt" wie Dinge mit Qt versuchte. Die Probleme wurden behoben, indem der qt moc (Meta-Objekt-Compiler) korrekt ausgeführt und diese Moc-Dateien korrekt kompiliert wurden.