Qt creator: c++: undefined reference to Class::Function
Solution 1
Your unit tests will need to compile the classes in your project that you want to unit-test. So you need to add the include in both project (otherwise the test project will not know the classes you are trying to test). And the linker needs to link to the project's code as well, as your tests will use the classes.
One way is to add the classes you want to test in your test project as well and compile them again when you compile your unit test project but this is tedious and not really handy as every time you want to add a class, you need to add it to both .pro files (hint, you can use wildcards in the .pro files, like *.cpp to add all source files in a folder to a project).
A better approach in my opinion is to setup the project you want to test as a static library, separating it from the application: you have another project which is an application, containing only the main.cpp
linking to that static library.
Here is a representation of the folder containing the project:
Project.pro #subdir project
UIProject/ #static lib
UIProject.pro
#all your classes here
MainProject/ #application
MainProject.pro
main.cpp
UITestProject/ #unit tests of UIProject (linking to it)
UITestProject.pro
#all your UI test classes here
Project.pro:
TEMPLATE = subdirs
SUBDIRS += UIProject
SUBDIRS += MainProject
SUBDIRS += UITestProject
UIProject.pro:
# project type
TEMPLATE = lib
# library type
CONFIG += staticlib
HEADERS += *.h
SOURCES += *.cpp
MainProject.pro:
#[...]
TEMPLATE = app
SOURCES += main.cpp
INCLUDEPATH += ../UIProject/
DEPENDPATH += $${INCLUDEPATH} # force rebuild if the headers change
# link against UILib
_UI_LIB = ../UIProject/
CONFIG(debug, debug|release) {
win32: _UI_LIB = $$join(_UI_LIB,,,debug/UIProject.lib)
} else {
win32: _UI_LIB = $$join(_UI_LIB,,,release/UIProject.lib)
}
LIBS += $${_UI_LIB}
PRE_TARGETDEPS += $${_UI_LIB}
UITestProject.pro:
#[...]
TEMPLATE = app
HEADERS += *.h
SOURCES += *.cpp
INCLUDEPATH += ../UIProject/
DEPENDPATH += $${INCLUDEPATH} # force rebuild if the headers change
# link against UILib
_UI_LIB = ../UIProject/
CONFIG(debug, debug|release) {
win32: _UI_LIB = $$join(_UI_LIB,,,debug/UIProject.lib)
} else {
win32: _UI_LIB = $$join(_UI_LIB,,,release/UIProject.lib)
}
LIBS += $${_UI_LIB}
PRE_TARGETDEPS += $${_UI_LIB}
You would have to edit that to match your project but the main things are here. It should work as I copied it from one of my project, providing I didn't add any errors.
Solution 2
you should include your cpp file to the project to tell build system (qmake) to compile the given file.
When you add
myClass.cpp
to test project, it gets compiled, otherwise does not.
So, when you will not add cpp file to the project, you'll get linker error.
Includes are just handled separately
When you add new path to INCLUDEPATH
, compiler will add that pass to headers search list
When you add
applicationProjectPath
to the include path, compiler will search headers there. It is important, as allows compiler to findmyClass.h
If you will not add path to headers search list, compiler will not be able to compile your main.cpp
and you'll get compilation error.
You, however, can just specify (relative) path to your myClass.h
in your test-project's main:
#include "../applicationProjectPath/myClass.h"
Summing up
You need add your source files to test project and add your headers path to test project's include search list.
Further reading
What is an undefined reference/unresolved external symbol error and how do I fix it?
hashDefine
Updated on July 09, 2022Comments
-
hashDefine over 1 year
I am creating two c++ projects in my Qt creator. The first is an
Application project
and the other isunit-test project
. the two projects, separately, work fine. However, when linking the two together I face a little problem.I am including
#INCLUDEPATH applicationProjectPath
in.pro file
in theunit-test project
. then#include myClass
from the application project in themain.cpp
of theunit-test project
. then, creating amyObject
frommyClass
and calling a function within that object.when compiling, this error appears:
undefined reference to `myObject::function'
however, when adding
#SOURCES applicationProjectPath/myClass.cpp
to the .pro file of the unit-test project (while keeping the#INCLUDEPATH applicationProjectPath
), everything is working (i.e.: the test units are executed)again when removing the
#INCLUDEPATH
from the .pro, it again crashes .I thought if I included
#SOURCES
, then I don't need to include the#INCLUDEPATH
. and if I included the#INCLUDEPATH
, I should not include#SOURCES
(at least not with the full path, just the .cpp file and then the compiler should look for both directories, the default one and the added one).so, my question is: why is this happening
-
hashDefine over 10 years>A better approach in my opinion is to setup the project you want to test as a static library. this exactly what I am looking for as an answer. so what you mean is: add my Application-project to the unit-test-project as a library instead of adding its path and source/header files. but my problem now is how to add my Application-project as a library (sorry, could not understand your code) .. but thank you very much for your explanation.
-
hashDefine over 10 yearsthanks for your answer .. and thank you for the link as it gives me what I want to understand the compiling process in more details ..
-
Uflex over 10 yearsIt wasn't code but the representation of the folders on disk, with some comments starting with
#
. I'll try editing my post to be more understandable -
Uflex over 10 yearsIf you need more explanations just tell me, I'll add some more stuff
-
hashDefine over 10 yearsThanks .. you mentioned that: (And the linker needs to link to the project's code as well, as your tests will use the classes.) by this you mean include both (path) and (classes) of the (unit-test project) in the (.pro file) of the (Application-project). But since I am already specifying the (Application project classes) I need to test in my (uni-test project) in its (.pro file) and the unit-test is working, do you really think adding the (unit-test project) to the (.pro file) of the (Application project) is necessary? (having asked that, I am still going to add the library)
-
Uflex over 10 yearsI'm not sure to understand what you mean but linking to the library will resolve that, without having to add anything else. All the objects needed will be contained in the library. If you use the code I wrote in my answer above (starting with "A better approach"), you will have a global project file, "Project.pro", containing no source code, only telling qmake to compile the subdirectories. UIProject will be a static library, used by both your MainProject AND UITestProject. Those last two projects are completely separated, the only thing in common in that they both use UIProject.
-
Uflex over 10 yearsI think I'll write a blog post this week end and explain all this a bit better. All that is not really well documented anywhere and can be a bit hard to understand at first.
-
DBedrenko over 7 years@Uflex Thanks for this answer, it helped me finally get tests set up correctly after trying for literally 7 hours. Did you end up writing the blog post? Could you link your blog please? I can't see it in your profile.
-
A. Vieira over 5 yearsI see. So, adding
applicationProjectPath
toINCLUDEPATH
makes the compiler aware of headers. Then you also need to add all .cpp's relevant to the project to theSOURCES
variable. I.e. you don't need to add the .h's toHEADERS
.