Partage
  • Partager sur Facebook
  • Partager sur Twitter

Probléme de link entre .cpp et .h

    27 février 2023 à 19:04:12

    Bonjour,

    Je rencontre un problème de link entre les différentes solution de mon projet. 
    Voici mon message d'erreur:

    PS D:\Programming\Chess> make
    g++ -c src/main.cpp -o src/main.o -IC:\SFML-2.5.1/include
    g++ src/main.o -o main -LC:\SFML-2.5.1/lib -lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio
    src/main.o:main.cpp:(.text+0x14): undefined reference to `ChessView::ChessView()'
    collect2.exe: error: ld returned 1 exit status
    make: *** [Makefile:7: link] Error 1
    PS D:\Programming\Chess>

    Voici mes fichiers :

    main.cpp

    #include <SFML/Graphics.hpp>
    #include "Game.cpp"
    
    int main()
    {
        Game game;
    
        return 0;
    }


    Game.h

    #ifndef GAME_H
    #define GAME_H
    
    #include "ChessView.h"
    
    class Game
    {
    public:
        Game();
    private:
        ChessView view;
    };
    
    #endif

    Game.cpp

    #include <iostream>
    
    #include "Game.h"
    
    Game::Game(){
        std::cout << "Game created\n";
    }

    ChessView.h

    #ifndef CHESSVIEW_H
    #define CHESSVIEW_H
    
    class ChessView{
        public:
            ChessView();
    
            void update();
            //void drawBoard(Board board); // To implement
    
        private:
            void init();
    };
    
    #endif

    ChessView.cpp

    #include "ChessView.h"
    
    ChessView::ChessView(){
        init();
    }
    
    void ChessView::init(){
        sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!!", sf::Style::Default);
    
        sf::RectangleShape shape;
        shape.setSize(sf::Vector2f(50.f, 50.f));
        shape.setFillColor(sf::Color::Red);
    
        while (window.isOpen()){
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed)
                    window.close();
            }
    
            window.clear();
            window.draw(shape);
            window.display();
        }
    }
    
    void ChessView::update(){
        // TODO
    }

    Le message d'erreur disparait lors de la suppression de la ligne 

    ChessView view;

    dans le Game.h.

    J'ai l'impression que c'est un soucis de headers guard, mais sans en être 100% sûr.

    J'en profite également pour vous demander : Ou est-ce que je dois implémenter mes #includes ? De préférence dans le .h ou dans le .cpp ?

    Merci par avance pour vos retour.

    -
    Edité par 238 27 février 2023 à 19:05:15

    • Partager sur Facebook
    • Partager sur Twitter
      27 février 2023 à 19:54:38

      Je n'ai pas tout lu, mais j'ai tiqué sur

      #include "Game.cpp"


      On inclue jamais de .cpp normalement, seulement des .h

      Pour répondre à votre question, je pense que le mieux est d'inclure tout ce qu'utilise votre classe dans son .h, et d'inclure ce seul fichier en haut du cpp. (C'est ce que vous avez fait visiblement)
      Mais pour utiliser une classe on n'inclue que le .h, jamais le cpp.

      -
      Edité par Umbre37 27 février 2023 à 19:57:29

      • Partager sur Facebook
      • Partager sur Twitter
        27 février 2023 à 21:02:07

        Umbre37 a écrit:

        Je n'ai pas tout lu, mais j'ai tiqué sur

        #include "Game.cpp"


        On inclue jamais de .cpp normalement, seulement des .h

        Pour répondre à votre question, je pense que le mieux est d'inclure tout ce qu'utilise votre classe dans son .h, et d'inclure ce seul fichier en haut du cpp. (C'est ce que vous avez fait visiblement)
        Mais pour utiliser une classe on n'inclue que le .h, jamais le cpp.

        -
        Edité par Umbre37 il y a environ 1 heure


        Merci pour le retour. En effet, j'ai modifié l'include.

        J'ai cependant toujours un msg d'erreur : 

        PS D:\Programming\Chess> make
        g++ -c src/main.cpp -o src/main.o -IC:\SFML-2.5.1/include
        g++ src/main.o -o main -LC:\SFML-2.5.1/lib -lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio
        src/main.o:main.cpp:(.text+0x15): undefined reference to `Game::Game()'
        collect2.exe: error: ld returned 1 exit status
        make: *** [Makefile:7: link] Error 1
        PS D:\Programming\Chess> 

        J'ai essayé de modifier plusieurs petites choses mais sans succés. 

        L'aide est tjrs bienvenue.

        Merci bcp.

        • Partager sur Facebook
        • Partager sur Twitter
          27 février 2023 à 21:37:04

          Il faut compiler Game.cpp et ChessView.cpp en plus de main.cpp, c'est la base de la compilation séparée.
          • Partager sur Facebook
          • Partager sur Twitter
            27 février 2023 à 21:37:53

            Ok j'ai trouvé mon problème. Je n'avais pas l'habitude de compiler avec un makefile (avant j'utilisais codeblock).

            Il faut donc compiler puis linker les .cpp avec les commandes ci-dessous:

            all: compile link clean execute
            
            compile:
            	g++ -c src/main.cpp -o src/main.o -IC:\SFML-2.5.1/include
            	g++ -c src/game.cpp -o src/game.o -IC:\SFML-2.5.1/include
            
            link:
            	g++ src/main.o src/game.cpp -o main -LC:\SFML-2.5.1/lib -lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio
            
            clean:
            	cd src && del *.o
            
            execute:
            	./main.exe

            Merci pour l'aide.

            • Partager sur Facebook
            • Partager sur Twitter
              27 février 2023 à 21:45:23

              Il faut compiler et linker les autres fichiers aussi. C'est votre makefile qui n'est pas bon je pense.
              Edit : oui c'est ça, (j'ai répondu trop tard)

              -
              Edité par Umbre37 27 février 2023 à 21:53:42

              • Partager sur Facebook
              • Partager sur Twitter
                28 février 2023 à 1:45:33

                Juste sur la remarque de @Umbre37

                >je pense que le mieux est d'inclure tout ce qu'utilise votre classe dans son .h, et d'inclure ce seul fichier en haut du cpp.

                Non, ça rallonge la compilation, ça cache les dépendances, etc...

                Il ne faut inclure dans le .h que ce qui est nécessaire à la compréhension du fichier d'en-tête par le compilateur.

                Dans bien des cas, on va inclure le fichier .h dans d'autres .cpp, et ils n'ont pas à connaitre des détails d'implémentation de la classe.

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  2 mars 2023 à 11:32:17

                  > Je n'avais pas l'habitude de compiler avec un makefile

                  Le Makefile n'est pas correct. Il ne tient aucunement compte des dépendances. Et il recompile tout à chaque fois. Ca va à l'encontre du but du Makefile.

                  Si c'est pour faire ça, autant mettre toutes les commandes dans un script, et hop.

                  Voir https://www.mbillaud.fr/notes/makefile-projet.html pour explications.

                  -
                  Edité par michelbillaud 2 mars 2023 à 11:34:40

                  • Partager sur Facebook
                  • Partager sur Twitter
                    13 mai 2023 à 12:18:15 - Message modéré pour le motif suivant : Merci d’utiliser le bouton code pour inséré un code sur le forum


                      13 mai 2023 à 14:12:55

                      Salut,

                      En plus, personne n'a percuté sur le fait qu'il s'agit d'un problème d'édition des liens, et non sur un problème de compilation.

                      Bon, il est vrai que, de manière générale, si le fichier objet d'une unité de compilation n'a pas été correctement utilisé, il y a très peu de chances pour que l'édition des liens n'arrive à son terme, mais quand meme ;)

                      Donc, @238, il faut déjà commencer par comprendre un peu comment fonctionne le processus (induement) appelé "compilation" :

                      Il se déroule (pour ce qui nous intéresse ici) en deux étapes:

                      Durant la première étape, le compilateur va générer ce que l'on appelle un "fichier objet" pour chaque fichier d'implémentation (les fichiers *.cpp) donné.

                      Pour faire simple, il va créer un fichier (portant le plus souvent l'extension *.o ou *.obj) qui contient la traduction de tout le code qu'il trouve dans le fichier *.cpp sous la forme ... d'instructions compréhensibles par le processeur.

                      Cette étape correspond aux lignes

                      compile:
                          g++ -c src/main.cpp -o src/main.o -IC:\SFML-2.5.1/include
                          g++ -c src/game.cpp -o src/game.o -IC:\SFML-2.5.1/include

                      (tu remarqueras au passage que les noms des fichiers générés portent effectivement l'extension .o ;) )

                      Si je disais plus haut que le processus est "mal nommé", c'est parce que, la compilation proprement dite s'arrête une fois que cette étape a été terminée avec succès.

                      La deuxième étape consistera à regrouper l'ensemble des fichiers objet générés lors de la première étape afin de produire le fichier exécutable qui pourra être lancé par l'utilisateur.

                      L'idée qui se cache derrière cette étape étant d'utiliser un outil appelé "éditeur de liens" (ld, dans ton cas) qui va regrouper "bout à bout" dans un seul fichier le contenu de tous les fichiers objets (*.o) avant de parcourir tout ce fichier à la recherche de tous les appels de fonctions que ce fichier contient.

                      A chaque fois qu'il trouvera l'appel à une fonction, il va s'arranger pour faire correspondre cet appel avec ... l'adresse à laquelle la fonction appelée commence.

                      Et, bien sur, s'il tombe sur l'appel à une fonction qu'il n'arrive pas à retrouver dans ce fichier, ben, il va t'engueuler (undefined reference to XXX ) avant d'arrêter brutalement ce qu'il était occupé à faire.

                      Cette deuxième étape correspond dans ton makefile aux lignes

                      link:
                          g++ src/main.o src/game.cpp -o main -LC:\SFML-2.5.1/lib -lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio

                      Enfin, elle devrait y correspondre, mais, comme l'a si bien fait remarquer @michelbillaud, ton makefile est faux, pour la simple et bonne raison que tu indique que cette étape doit utiliser le fichier src/game.cpp, alors que c'est le fichier src/game.o qui contient le code binaire des fonctions de ta classe game

                      NOTA:

                      C'est justement -- entre autres -- pour éviter ce genre de problèmes qu'il est généralement conseillé de placer les fichiers objets généré par l'étape de compilation proprement dite dans un dossier séparé (appelons le obj pour la facilité), qui ne contiendra que eux.

                      Car le fait est que, face à ce problème, la première chose que tu as sans doute faite aura été ... d'aller voir dans l'explorateur de fichier si le fichier game.cpp existait bel et bien et que c'était le cas.

                      Mais tu n'as sans doute pas remarqué qu'il existait un autre fichier dont le nom commençait par game, mais dont l'extension était en *.o

                      En plaçant les fichiers objets dans un dossier à part, la cause de l'erreur t'aurait beaucoup plus facilement sauté au nez, car les possibilité auxquelles tu aurait été confronté étaient:

                      • de chercher "game.cpp" dans le dossier obj et de ne pas le trouver
                      • de chercher "game*"  dans le dossier obj et de constater que le seul fichier dont le nom commence par "game" est le fichier ... game.o
                      • de chercher "game*" dans le dossier src, d'y trouver game.cpp et ... de constater que tu étais dans le mauvais dossier...
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait

                      Probléme de link entre .cpp et .h

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown