undefined reference to ...

edited November 13 in General Discussions
Hello Guys,

i'm new to C/C++ (since today) but not new to programming in general (C#, lua, basic..).
I'm mostly into game programming and wanted to teach myself a bit of C/C++ as i
taught myself all the other languages.

For that i wanted to try out raylib as i learned all the other languages by making games as well.

So i wanted to create some basic libs like for scene management etc.

But when i want to compile the code, i get the " undefined reference to `Composer::Composer()'" error.

I think the problem is, that the linker can't find the object file i guess, but how do i link stuff?

I'm using the preconfigured Notpad++ from raylib.

Below, the code i have so far: (probably full of mistakes, but i can't go to debugging because i don't get any further because of this error)


composer.h

#ifndef __COMPOSER_H__
#define __COMPOSER_H__

#include "string.h"
#include list
#include "stdio.h"

#include "Scene.h"

class Composer{
public:
Composer();
~Composer();
static void addToScenes(Scene scene);
void goToScene(std::string sceneName);
void updateCurrentScene();
void drawCurrentScene();
std::string getCurrentSceneName();
void deleteScene();
void deleteLastScene();

private:
// a list of all scenes
static std::list scenes;
// handle to the current shown scene
Scene *currentScene;
// handle to the last shown scene
Scene *lastScene;
};

#endif // __COMPOSER_H__

composer.cpp

#include "Composer.h"

void Composer::Composer(){
this->currentScene = nullptr
this->lastScene = nullptr
}

void Composer::~Composer(){
delete currentScene;
delete lastScene;

for(auto itr = scenes.begin(); itr != scenes.end(); ++itr) {
Scene* scn = *itr;
delete scn;
}
}

static void Composer::addToScenes(Scene scene){
itr = scenes.begin();
bool sceneUnique = true;
while(itr != scenes.end()){
if (*itr->name == scene.name){
std::cout << "Scene name already exist!"
sceneUnique = false;
break;
}
}
if (sceneUnique == true){
scenes.push_back(scene);
}
}

void Composer::goToScene(string sceneName){
// get the beginning address of the scene list
itr = scenes.begin();
while(itr != scenes.end()){
if (*itr->name == sceneName){
this->lastScene = this->currentScene;
this->currentScene = itr;
break;
}
}
}

void Composer::updateCurrentScene(){
if (this->currentScene != nullptr){
if (this->lastScene != nullptr){
*this->lastScene.hide();
}
*this->currentScene.update();
}
}

void Composer::drawCurrentScene(){
if (this->currentScene != nullptr){
if (this->lastScene != nullptr){
*this->lastScene.hide();
}
*this->currentScene.draw();
}
}

string Composer::getCurrentSceneName(){
if (this->currentScene != nullptr){
return *this->currentScene.name;
}
}

void Composer::deleteScene(string sceneName){
itr = scenes.begin();
while(itr != scenes.end()){
if (*itr->name == sceneName){
if (itr != this->currentScene){
if (itr == this->lastScene){
scenes.erase(itr);
delete this->lastScene;
break;
}
else {
scenes.erase(itr);
break;
}
}
else {
std::cout << "Scene can't be deleted as it is the current shown Scene!"
}
}
}
}

void Composer::deleteLastScene(){
itr = scenes.begin();
while(itr != scenes.end()){
if (itr == this->lastScene){
if (itr != this->currentScene){
scenes.erase(itr);
delete this->lastScene;
break;
}
else {

}
}
}
}


test.c (main)

#include "raylib.h"

#include "redlib/Composer.h"
#include "redlib/Scene.h"

#include "Scene1.h"


int main(int argc, char* argv[]) {
// Initialization
//--------------------------------------------------------------------------------------
int screenWidth = 800;
int screenHeight = 450;

InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");

Composer* composer = new Composer();

new Scene1("Scene1");

composer->goToScene("Scene1");


SetTargetFPS(60);
//--------------------------------------------------------------------------------------

// Main game loop
while (!WindowShouldClose()) { // Detect window close button or ESC key
// Update
//----------------------------------------------------------------------------------
// TODO: Update variables here
//----------------------------------------------------------------------------------

// Draw
//----------------------------------------------------------------------------------
BeginDrawing();

ClearBackground(RAYWHITE);

composer->drawCurrentScene();

EndDrawing();
//----------------------------------------------------------------------------------
}

// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------

return 0;
}
I get the same errors for the base class Scene and the derived class Scene1, but as i think it is the same problem, i don't need to post the code here and bloat the post :)

And here is the output

