Eclipse-CDTを使用して、Ubuntu x64でC++プロジェクトをセットアップしています。私は基本的にハローワールドをやっていて、商用のサードパーティライブラリにリンクしています。
ライブラリにリンクされたヘッダーファイルを含めましたが、それでもリンカーエラーが発生します。ここには明らかな問題以外に考えられる問題がありますか(例:正しいライブラリにリンクしていることを99%確信しています)。
Eclipseは言う:
ビルドターゲット:LinkProblem 呼び出し:GCC C++リンカー g ++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o "LinkProblem" ./ src/LinkProblem.o -lsomelib1 -lpthread -lsomelib2 -lsomelib3 ./ src/LinkProblem.o:関数 `main ': /home/notroot/workspace/LinkProblem/Debug/..内/src/LinkProblem.cpp:17: `SomeClass :: close() ' ./ src/LinkProblem.o:関数` SomeOtherClass': /home/notroot/workspaceへの未定義の参照/somelib-3/somelib/include/sql/somefile.h:148: `SomeClass :: SomeClass() ' /home/notroot/workspace/somelib-3/somelib/include/sql /への未定義の参照somefile.h:148: `vtable for SomeOtherClass 'への未定義の参照 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151:` SomeClass ::〜への未定義参照SomeClass() ' ./ src/LinkProblem.o:関数 `〜SomeOtherClass': /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h: 140:SomeOthの `vtableへの未定義の参照erClass ' /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: `SomeClass :: ~~ SomeClass()' /home /への未定義の参照notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: `SomeClass ::〜SomeClass() ' collect2:ldが1つの終了ステータスを返しました make :*** [LinkProblem]エラー1
これらのメソッドがライブラリの1つにあると仮定すると、順序付けの問題のように見えます。
ライブラリを実行可能ファイルにリンクする場合、ライブラリは宣言された順序で実行されます。
また、リンカーは、現在未解決の依存関係を解決するために必要なメソッド/関数のみを使用します。後続のライブラリがオブジェクトに本来必要とされなかったメソッド/関数を使用する場合、依存関係が失われます。
使い方:
例:
オブジェクトに必要なもの:
Lib 1は以下を提供します。
Lib 2が提供するもの
このようにリンクされている場合:
gcc -o plop plop.o -l1 -l2
その後、リンカーは読み取りおよび書き込みシンボルの解決に失敗します。
しかし、次のようにアプリケーションをリンクすると:
gcc -o plop plop.o -l2 -l1
その後、正しくリンクされます。 l2はBatchReadとBatchWriteの依存関係を解決しますが、2つの新しい依存関係(読み取りと書き込み)も追加します。次にl1とリンクすると、4つの依存関係がすべて解決されます。
このリンカエラーは、(私の経験では)通常、宣言を使用して子クラスの仮想関数をオーバーライドしたが、メソッドの定義を与えていないことを意味します。例えば:
class Base
{
virtual void f() = 0;
}
class Derived : public Base
{
void f();
}
しかし、あなたはfの定義を与えていません。クラスを使用すると、リンカーエラーが発生します。通常のリンカエラーと同じように、コンパイラがあなたの言っていることを知っていたのに、リンカは定義を見つけることができなかったからです。メッセージを理解するのが非常に難しいだけです。
Qt C++は、クラスを変更してQObjectから継承するように(つまり、シグナル/スロットを使用できるように)クラスを変更すると、このエラーを表示します。 qmake -rを実行すると、mocが呼び出され、この問題が修正されます。
何らかのバージョン管理を介して他のユーザーと作業している場合は、.proファイルに変更を加えます(つまり、空白行を追加/削除します)。他の全員が変更を取得してmakeを実行すると、makeは.proファイルが変更されたことを確認し、qmakeを自動的に実行します。これにより、チームメイトがフラストレーションを繰り返すのを防ぎます。
私にとっての問題はかなりあいまいであることが判明しました。クラスは次のようになりました。
//-----------------------------------------
// 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;
}
//-----------------------------------------
問題はリンカにあります。私のヘッダーファイルはどこかのライブラリに入れられましたが、すべての仮想関数はクラス宣言で「インライン」で宣言されました。 (まだ)仮想関数を使用するコードがなかったため、コンパイラまたはリンカーは実際の関数本体を配置することを怠りました。また、vtableの作成にも失敗しました。
このクラスから派生したメインコードで、リンカーはクラスを基本クラスとそのvtableに接続しようとしました。しかし、vtableは破棄されていました。
解決策は、次のように、クラス宣言の外側で仮想関数の本体の少なくとも1つを宣言することでした。
//-----------------------------------------
// libbase.h
class base {
public:
base() { }
virtual ~base() ; //-- No longer declared 'inline'
virtual int foo() { return 0; }
};
//-----------------------------------------
//-----------------------------------------
// libbase.cpp
#include "libbase.h"
base::~base()
{
}
//-----------------------------------------
Qt4の問題に関しては、上記のqmake mocオプションを使用できませんでした。しかし、それはとにかく問題ではありませんでした。クラス定義に次のコードがありました:
class ScreenWidget : public QGLWidget
{
Q_OBJECT // must include this if you use Qt signals/slots
...
};
シグナルまたはスロットが定義されていないため、「Q_OBJECT」行を削除する必要がありました。
このエラーメッセージが表示されました。問題は、ヘッダーファイルで仮想デストラクタを宣言したことですが、仮想関数の本体は実際には実装されていませんでした。
このエラーは、基本クラスの定義なしで仮想関数を単に宣言した場合にも発生します。
例えば:
class Base
{
virtual void method1(); // throws undefined reference error.
}
上記の宣言を次の宣言に変更すると、正常に機能します。
class Base
{
virtual void method1()
{
}
}
私の場合、純粋な仮想クラスの1つの関数に= 0を追加するのを忘れたときに問題が発生しました。 = 0が追加されたときに修正されました。上記のフランクと同じです。
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
}
私もこの問題に出くわしました。アプリケーションは純粋な仮想インターフェイスクラスを定義し、共有ライブラリを介して提供されるユーザー定義クラスはインターフェイスを実装することになっています。アプリケーションをリンクする際、リンカは、共有ライブラリが基本クラスのvtableとtype_infoを提供しないこと、また他の場所に見つからないことを訴えました。インターフェースのメソッドの1つを純粋な仮想にすることを忘れていました(つまり、宣言の最後に「= 0」を省略しました。非常に初歩的で、リンカーの診断を根本的な原因。
純粋な仮想関数を持つ基本クラスがある場合は、基本クラスのコンストラクタとデストラクタに本体があることを確認してください。そうでない場合、リンカは失敗します。
私は将来の訪問者のためにこれを置きます:
Exception
オブジェクトの作成時にエラーを受け取った場合、その原因はおそらくwhat()
仮想関数の定義の欠如です。
Qtで「hello world」のようなことをしようとすると、このエラーメッセージが表示されました。問題は、qt moc(メタオブジェクトコンパイラ)を正しく実行し、これらのmocで生成されたファイルを正しくコンパイルして含めることでなくなりました。