undefined reference to ...

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 http://www.raylib.com/ 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?

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  
#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<Scene> scenes;
        // handle to the current shown scene
        Scene *currentScene;
        // handle to the last shown scene
        Scene *lastScene;
};

#endif // __COMPOSER_H__ 


Composer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

#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 {
                std::cout << "Scene can't be deleted as it is the current shown Scene!"
            }
        }
    }
}



test.c (main)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#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 Scene and 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:
1
2
3
4
5
6
7
8
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<char, std::char_traits<char>, std::allocator<char> >)'
C:\Users\Micha\AppData\Local\Temp\ccYNvs8W.o:test.c:(.text+0xc7): undefined reference to `Composer::goToScene(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
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!












Last edited on
Your compile/link command doesn't mention the file composer.cpp , so that file isn't being compiled and linked.

Also, rename your test.c file to "test.cpp". It's C++ code and various tools will, in the absence of direct instructions, sometimes use the file extension to know what kind of file it is.

std=c99 ; why? You're writing C++ code. You may well be linking to libraries that were compiled as C code, but your compiler is operating on your C++ code.

That said, you might have trouble linking if the raylib headers don't include instructions that the libraries to link to were compiled as C code. If you hit that, I'm sure you'll come back.
Last edited on
Thanks for the reply.

I've changed it to test.cpp. Further i removed the std:c99. Now i don't know how to tell the compiler/linker about the other files.

I'm using the preconfigured Notepad++ from raylib with this preconfigured script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//echo > Setup required Environment
//echo -------------------------------------
SET RAYLIB_DIR=C:\raylib
ENV_SET PATH=$(RAYLIB_DIR)\MinGW\bin
cd $(CURRENT_DIRECTORY)
//echo
//echo NOTE: raylib uses OpenAL Soft library compiled statically and linked into the executable
//echo
//echo > Cleaning latest build
//echo ---------------------------
cmd /c IF EXIST $(NAME_PART).exe del /F $(NAME_PART).exe
//echo
//echo > Compiling program
//echo -------------------------
g++ -o $(NAME_PART).exe $(FILE_NAME) -s $(RAYLIB_DIR)\raylib\raylib_icon -Iexternal -lraylib -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm  -Wl,-allow-multiple-definition -Wl,--subsystem,windows
//echo
//echo > Reset Environment
//echo --------------------------
ENV_UNSET PATH
//echo
//echo > Executing program
//echo -------------------------
cmd /c IF EXIST $(NAME_PART).exe $(NAME_PART).exe


the "g++" command i've changed as it was "gcc" previously.

Last edited on
closed account (SECMoG1T)
in addition i have found this errors on your class member definitions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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);
    }
}


1. you shouldn't specify return type for constructors, that's invalid in c++ void Composer::Composer()//should be an error

2.you shouldn't specify return type for destructors, also invalid in c++ void Composer::~Composer()

3.static void Composer::addToScenes(Scene scene) you shouldn't re-declare
that static qualifier when defining your static function, just use it only in in-class
declaration otherwise it's an error.

4. remember to define your static members before trying to use them anywhere, the linker
should complain "undefined reference" , they aren't defined anyways
std::list<Scene> scenes;//this guy here

5. line 20 in your main , assign that scene to a pointer
Now i don't know how to tell the compiler/linker about the other files.


All at once.

g++ -o test.exe test.cpp composer.cpp scene.cpp anythingElse.cpp -s C:\raylib\raylib\raylib_icon -Iexternal -lraylib -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm -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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "Composer.h"


Composer::Composer(){
    this->currentScene = NULL;
    this->lastScene = NULL;
    std::list<Scene> 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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 some of the errors i get:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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<Scene>}' 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<Scene>::iterator {aka std::_List_iterator<Scene>}' 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<Scene> scenes;
                          ^
redlib/Composer.h:25:31: error: template argument 1 is invalid
         static std::list<Scene> scenes;


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

Why does it have to be so complicated.
Last edited on
Why does it have to be so complicated.

Programming in C++ and C and other such languages demand a more precise way of thinking, and understanding what you're creating. Let's look at the first error:

1
2
redlib/Composer.cpp:17:23: error: cannot convert 'Scene' to 'Scene*' in initialization
         Scene* scn = *itr;


What kind of object is scn ? It is a pointer-to-scene.
What kind of object is *itr? itr is an iterator, and the * operator applied to it gives you the object it is associated with in the container, and in this case that object is a Scene object. So *itr is a Scene object.

So you're trying to make a pointer (which is a single number, representing a memory location) the same as a Scene object, which is a big class. Makes no sense, hence the error. Also, very very simple. You just have to understand what kind of objects you have.

For the next one, seeing your scene.h file would be helpful.

You might also find understanding how code is turned into binary in C++ helpful; https://www.daniweb.com/programming/software-development/tutorials/466177/understanding-c-from-source-to-binaries


I'm seeing a lot of unnecessary use of this-> , and I'm seeing a lot of delete without much sign of corresponding new. Managing your own memory in such a manual fashion is to be avoided; I'm not convinced it's necessary here. In fact, it looks like you're just plain using it incorrectly. delete means "this object I allocated with new; please run the object's destructor and I don't care what you do with the memory after that". If you are applying delete to an object that wasn't created with new, it's a mistake.

Your headers look pretty messed up. string.h is for C-style strings. <string> is for C++. I see classes trying to use std::cout that don't include <iostream>. stdio.h is a legacy C header providing functions you're not using.

*this->lastScene->hide();
I've got no idea what's going on here.

-> allows you to dereference a pointer and then call a function on it, but you're dereferencing the pointer yourself and then applying -> anyway.

*this->lastScene->hide(); should be lastScene->hide();, on the assumption that lastScene is a pointer. Is it?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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;
    }
}

This looks very wrong. In the constructor, name is implied to be an object of type std::string. But in the function getName, you're checking if it's NULL. You're trying to check if it's a NULL pointer. Is it a pointer or is it a string? As it is, NULL is old-school code that causes problems in situations like this, because it's sometimes just 0. Do yourself a favour; use nullptr for null pointers. Then, in the destructor, you're trying to delete it, so it must be a pointer, but when was it created with new? This all suggests you're using pointers, new and delete without understanding what they are and what they do.

Last edited on
Topic archived. No new replies allowed.