PDA

View Full Version : error LNK2001: unresolved external symbol "public: static struct QMetaObject



qlands
11th August 2012, 19:17
Hi,

I am trying to link an application using QGIS API. Everything works on Linux but in Windows (QT 4.8.1 + Visual Studio Express 2010) I get:



1>maptoolselect.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const QgsVectorLayer::staticMetaObject" (?staticMetaObject@QgsVectorLayer@@2UQMetaObject@@ B)
1>mapwidget.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const QgsVectorLayer::staticMetaObject" (?staticMetaObject@QgsVectorLayer@@2UQMetaObject@@ B)
1>mapwidget.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const QgsRasterLayer::staticMetaObject" (?staticMetaObject@QgsRasterLayer@@2UQMetaObject@@ B)
1>debug\\nile.exe : fatal error LNK1120: 2 unresolved externals


my pro file is defined as:



QT += core gui sql xml

TARGET = nile
TEMPLATE = app

unix:INCLUDEPATH += /usr/local/gis/include/qgis /usr/local/gis/include ./mapviewsrc
win32:INCLUDEPATH += C:/QGIS/apps/qgis/include C:/QGIS/include ./mapviewsrc

unix:LIBS += -L/usr/local/gis/lib -lgdal -lgeos -lqgis_core -lqgis_gui
win32:LIBS += C:/QGIS/apps/qgis/lib/qgis_core.lib C:/QGIS/apps/qgis/lib/qgis_gui.lib C:/QGIS/lib/geos_c_i.lib C:/QGIS/lib/gdal_i.lib

CONFIG += release

DEFINES += QGISPLUGINDIR=$${QGISPLUGINDIR} CORE_EXPORT= GUI_EXPORT=



I tried to generate a Visual Studio project with


qmake -tp vc


but I get the same error.

Any help is much appreciated!.

Carlos

d_stranz
11th August 2012, 20:22
I think this error typically occurs because MOC hasn't run to generate its moc_*.cpp files, or if it has, the .cpp files have not been compiled or the resulting .obj files have not been included in the link. Try doing a clean rebuild. Also make sure that you have declared Q_OBJECT in and classes that inherit from QObject.

You could also look at your .vcproj file. You should see entries such as this:



<FileConfiguration Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
Description="Moc&apos;ing $(InputFileName)..."
CommandLine="&quot;$(QTDIR)\bin\moc.exe&quot; &quot;$(InputPath)&quot; -o &quot;.\GeneratedFiles\$(ConfigurationName)\moc_$(Input Name).cpp&quot; -D_UNICODE -DQT_CORE_LIB -DQT_GUI_LIB -DQT_LARGEFILE_SUPPORT -DQT_THREAD_SUPPORT -DSACOREQT_LIB -DUNICODE -DWIN32 -DXERCES_STATIC_LIBRARY -I&quot;$(QTDIR)\include&quot; -I&quot;$(QTDIR)\include\ActiveQt&quot; -I&quot;$(QTDIR)\include\QtCore&quot; -I&quot;$(QTDIR)\include\QtGui&quot; -I&quot;.&quot; -I&quot;.\..\Include&quot; -I&quot;.\GeneratedFiles&quot; -I&quot;.\GeneratedFiles\$(ConfigurationName)&quot;&#x0D;&#x0A;"
AdditionalDependencies="&quot;$(QTDIR)\bin\moc.exe&quot;;$(InputPath)"
Outputs="&quot;.\GeneratedFiles\$(ConfigurationName)\moc_$(Input Name).cpp&quot;"
/>
</FileConfiguration>

qlands
12th August 2012, 17:27
Hi,

I added those lines to the proj file but I get the same. Here it the output:



1>------ Build started: Project: nile, Configuration: Debug Win32 ------
1> MOC mapviewsrc\gendockwidget.h
1> MOC genmodels.h
1> MOC gobletrunner.h
1> MOC importraster.h
1> MOC mapviewsrc\keywidget.h
1> MOC mapviewsrc\lyrwidget.h
1> MOC mainwidget.h
1> MOC mapviewsrc\mapdialog.h
1> MOC mapviewsrc\maptoolselect.h
1> MOC mapviewsrc\mapwidget.h
1> MOC mapviewsrc\mapwindow.h
1> MOC practice.h
1> MOC practype.h
1> MOC mapviewsrc\statswidget.h
1> MOC strategy.h
1> UIC gobletrunner.ui
1> UIC importraster.ui
1> UIC mapviewsrc\keywidget.ui
1> UIC mapviewsrc\lyrwidget.ui
1> UIC mainwidget.ui
1> UIC mapviewsrc\mapdialog.ui
1> UIC mapviewsrc\mapwidget.ui
1>mapviewsrc\mapwidget.ui : warning : Z-order assignment: '' is not a valid widget.
1> UIC mapviewsrc\mapwindow.ui
1> UIC practice.ui
1> UIC practype.ui
1> UIC mapviewsrc\statswidget.ui
1>mapviewsrc\statswidget.ui : warning : Z-order assignment: '' is not a valid widget.
1> UIC strategy.ui
1> RCC files.qrc
1> RCC mapviewsrc\mapimages.qrc
1> genFunctions.cpp
1> gendockwidget.cpp
1> genmodels.cpp
1> gobletrunner.cpp
1> importraster.cpp
1> keywidget.cpp
1> lyrwidget.cpp
1> main.cpp
1> mainwidget.cpp
1> mapdialog.cpp
1> maptoolselect.cpp
1> mapwidget.cpp
1> mapwindow.cpp
1> practice.cpp
1> practype.cpp
1> statswidget.cpp
1> strategy.cpp
1> treeitem.cpp
1> moc_gendockwidget.cpp
1> moc_genmodels.cpp
1> Generating Code...
1> Compiling...
1> moc_gobletrunner.cpp
1> moc_importraster.cpp
1> moc_keywidget.cpp
1> moc_lyrwidget.cpp
1> moc_mainwidget.cpp
1> moc_mapdialog.cpp
1> moc_maptoolselect.cpp
1> moc_mapwidget.cpp
1> moc_mapwindow.cpp
1> moc_practice.cpp
1> moc_practype.cpp
1> moc_statswidget.cpp
1> moc_strategy.cpp
1> qrc_files.cpp
1> qrc_mapimages.cpp
1> Generating Code...
1>maptoolselect.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const QgsVectorLayer::staticMetaObject" (?staticMetaObject@QgsVectorLayer@@2UQMetaObject@@ B)
1>mapwidget.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const QgsVectorLayer::staticMetaObject" (?staticMetaObject@QgsVectorLayer@@2UQMetaObject@@ B)
1>mapwidget.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const QgsRasterLayer::staticMetaObject" (?staticMetaObject@QgsRasterLayer@@2UQMetaObject@@ B)
1>debug\\nile.exe : fatal error LNK1120: 2 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


I can see that moc is generating the moc_ and the files are compiled but still the linking fails.

This is the first time I use a .proj files. I usually use qmake and then nmake but I get the same error in the linking

Thanks.

d_stranz
12th August 2012, 18:20
Well, the linker is complaining about two files in particular, the ones that contain QgsVectorLayer and QgsRasterLayer. I don't see that listed in your build output, so you either forgot to include them in the project or you are not linking to the object files or library that contains them.

qlands
12th August 2012, 19:16
Hi,

Yes, both classes QgsVectorLayer and QgsRasterLayer are defined in external libraries

How can I see in the project if my application is linking using:

C:/QGIS/apps/qgis/lib/qgis_core.lib
C:/QGIS/apps/qgis/lib/qgis_gui.lib
C:/QGIS/lib/geos_c_i.lib
C:/QGIS/lib/gdal_i.lib

Many thanks,
Carlos.

d_stranz
13th August 2012, 02:06
If you are using Visual Studio, go to the Solution Explorer window (on the menu: View->Solution Explorer), right click on the name of your project, then select the Properties item at the bottom of the popup menu. When the Property Pages dialog appears, expand the "Linker" entry, then click the "Input" item. At the top of the properties table, you should see "Additional Dependencies". Click that, then click the "..." button that appears to the right of the second column. You will see a dialog with all of the libraries that are being linked in to your project. If the libraries you need aren't in the list, then at the bottom of the list you can type the names of the libraries, one per line. You can type either the full name including the path (C:\QGIS\lib\gdal_i.lib) or just the name of the library file (gdal_i.lib). Click OK when you have added them all.

If you type only the name, then you need to tell the linker where to find the library files. Go to the "General" item under "Linker". Click "Additional Library Directories" and the "..." button to the right. At the bottom of the list of directories (might be empty in your case), double-click, click the "..." button and browse to select the directory that contains the library files (C:\QGIS\lib). Repeat for each directory. Click OK to close this dialog, click OK to close the properties dialog, and then rebuild.

By the way, I'm using the full version of Visual Studio. I do not know if what I described in in the Express version, but I would be very surprised if it isn't. Being able to add files and libraries to the project configuration is a pretty basic requirement.

qlands
13th August 2012, 17:16
Hi,

