I'm having massive problems simply trying to add a new class into the scene manager.
I have literally tried dozens of different ways of doing it and still nothing works.
All I get is some stupid error message that makes no sense at all from VS.
Hopefully someone on this forum can help me out and show me how I went wrong.....
I have a working (from older irrlicht) code with the header and cpp file with new class I want to add into the scene manager.
I want it to compile first (which refuses to do so for unknown reasons).
For SceneManager.h - I added into line 35 a new class - "class CCloudSceneNode;" and included "# include CCloudSceneNode.h"
For SceneManager.cpp - I added into line 222 this:
CCloudSceneNode* cloudLayer1 = new CCloudSceneNode(this->getRootSceneNode(), this);
cloudLayer1->setTranslation(core::vector2d<f32>(0.008f, 0.0f));
cloudLayer1->getMaterial(0).setTexture(0, Driver->getTexture("../../../media/clouds/cloud01.png"));
cloudLayer1->setCloudHeight(0.5f, 0.1f, -0.05f);
No matter what, it refuses to compile and currently getting this error:
flaceLib.lib(CSceneManager.obj) : error LNK2019: unresolved external symbol "public: __cdecl irr::scene::CCloudSceneNode::CCloudSceneNode(class irr::scene::ISceneNode *,class irr::scene::ISceneManager *,int)" (??0CCloudSceneNode@scene@irr@@QEAA@PEAVISceneNode@12@PEAVISceneManager@12@H@Z) referenced in function "public: __cdecl irr::scene::CSceneManager::CSceneManager(class irr::video::IVideoDriver *,class irr::io::IFileSystem *,class irr::gui::ICursorControl *,class irr::scene::IMeshCache *,class irr::gui::IGUIEnvironment *)" (??0CSceneManager@scene@irr@@QEAA@PEAVIVideoDriver@video@2@PEAVIFileSystem@io@2@PEAVICursorControl@gui@2@PEAVIMeshCache@12@PEAVIGUIEnvironment@82@@Z)
C:\src_2023\OCC_tryClouds\win32player\x64\Release\win32player.exe : fatal error LNK1120: 1 unresolved externals
Can someone please suggest fixes for this ? - its driving me nuts.....
Files attached.
https://easyupload.io/ahogx9
Add class to scene manager
Re: Add class to scene manager
There are a few things to mention here.
First is that you don't have to modify the engine itself to add a new node. And generally you shouldn't do that unless there is no other option as it will make it harder for you to update the engine in the future. Example 03 CustomSceneNode shows how to add a new node in your project without modifying the engine.
Thought you will probably run into the exact same error at first. If you look at your error closely it says LNK - which stands for linker error. So your compiler is already done and was successful.
In short in means you haven't added CCloudSceneNode.cpp to your project. Or to Irrlicht in this case. You do that the error goes away.
The long explanation:
C/C++ compilers always compile each .c/.cpp file on their own and create an object file for that (.o with Visual Studio).
#include commands copy-paste whatever code is in the include (usually a header file) into the .c/.cpp file. Meaning every time you include a header it just puts all the code into a cpp file replacing the #include line itself. The pre-processor does that before the compiler runs. It also does some other stuff like replacing #defines, so that all happens before the compiler even starts.
But it still does _not_ copy the other cpp file which has the code! So when the compiler compiles your .cpp files it doesn't know anything about the other .cpp file (which is why compilers can compile all files in parallel). What header files contain is (usually) information for the compiler about function names, class names and their parameters. Especially important the size of each parameter. Which matters a lot as a compiler always reads a file from top to bottom and it can never use any type unless it knows already it's name and size (slight exception are pointers which all have the same size, so the compiler only needs the name there). So basically header says - this class has that and that name and needs X bytes size in memory. And as soon as the compiler has that much information it will allow you to work with such classes/functions in your .c/.cpp even if it doesn't have the code itself. It just adds placeholders (more or less).
But there is a problem - each .c/.cpp file is compiled on it's own. So the actual code of those functions might not be in the same .cpp file you used to create an object file (it only has names and parameters with their sizes). So when the compiler creates your object file it kinda say - those functions are somewhere external. And then the compilers job is done!
After all your .c./cpp files are compiled into object files comes the next step - the linker will now (usually) run.
It generally has 3 main options: Create a static library (.lib in Visual Studio) , Create a dynamic library (.dll + .lib in Visual Studio) or create an executable (.exe on Windows). Linux is similar except different names and dynamic libraries on Linux have only one file. What it does when creating a library is more or less copy all .o files into a single archive file (the .lib - kinda similar as when you create a zip file, so mostly contains stuff from all the .o files). Similar for dynamic library - except this time it creates (on Windows) one tiny lib file which just contains info about more or less the same information headers have (names and type sizes) and the real code is put into the dll.
The last option is creating something which actually runs - an executable. And to run it needs now all the real compiled code - not just the information about function names and sizes. So at this step it has to resolve all those placeholders (function name + parameters) with pointers to the actual code. The stuff which is distributed over all the object files of your project and the library files added to your project. And if it is missing an object file now - it has the information from the header how a function looks like, but doesn't know about the code, so it complains that it can't resolve that function, like: unresolved external symbol "bla bla bla". Always means the same - it doesn't find the object file or library which contains that function. Which in 90% of the cases means you forgot to add the .cpp file to your project or to the library (the other 10% are mostly about implementation and header not looking exactly the same, like accidentally misspelling something or forgetting you added a parameter in one, but not the other).
Last a quick note about dll's... functions/classes in those are not resolved by the linker. Instead when the linker sees there is a dynamic library involved it again only adds placeholders in your executable. And says: Look for those when starting the application - they should be in some dll called <whatever>. And then the exe starts it searches for that dll and if it's not there it complains then that whatever.dll is missing or that function xzy wasn't found in whatever.dll.
And you can even delay function resolving further and only work with function pointers in your code from the start - then the linker will do nothing at all. But it's your tasks then to load a dll and fill the pointers with addresses to the real code. That's the way plugin systems in applications usually work. Then you manually load dll's and search for function names in those and pass the addresses of the code to your pointers which are then called. But just mentioning this here so you do get the full overview, you'll likely won't need that last one for a long time ;-)
First is that you don't have to modify the engine itself to add a new node. And generally you shouldn't do that unless there is no other option as it will make it harder for you to update the engine in the future. Example 03 CustomSceneNode shows how to add a new node in your project without modifying the engine.
Thought you will probably run into the exact same error at first. If you look at your error closely it says LNK - which stands for linker error. So your compiler is already done and was successful.
In short in means you haven't added CCloudSceneNode.cpp to your project. Or to Irrlicht in this case. You do that the error goes away.
The long explanation:
C/C++ compilers always compile each .c/.cpp file on their own and create an object file for that (.o with Visual Studio).
#include commands copy-paste whatever code is in the include (usually a header file) into the .c/.cpp file. Meaning every time you include a header it just puts all the code into a cpp file replacing the #include line itself. The pre-processor does that before the compiler runs. It also does some other stuff like replacing #defines, so that all happens before the compiler even starts.
But it still does _not_ copy the other cpp file which has the code! So when the compiler compiles your .cpp files it doesn't know anything about the other .cpp file (which is why compilers can compile all files in parallel). What header files contain is (usually) information for the compiler about function names, class names and their parameters. Especially important the size of each parameter. Which matters a lot as a compiler always reads a file from top to bottom and it can never use any type unless it knows already it's name and size (slight exception are pointers which all have the same size, so the compiler only needs the name there). So basically header says - this class has that and that name and needs X bytes size in memory. And as soon as the compiler has that much information it will allow you to work with such classes/functions in your .c/.cpp even if it doesn't have the code itself. It just adds placeholders (more or less).
But there is a problem - each .c/.cpp file is compiled on it's own. So the actual code of those functions might not be in the same .cpp file you used to create an object file (it only has names and parameters with their sizes). So when the compiler creates your object file it kinda say - those functions are somewhere external. And then the compilers job is done!
After all your .c./cpp files are compiled into object files comes the next step - the linker will now (usually) run.
It generally has 3 main options: Create a static library (.lib in Visual Studio) , Create a dynamic library (.dll + .lib in Visual Studio) or create an executable (.exe on Windows). Linux is similar except different names and dynamic libraries on Linux have only one file. What it does when creating a library is more or less copy all .o files into a single archive file (the .lib - kinda similar as when you create a zip file, so mostly contains stuff from all the .o files). Similar for dynamic library - except this time it creates (on Windows) one tiny lib file which just contains info about more or less the same information headers have (names and type sizes) and the real code is put into the dll.
The last option is creating something which actually runs - an executable. And to run it needs now all the real compiled code - not just the information about function names and sizes. So at this step it has to resolve all those placeholders (function name + parameters) with pointers to the actual code. The stuff which is distributed over all the object files of your project and the library files added to your project. And if it is missing an object file now - it has the information from the header how a function looks like, but doesn't know about the code, so it complains that it can't resolve that function, like: unresolved external symbol "bla bla bla". Always means the same - it doesn't find the object file or library which contains that function. Which in 90% of the cases means you forgot to add the .cpp file to your project or to the library (the other 10% are mostly about implementation and header not looking exactly the same, like accidentally misspelling something or forgetting you added a parameter in one, but not the other).
Last a quick note about dll's... functions/classes in those are not resolved by the linker. Instead when the linker sees there is a dynamic library involved it again only adds placeholders in your executable. And says: Look for those when starting the application - they should be in some dll called <whatever>. And then the exe starts it searches for that dll and if it's not there it complains then that whatever.dll is missing or that function xzy wasn't found in whatever.dll.
And you can even delay function resolving further and only work with function pointers in your code from the start - then the linker will do nothing at all. But it's your tasks then to load a dll and fill the pointers with addresses to the real code. That's the way plugin systems in applications usually work. Then you manually load dll's and search for function names in those and pass the addresses of the code to your pointers which are then called. But just mentioning this here so you do get the full overview, you'll likely won't need that last one for a long time ;-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Posts: 6
- Joined: Sun Sep 24, 2023 5:48 am
Re: Add class to scene manager
Much appreciated the detailed response to that problem of linking.
Yes, over the last year I became aware that the Linking issues was the final step and what you said above is totally right.
I still have issues finding where these mismatched method calls/formats etc in the new class.cpp file are so I found a dodgy solution:
I past all the new class .cpp code into SceneManager manually into some temp function already setup for this and then run VS - it will then show me the wrong names/format or function names as its part of the core engine now and not a separate class.
I then go back and update the linked class .h and .cpp file but until now still am getting an error every time I use the "new" keyword to actually initialise the new class object or node.. even after fixing up and replacing redundant bits of code to some thing that does the same thing...
Any suggestions ?
Yes, over the last year I became aware that the Linking issues was the final step and what you said above is totally right.
I still have issues finding where these mismatched method calls/formats etc in the new class.cpp file are so I found a dodgy solution:
I past all the new class .cpp code into SceneManager manually into some temp function already setup for this and then run VS - it will then show me the wrong names/format or function names as its part of the core engine now and not a separate class.
I then go back and update the linked class .h and .cpp file but until now still am getting an error every time I use the "new" keyword to actually initialise the new class object or node.. even after fixing up and replacing redundant bits of code to some thing that does the same thing...
Any suggestions ?
Re: Add class to scene manager
When you get an error please always copy-paste the exact error.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm