Hey! raylib forum is closing!

After a year with not much movement in the forum I decided to close it.

The cost of maintaining the hosting is a bit high for the usage of the platform, updating the forum and managing it is also a bit cumbersome and the truth is that I'm already trying to maintain multiple other networks pretty more active than this forum.

I'll recommend you to move to the other raylib networks:

- For a forum style, use Reddit: https://www.reddit.com/r/raylib/
- For direct messaging and questions, use Discord: https://discord.gg/VkzNHUE
- To report issues, use GitHub: https://github.com/raysan5/raylib

- Also, remember you can contact me personally on Twitter: https://twitter.com/raysan5 or directly by mail to ray[at]raylib.com

If you feel generous, you can also contribute to the project on my Patreon: https://www.patreon.com/raylib

Thanks to you all for joining the project and help to improve it with your questions. Keep it up! :)

Best Regards,

Ray

PD. Closing will be effective by October 31th.

undefined reference to ...

edited November 2017 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.