La creación de la aplicación Qt con CONFIG +=staticlib provoca una referencia indefinida a errores de vtable

 C Programming >> Programación C >  >> Tags >> Qt
La creación de la aplicación Qt con CONFIG +=staticlib provoca una referencia indefinida a errores de vtable


EDITAR:he editado en gran medida esta publicación para reducir el proyecto a lo esencial. También agregué un repositorio de Github, incluidos los archivos a los que no se hace referencia en esta publicación.



Tengo un proyecto Qt Creator (qmake, Qt 5.2.0, Creator 3.0.0) que usa subdirs modelo. Hay tres subproyectos:



  1. Stadium:biblioteca que está configurada como TEMPLATE = lib y CONFIG += staticlib .

  2. Fútbol:biblioteca que está configurada como TEMPLATE = lib y CONFIG += staticlib y usa el Field biblioteca.

  3. Servidor:una aplicación QML que utiliza las bibliotecas Stadium y Football.


Estoy creando esta aplicación tanto en Windows 8.1 (MSVC2012) como en Linux (gcc 4.8.1). Funciona sin problemas en Windows , pero la compilación de Linux se comporta de forma extraña.


Los errores que obtengo se ven así:


undefined reference to 'vtable for Stadium::Engine'

He reescrito este proyecto en un conjunto de archivos simples que muestra el error. Puedes encontrarlo en Github aquí:Fútbol. Siéntete libre de clonarlo y ver todos los errores por ti mismo. El 661441c commit resuelve el problema, y ​​el 09836f9 commit contiene los errores.


El archivo Stadium Engine.h es una clase abstracta. Se ve así:


#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

Aquí está el archivo Football Engine.h, que hereda del archivo Stadium Engine.h anterior:


#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

Y el archivo 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.";
}

Si muevo la definición del constructor del cpp al archivo de encabezado, se compila sin errores.


A continuación se muestra el archivo Server.pro. Es indicativo de todos mis otros archivos de perfil, en el sentido de que las descripciones de enlaces estáticos (generados automáticamente por Qt Creator) tienen el mismo aspecto.


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

Intenté limpiar, volver a ejecutar qmake, eliminar el directorio de compilación y reconstruir. La única forma de compilar este proyecto en Linux es eliminar el CONFIG += staticlib línea en el archivo .pro de la biblioteca Stadium (y el correspondiente else:unix: PRE_TARGETDEPS += $$OUT_PWD/../stadium/libstadium.a línea en el Game.pro también, por supuesto). Esto compila el proyecto con éxito y se ejecuta sin problemas. Pero simplemente no entiendo por qué. Tampoco entiendo por qué importa dónde se define la definición del constructor.


¿Alguna idea?


Algunas respuestas de código


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() {}