g++ -o test.exe test.c -s C:\raylib\raylib\raylib_icon -Iexternal -lraylib -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm -std=c99 -Wl,-allow-multiple-definition -Wl,--subsystem,windows
Process started >>>
cc1plus.exe: warning: command line option '-std=c99' is valid for C/ObjC but not for C++
C:\Users\Micha\AppData\Local\Temp\ccYNvs8W.o:test.c:(.text+0x38): undefined reference to `Composer::Composer()'
C:\Users\Micha\AppData\Local\Temp\ccYNvs8W.o:test.c:(.text+0x7b): undefined reference to `Scene1::Scene1(std::__cxx11::basic_string, std::allocator >)'
C:\Users\Micha\AppData\Local\Temp\ccYNvs8W.o:test.c:(.text+0xc7): undefined reference to `Composer::goToScene(std::__cxx11::basic_string, std::allocator >)'
C:\Users\Micha\AppData\Local\Temp\ccYNvs8W.o:test.c:(.text+0x147): undefined reference to `Composer::drawCurrentScene()'
collect2.exe: error: ld returned 1 exit status
As i said, i'm new to C/C++ so please don't be too harsh if that might be a really stupid mistake.

Thanks!


Btw. how do i post code segments properly? The tags pre and /pre with enclosing <> seem to mess things up as you can see obove, had to change the code a bit that it is displayed correctly...

