CONFIG +=staticlib を使用して Qt アプリをビルドすると、vtable エラーへの未定義の参照が発生する



編集:この投稿を大幅に編集して、プロジェクトをその本質にまで落とし込みました。この投稿で参照されていないファイルを含む Github リポジトリも追加しました。



subdirs を使用する Qt Creator プロジェクト (qmake、Qt 5.2.0、Creator 3.0.0) があります。 テンプレート。 3 つのサブプロジェクトがあります:



  1. Stadium - TEMPLATE = lib として構成されている図書館 そして CONFIG += staticlib .

  2. Football - TEMPLATE = lib として設定されたライブラリ と CONFIG += staticlib Field を使用します ライブラリ

  3. サーバー - スタジアム ライブラリとフットボール ライブラリの両方を使用する QML アプリケーション


このアプリケーションは、Windows 8.1 (MSVC2012) と Linux (gcc 4.8.1) の両方でビルドしています。 Windows では問題なく動作します 、しかし、Linux ビルドは奇妙な動作をします。


エラーは次のようになります:


undefined reference to 'vtable for Stadium::Engine'

このプロジェクトを、エラーを表示する一連のベア ファイルに書き直しました。 Github で見つけることができます:Football.自由に複製して、すべてのエラーを自分で確認してください。 661441c commit は問題を解決し、 09836f9 commit にエラーが含まれています。


Stadium Engine.h ファイルは抽象クラスです。次のようになります:


#ifndef STADIUM_ENGINE_H
#define STADIUM_ENGINE_H
#include <QObject>
namespace Stadium {
class Engine : public QObject
{
Q_OBJECT
public slots:
virtual void executeCommand() = 0;
};
} // namespace Stadium
#endif // STADIUM_ENGINE_H

上記の Stadium Engine.h ファイルから継承した Football Engine.h ファイルは次のとおりです。


#ifndef FOOTBALL_ENGINE_H
#define FOOTBALL_ENGINE_H
#include <QObject>
#include "../Stadium/Engine.h"
namespace Football
{
class Engine : public Stadium::Engine
{
Q_OBJECT
public:
Engine();
~Engine() {}
public slots:
void executeCommand();
};
} // namespace Football
#endif // FOOTBALL_ENGINE_H

そして、Football Engine.cpp ファイル:


#include "Engine.h"
#include <QDebug>
Football::Engine::Engine()
{
qDebug() << "[Football::Engine] Created.";
}
void Football::Engine::executeCommand()
{
qDebug() << "[Football::Engine] The command was executed.";
}

コンストラクター定義を cpp からヘッダー ファイルに移動すると、エラーなしでビルドされます。


以下は Server.pro ファイルです。静的リンクの説明 (Qt Creator によって自動生成される) が同じように見えるという点で、他のすべての pro ファイルを示しています。


QT       += core
QT -= gui
TARGET = Server
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Stadium/release/ -lStadium
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Stadium/debug/ -lStadium
else:unix: LIBS += -L$$OUT_PWD/../Stadium/ -lStadium
INCLUDEPATH += $$PWD/../Stadium
DEPENDPATH += $$PWD/../Stadium
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/release/libStadium.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/debug/libStadium.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/release/Stadium.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/debug/Stadium.lib
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../Stadium/libStadium.a
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Football/release/ -lFootball
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Football/debug/ -lFootball
else:unix: LIBS += -L$$OUT_PWD/../Football/ -lFootball
INCLUDEPATH += $$PWD/../Football
DEPENDPATH += $$PWD/../Football
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/release/libFootball.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/debug/libFootball.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/release/Football.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/debug/Football.lib
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../Football/libFootball.a

クリーニング、qmake の再実行、ビルド ディレクトリの削除、および再構築を試みました。このプロジェクトを Linux でビルドする唯一の方法は、CONFIG += staticlib を削除することです。 Stadium ライブラリの .pro ファイルの行 (および対応する else:unix: PRE_TARGETDEPS += $$OUT_PWD/../stadium/libstadium.a もちろん、Game.pro の行も)。これにより、プロジェクトが正常にビルドされ、問題なく実行されます。しかし、私はその理由を理解していません。また、コンストラクター定義が定義されている場所が重要な理由もわかりません。


アイデアはありますか?


いくつかのコードの回答


undefined reference to 'vtable for Stadium::Engine' 
#ifndef STADIUM_ENGINE_H #define STADIUM_ENGINE_H  #include <QObject>
namespace Stadium { class Engine : public QObject {
Q_OBJECT public slots:
virtual void executeCommand() = 0;
};
} // namespace Stadium #endif // STADIUM_ENGINE_H
#ifndef FOOTBALL_ENGINE_H #define FOOTBALL_ENGINE_H  #include <QObject>
#include "../Stadium/Engine.h" namespace Football { class Engine : public Stadium::Engine {
Q_OBJECT public:
Engine();
~Engine() {} public slots:
void executeCommand();
};
} // namespace Football #endif // FOOTBALL_ENGINE_H
#include "Engine.h"  #include <QDebug>
Football::Engine::Engine() {
qDebug() <<
"[Football::Engine] Created.";
} void Football::Engine::executeCommand() {
qDebug() <<
"[Football::Engine] The command was executed.";
}
QT
+= core QT
-= gui TARGET = Server CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Stadium/release/ -lStadium else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Stadium/debug/ -lStadium else:unix: LIBS += -L$$OUT_PWD/../Stadium/ -lStadium INCLUDEPATH += $$PWD/../Stadium DEPENDPATH += $$PWD/../Stadium win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/release/libStadium.a else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/debug/libStadium.a else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/release/Stadium.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Stadium/debug/Stadium.lib else:unix: PRE_TARGETDEPS += $$OUT_PWD/../Stadium/libStadium.a win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Football/release/ -lFootball else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Football/debug/ -lFootball else:unix: LIBS += -L$$OUT_PWD/../Football/ -lFootball INCLUDEPATH += $$PWD/../Football DEPENDPATH += $$PWD/../Football win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/release/libFootball.a else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/debug/libFootball.a else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/release/Football.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../Football/debug/Football.lib else:unix: PRE_TARGETDEPS += $$OUT_PWD/../Football/libFootball.a
g++ [...] -lStadium [...] -lFootball  
[...]  SOURCES += main.cpp  LIBS += -L$$OUT_PWD/../Football/ -lFootball INCLUDEPATH += $$PWD/../Football DEPENDPATH += $$PWD/../Football PRE_TARGETDEPS += $$OUT_PWD/../Football/libFootball.a  LIBS += -L$$OUT_PWD/../Stadium/ -lStadium INCLUDEPATH += $$PWD/../Stadium DEPENDPATH += $$PWD/../Stadium PRE_TARGETDEPS += $$OUT_PWD/../Stadium/libStadium.a 
g++ [...] -lFootball [...] -lStadium 
inline Stadium::Engine::Engine() {} inline Stadium::Engine::~Engine() {}