I realized that the problem arises from the use of qobject_cast in lines like:


QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );


If I change those lines to use dynamic_cast the error disappears and the application runs properly.

Any idea why I cannot use qobject_cast in Windows?

Many thanks.

tescrin
13th August 2012, 17:28
D_stranz answer above should cover this. These linker errors occur because something is not defined:
-meaning that a library or dll isn't in the right spot
-a library or dll fails to contain the same symbol (i.e. function name)
-a .cpp file fails to contain the same symbol

and I may be missing an instance. To fix this; you'll need to follow his answer above and:
-Add the correct lib file (if it exists) to the required libraries and add it's path to the additional directories
-Add to your PATH variable (under c/c++->debugging) the path of any .dll files you may need
-Add the .h file to your include directory or add a path in the include directory to the .h file

The error is not the cast itself, it's *in* the cast. The cast is asking (implicitly) for a constructor which you seem to not have defined. It may be a standard constructor but your library isn't linked or something. I guarantee linking the correct files into your project will fix *these* errors.

qlands
13th August 2012, 17:52
Hi,

Yes I did all that and I just did your bits.. However I get the same result with qobject_cast. Before I changed those lines to dynamic_cast I changed the .pro to release and generated the Makefile with qmake but without creating a .proj file. nmake in that instance pointed me to the lines containing qobject_cast. As I am using QGIS i don't know if there is an issue with the QGIS API. From a set of examples in QGIS I can see that dynamic_cast is used.

What I don't understand is why the linker errors disappear using dynamic_cast. It might be as you said because a constructor has not been defined.

Thanks.

d_stranz
13th August 2012, 17:57
If I change those lines to use dynamic_cast the error disappears and the application runs properly.


I'm betting that you aren't getting a valid pointer to a QgsVectorLayer instance when you do this, but you're lucky because whatever is using this pointer is probably checking for a NULL pointer before trying to dereference it.

The reason why qobject_cast causes link errors is that, unlike dynamic_cast, it is actually checking to see that the pointer *really does* point to a QgsVectorLayer instance, and to do that it needs the Qt meta-object system to be in place and working for it.

So, do like tescrin and I have suggested: Check the Visual Studio properties for the project and make sure your libraries *are* being linked in. Change the cast back to qobject_cast.

qlands
13th August 2012, 18:06
Check the Visual Studio properties for the project and make sure your libraries *are* being linked in. Change the cast back to qobject_cast.

I decided to not use a Visual Studio project file but I will check the code to see if I'm not getting a valid pointer.

d_stranz
13th August 2012, 18:15
Well, then, good luck. I don't use .pro files; I create my projects directly in Visual Studio and use only the VS project files, so I can't help you get it configured. If qmake is generating a makefile for you, then you should see some kind of link line in there that should include all of the .lib files you listed. If they aren't on the link line, they aren't being linked in.

mobrien
6th May 2019, 00:54
This is sometimes due to the fact your class (the one with the unresolved symbols) is a QObject (using macro in header and deriving from qobject), but the linker cant find the constructor.
This happens for example if the class is a singleton (constructor is private etc). So you must either explicity have a constructor that is visible (protected or public), or make the class a non QT object (dont derive from qobject).

d_stranz
7th May 2019, 00:02
The error reported in the original post had nothing to do with the linker not being able to find a constructor. The error is due to the linker being unable to find the symbols generated by the MOC compiler when it processes the class header file. This can occur for four reasons: 1) the MOC compiler didn't run to create the *_moc.cpp file from the class header file, 2) MOC did run, but the generated cpp file wasn't compiled, 3) MOC did run, but the class definition was missing the Q_OBJECT macro (which defines the staticMetaObject embedded class) so the code inserted by the macro wasn't there, or 4) the object code compiled from the cpp file wasn't linked into the executable.

In the linux world, there is another possibility: the object files / libraries were not linked in the correct order. Object files must be presented to the gcc / g++ linker so any object file that is dependent on another object file (.o or .lib) must appear -before- that .o or .lib in the link command. Otherwise, dependencies discovered by the linker -after- the file that defines them has been processed will remain unresolved.

The MSVC linker is smarter; it apparently builds a table of all references contained in the object files and can resolve references anywhere they occur when processing the link command.


This happens for example if the class is a singleton

It does not matter if an instance of a class is declared as a singleton, as a static instance at global or file scope, on the heap, or on the stack; the compiler will generate a reference to it which the linker must resolve. If your code tries to instantiate a class with a private or protected constructor under circumstances where that constructor is inaccessible, that will generate a compile-time error, not a link error.