Comments

  • Hi Rednib,

    first you need to tell the compiler all source files. Try:

    g++ -o test.exe test.c composer.cpp ...etc...

    now the compiler knows of your other source file 'composer.cpp'

    You can also remove the -std=c99 from your command because you are compiling c++ code and that flag is only for c compilers/code.

    Let's start with those two little things and see if it helps :)

    Cheers
  • Hi Rednib, welcome to the forum!

    First thing, if you're using C++, I'll recommend you use .cpp naming for code files. In that case -std=c99 is not valid, it's only for C language.

    Second, you need to compile every .cpp file independently to generate .o files and then link all together into the .exe. You can do:

    g++ -c composer.cpp -Wall
    g++ -o test.exe test.cpp composer.o -s C:\raylib\raylib\raylib_icon -Iexternal -lraylib -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm -std=c99 -Wl,-allow-multiple-definition -Wl,--subsystem,windows
    Haven't test it but you get the idea, every .cpp file should be compiled independently and finally linked all together...

    I think you probably also do:

    g++ -o test.exe test.cpp composer.cpp scene1.cpp -s C:\raylib\raylib\raylib_icon -Iexternal -lraylib -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm -std=c99 -Wl,-allow-multiple-definition -Wl,--subsystem,windows
  • Hi,

    thanks for the help, compiling works now.
    But i get flooded with errors, some i could fix but the other i don't know how.

    These are the new files:

    Composer.h

    #ifndef __COMPOSER_H__
    #define __COMPOSER_H__

    #include "string.h"
    #include list // list is in enclosing <> but can't post it here
    #include "stdio.h"

    #include "Scene.h"

    class Composer{
    public:
    Composer();
    ~Composer();
    static void addToScenes(Scene scene);
    void goToScene(std::string sceneName);
    void updateCurrentScene();
    void drawCurrentScene();
    std::string getCurrentSceneName();
    void deleteScene(std::string sceneName);
    void deleteLastScene();

    private:
    // a list of all scenes
    static std::list Scene scenes; // Scene is in enclosing <> but can't post it here
    // handle to the current shown scene
    Scene *currentScene;
    // handle to the last shown scene
    Scene *lastScene;
    };

    #endif // __COMPOSER_H__
    Composer.cpp

    #include "Composer.h"


    Composer::Composer(){
    this->currentScene = NULL;
    this->lastScene = NULL;
    std::list scenes;

    }

    Composer::~Composer(){
    delete currentScene;
    delete lastScene;
    // Scene is in enclosing <> but can't post it here
    for(std::list Scene ::iterator itr = scenes.begin(); itr != scenes.end(); ++itr) {
    Scene* scn = *itr;
    delete scn;
    }

    //while(!scenes.empty()) {
    // delete scenes.front(), scenes.pop_front();
    //}
    }

    void Composer::addToScenes(Scene scene){
    // Scene is in enclosing <> but can't post it here
    std::list Scene ::iterator itr = scenes.begin();
    bool sceneUnique = true;
    while(itr != scenes.end()){
    if (*itr->getName() == scene.getName()){
    std::cout << "Scene name already exist!"
    sceneUnique = false;
    break;
    }
    }
    if (sceneUnique == true){
    scenes.push_back(scene);
    }
    }

    void Composer::goToScene(std::string sceneName){
    // get the beginning address of the scene list
    // Scene is in enclosing <> but can't post it here
    std::list Scene ::iterator itr = scenes.begin();
    while(itr != scenes.end()){
    if (*itr->getName() == sceneName){
    this->lastScene = this->currentScene;
    this->currentScene = itr;
    break;
    }
    }
    }

    void Composer::updateCurrentScene(){
    if (this->currentScene != NULL){
    if (this->lastScene != NULL){
    *this->lastScene->hide();
    }
    *this->currentScene->update();
    }
    }

    void Composer::drawCurrentScene(){
    if (this->currentScene != NULL){
    if (this->lastScene != NULL){
    *this->lastScene->hide();
    }
    *this->currentScene->draw();
    }
    }

    std::string Composer::getCurrentSceneName(){
    if (this->currentScene != NULL){
    return *this->currentScene->getName();
    }
    }

    void Composer::deleteScene(std::string sceneName){
    // Scene is in enclosing <> but can't post it here
    std::list Scene ::iterator itr = scenes.begin();
    while(itr != scenes.end()){
    if (*itr->getName() == sceneName){
    if (itr != this->currentScene){
    if (itr == this->lastScene){
    scenes.erase(itr);
    delete this->lastScene;
    break;
    }
    else {
    scenes.erase(itr);
    break;
    }
    }
    else { // had to change cout to be able to post it
    std::cout -- "Scene can't be deleted as it is the current shown Scene!"
    }
    }
    }
    }

    void Composer::deleteLastScene(){
    // Scene is in enclosing <> but can't post it here
    std::list Scene ::iterator itr = scenes.begin();
    while(itr != scenes.end()){
    if (itr == this->lastScene){
    if (itr != this->currentScene){
    scenes.erase(itr);
    delete this->lastScene;
    break;
    }
    else { // had to change cout to be able to post it
    std::cout -- "Scene can't be deleted as it is the current shown Scene!"
    }
    }
    }
    }
    #endif // __SCENE_H__



    Scene.cpp

    #include "Scene.h"

    Scene::Scene(std::string sceneName){
    this->name = sceneName;
    Composer::addToScenes(this);
    }

    Scene::~Scene(){
    delete name;
    }

    std::string Scene::getName(){
    if (this->name != NULL){
    return this->name;
    }
    }

    And these are the errors i get:

    redlib/Composer.cpp:17:23: error: cannot convert 'Scene' to 'Scene*' in initialization
    Scene* scn = *itr;
    ^
    redlib/Composer.cpp:30:38: error: 'class Scene' has no member named 'getName'
    if (*itr->getName() == scene.getName()){
    ^
    redlib/Composer.cpp:31:13: error: 'cout' is not a member of 'std'
    std::cout << "Scene name already exist!"
    ^
    redlib/Composer.cpp:47:32: error: cannot convert 'std::__cxx11::list<Scene>::iterator {aka std::_List_iterator}' to 'Scene*' in assignment
    this->currentScene = itr;
    ^
    redlib/Composer.cpp: In member function 'void Composer::updateCurrentScene()':
    redlib/Composer.cpp:56:35: error: void value not ignored as it ought to be
    *this->lastScene->hide();
    ^
    redlib/Composer.cpp:58:36: error: void value not ignored as it ought to be
    *this->currentScene->update();
    ^
    redlib/Composer.cpp:67:34: error: void value not ignored as it ought to be
    *this->currentScene->draw();
    ^
    redlib/Composer.cpp: In member function 'std::__cxx11::string Composer::getCurrentSceneName()':
    redlib/Composer.cpp:73:37: error: 'class Scene' has no member named 'getName'
    return *this->currentScene->getName();
    ^
    redlib/Composer.cpp: At global scope:
    redlib/Composer.cpp:77:6: error: prototype for 'void Composer::deleteScene(std::__cxx11::string)' does not match any in class 'Composer'
    void Composer::deleteScene(std::string sceneName){
    ^
    redlib/Composer.cpp:103:21: error: no match for 'operator!=' (operand types are 'std::__cxx11::list::iterator {aka std::_List_iterator}' and 'Scene*')
    if (itr != this->currentScene){
    redlib/Composer.cpp:109:17: error: 'cout' is not a member of 'std'
    std::cout << "Scene can't be deleted as it is the current shown Scene!"
    ^
    redlib/Scene.cpp: In constructor 'Scene::Scene(std::__cxx11::string)':
    redlib/Scene.cpp:6:31: error: invalid conversion from 'Scene*' to 'int' [-fpermissive]
    Composer::addToScenes(this);

    redlib/Scene.cpp: In member function 'std::__cxx11::string Scene::getName()':
    redlib/Scene.cpp:14:20: error: no match for 'operator!=' (operand types are 'std::__cxx11::string {aka std::__cxx11::basic_string<char>}' and 'int')
    if (this->name != NULL){
    redlib/Composer.h:15:33: error: 'Scene' has not been declared
    static void addToScenes(Scene scene);
    ^
    redlib/Composer.h:25:26: error: 'Scene' was not declared in this scope
    static std::list scenes;
    ^
    redlib/Composer.h:25:31: error: template argument 1 is invalid
    static std::list scenes;

    I feel like someone who has never written any line of code.

    Why does it have to be so complicated.
  • Hey again!

    You should upload all of your code to something like Github or at least paste it to https://pastebin.com or similar to show it here. Because at the moment we don't even see line numbers and it's cumbersome to follow.

    I had a brief look at the code and there is a lot wrong with it. Your first bug is because your list contains Scene objects not pointers to Scene objects. But the whole loop is useless because:

    You do only "delete" what you have allocated with "new".

    You could get rid of that whole constructor. My advice is take some book about c++ and read the chapter about pointers, new and delete.

    General rule of thumb:
    "For every new there must be a delete".
Sign In or Register to comment.