I'm playing around with Qt Creator and QMake project structures and am running into a linker issue (undefined reference) when compiling an app that attempts to make use of items defined in a cpp in a library. I'm using the subdirs project type to house related subprojects with the following structure:
parentProject
|- parentProject.pro
|- coreApp
| |- coreApp.pro
| |- main.cpp
| |- mainwindow.cpp
|- coreLib
|-coreLib.pro
|- corelib.h
|- corelib.cpp
|- coreLib_global.h
|- Temp.h
|- temp2.h
|- temp2.cpp
Parent project being the subdirs project maintains references to the various subprojects
#parentProject.pro
TEMPLATE = subdirs
SUBDIRS += \
coreApp \
coreLib
coreApp.depends+=coreLib
The coreLib was created using the QtCreator New Project -> Library -> C++ Library
wizard and virtually nothing was changed. Only the temp files were added to play around with things (posted below).
#coreLib.pro
QT -= gui
TEMPLATE = lib
DEFINES += CORELIB_LIBRARY
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
corelib.cpp \
temp2.cpp
HEADERS += \
Temp.h \
coreLib_global.h \
corelib.h \
temp2.h
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target
The coreApp was created using the QtCreator New Project -> Application (Qt) -> Qt Widgets Application
and essentially left untouched. The only changes I'd made are as follows:
coreApp project -> Add Library -> Internal Library -> select coreLib
with everything else in that dialog left at the defaultmain.cpp
updated to make call to my test classes in coreLib#coreApp.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
TRANSLATIONS += \
coreApp_en_US.ts
CONFIG += lrelease
CONFIG += embed_translations
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../coreLib/release/ -lcoreLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../coreLib/debug/ -lcoreLib
else:unix: LIBS += -L$$OUT_PWD/../coreLib/ -lcoreLib
INCLUDEPATH += $$PWD/../coreLib
DEPENDPATH += $$PWD/../coreLib
And the updated to main.cpp
can literally be written out as:
//main.cpp
//snip
#include "corelib.h"
#include "temp2.h"
#include <iostream>
int main(int argc, char *argv[])
{
CoreLib();
std::cout << "RESULT: " << Temp2().sub(1, 2) << std::endl;
// snip
}
The files in coreLib are as rudimentary as it gets
//corelib.h - as per what was generated
#ifndef CORELIB_H
#define CORELIB_H
#include "coreLib_global.h"
class CORELIB_EXPORT CoreLib
{
public:
CoreLib();
};
#endif // CORELIB_H
//corelib.cpp - as per generated just with the cout added
#include "corelib.h"
#include <iostream>
CoreLib::CoreLib()
{
std::cout << "NOT HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
}
//Temp.h
#ifndef TEMP_H
#define TEMP_H
inline int add(int x, int y) {
return x + y;
}
#endif // TEMP_H
//temp2.h
#ifndef TEMP2_H
#define TEMP2_H
class Temp2
{
public:
Temp2();
int sub(int x, int y);
};
#endif // TEMP2_H
//temp2.cpp
#include "temp2.h"
Temp2::Temp2()
{
}
int Temp2::sub(int x, int y) {
return x - y;
}
What I'm Experiencing:
corelib.cpp
can be access and changes are reflected (i.e.: if I change the cout in the constructor I can see the change when I launch coreApp)Temp.cpp
I get a linker error relating to unresolved reference to Temp::add()My confusion:
corelib.h
and corelib.cpp
look to be working indicates that the coreLib.dll is created and accessed by coreAppTemp.h
temp2.cpp
is getting compiled (I can see temp2.o
in the build directory with the expected timestamp)It feels like other cpp files while compiled are not included in the generated dll. Why would this be?
Turns out it's the coreLib_global.h
that is the crux of the matter. If the class/header definition makes use of that it will be available for use outside of the library. Meaning temp2.h becomes:
//temp2.h
#ifndef TEMP2_H
#define TEMP2_H
#include "coreLib_global.h"
class CORELIB_EXPORT Temp2
{
public:
Temp2();
int sub(int x, int y);
};
#endif // TEMP2_H
And by marking the class as a CORELIB_EXPORT it becomes accessible to outside of the library. Without it, it can only be used internally (or purely as a header).
More detail can be found in the QT Docs.