Wie Project aufsplitten und eigene Headerdatei einbinden?



  • Sorry, aber ich bin mal wieder an einem dieser Probleme angekommen, mit dem ich absolut nicht gerechnet habe ...

    Nachdem ich jetzt unabhaengig voneinander mehrere Module geschrieben und ausgiebig getestet habe, moechte ich diese jetzt zu einem Projekt zusammenfuehren, also nur noch eine main() haben und den Rest ueber Funktionen aus diversen cpp-Dateien.

    Dazu habe ich mir eine mir eine Datei namens "erpel.h" gebastelt mit folgendems Inhalt:

    //Funktionen deklarieren, diese Funktionen stehgen in der gbslib.cpp
    bool get_Name(std::string);
    bool gbs_print (int, std::string, double);
    

    die ich

    #include "erpel.h"
    

    in die jeweilige cpp-Datei einbinde.

    Die beiden Funktionen, die haeufig gebraucht werden, habe ich zudem in eine Datei namens gbslib.cpp verschoben.

    Wenn ich nun

    g++ -c erpel.cpp
    g++ -c artikel.cpp
    g++ -c gbslib.cpp
    

    ausfuehre, dann scheint alles zu klappen und ich haben anschliessend jeweils eine

    erpel.o
    artikel.o
    gbslib.o
    

    vorliegen.

    Und jetzt kommt mein Problem: Wenn ich nun meine o's linken moechte, dann erhalte ich die Fehlermeldung:

    artikel.cpp: ... undefined reference to `gbs_print(int, std::basic_string<char,
                     std::char_traits<char>, std::allocator<char> >, double)'
    artikel.cpp: ... undefined reference to `get_Name(std::basic_string<char, 
                     std::char_traits<char>, std::allocator<char> >)'
    

    Wenn ich das jetzt richtig interpretiere, denn glaubt der Linker irrtuemlich, meine Funktionen waeren in irgendeiner Library zu finden, oder?

    Ich hatte das bisher so verstanden, als wuerde der Linker bei einem '#include <"erpel.h">' den Inhalt der erpel.h an entsprechender Stelle einfuegen, aber das scheint nicht so zu sein.

    Wo liegt hier mein Denkfehler, fehlt mir was in der erpel.h? Oder habe ich heute einfach mal wieder nur das beruehmte Brett vor'm Kopf?

    Gruss

    Guenther



  • Sieht so aus als wäre beim Linken die gbslib.o nicht dabei. Wie sieht die Kommandozeile beim linken denn aus?



  • LordJaxom schrieb:

    Sieht so aus als wäre beim Linken die gbslib.o nicht dabei. Wie sieht die Kommandozeile beim linken denn aus?

    g++ erpel.o gbslib.o address.o artikel.o -o erpel -lmysqlclient -lsoci_core-gcc-2_2 -lsoci_mysql-gcc-2_2 -lncurses



  • Das #include hat mit dem Linking-Prozess nichts zu tun. Das dient lediglich dem Präprozessor.

    Mit #include bindet man (normalerweise) Header-Dateien (*.h, *.hpp, ...) ein, sprich die Klassenbeschreibungen und Funktionsdeklarationen. Das dient dazu, dass der Kompilierer die Signatur (sprich den Aufruf) der Funktionen kennt, ohne den Inhalt bzw. die Arbeitsweise der Funktionen zu kennen.

    Ergo: Deklarationen gehören nicht in cpp-Dateien, sondern in Header-Dateien.

    // foo.hpp
    void foo();
    
    // foo.cpp
    #include "foo.hpp"
    void foo()
        {
            // Do some foo'ish things
        }
    

    Übersetzen dann wie bekannt:

    g++ -c foo.cpp
    

    Das Hauptprogramm übersetzen und Linken kann dann in einem Schritt erfolgen

    g++ -o progname main.cpp foo.o -lsome_other_lib
    

    Das Linking ist ein selbständiger Arbeitsschritt.

    Grüße...

    Heiko



  • Es scheint mir eher so, dass ich irgendwo einen Denkfehler mit den Funktionen mache.

    Also mal ein Beispiel:

    // Dies ist die erpel.cpp, mein Hauptprogramm welches die main() enthaelt:        
    int main() 
    {
        artikel();     
        return 0;
    }
    
    // Dies ist die artikel.cpp, also ein Unterprogramm
    #include <stdio.h>
    #include <iostream>
    
    int artikel();
    int get_Name();
    
    int artikel() 
    {
    
        get_Name();        // Und dieser Aufruf einer weiteren Funktion scheint mein Problem zu sein, ...         
    
        return 0;
    }
    

    denn diese Funktion wird anscheinend nur dann gefunden, wenn sie in der erpel.cpp steht, also da, wo auch die main() auftaucht.

    Schreibe ich diese Funnktion z. B. in die gbslib.cpp oder auch hier in die artikel.cpp, dann wird sie offensichtlich nicht gefunden ....

    Guenther

    Edit: Sorry, hatte bei der Deklaration getname statt get_Name geschrieben.



  • Du bist ja auch reichlich inkonsequent in der Benennung - C++ unterscheidet schon zwischen Getname() und getname(), erst recht zwischen getname() und get_Name().

    (und der Prototyp der artikel()-Funktion passt auch nicht zur anschließenden Definition)



  • Jein, denn im Source steht das schon richtig drin. Der Fehler ist mir nur hier passiert, als ich das Problem etwas naeher erlaeutern wollte und dabei 'freihaendig' geschriebe habe ...



  • Wenn ich - siehe unten - diese beiden Zeilen hinzufuege, dann werden die Funktionen aus der gbslib.cpp gefunden und das Programm laeuft ...

    // erpel.cpp
    #include "gbslib.cpp"             // <<-- Zeile hinzugefuegt ....    
    
    int main()
    {
        artikel();    
        return 0;
    }
    
    // artikel.cpp
    #include <stdio.h>
    #include <iostream>
    
    bool suche_nach(string &name);    // << -- Zeile hinzugefuegt ....    
    
    int artikel()
    {
        string name;
        .
        .
        suche_nach(name);
    
        return 0;
    }
    

    ... aber ist das so richtig oder eher Zufall?

    Ich war bisher davon ausgegangen, dass es reicht, wenn die gbslib einfach nur mit-gelinked wird.

    Uebrigens habe ich bei der Gelegenheit auch den Namen von get_Name() auf suche_nach() geaendert, da ich mir nicht sicher bin, ob ich nicht mit irgendwelchen reservierten Woertern kollidiere.

    Guenther



  • Ist der suche_nach-Parameter jetzt ein string oder ein string**&**?

    Du musst das schon überall einheitlich machen.



  • probier mal die Funktionen in erpel.h "extern" zu deklarieren, d.h.

    extern bool get_Name(std::string);
    extern bool gbs_print (int, std::string, double);
    


  • Hallo Guenther,

    die Beispiele von dir waren schon recht aufschlussreich. In Bezug auf mein Posting von oben solltest du dein Projekt folgendermaßen aufteilen:

    // erpel.cpp
    #include "artikel.hpp" // <-- ! Headerdatei, nicht Quelldatei
    
    int main()
        {
             int ergbnis = artikel(); // Artikel gibt ein int zurück
                 // dient nur der Verdeutlichung.
             return 0;
        }
    
    // artikel.hpp
    #ifndef ARTIKEL_HPP
    #define ARTIKEL_HPP
      // so genannte include-guards
    
    // Funktionsprototyp
    int artikel();
    
    #endif
    
    // artikel.cpp
    #include "artikel.hpp"
    
    // Funktionionsdefinition
    int artikel()
        {
            // Tut irgendwas sinnvolles
            return 0;
        }
    

    So solltest Du mit all Deinen einzelnen Projektdateien verfahren.

    Grüße...

    Heiko



  • MFK schrieb:

    Ist der suche_nach-Parameter jetzt ein string oder ein string**&**?
    Du musst das schon überall einheitlich machen.

    Also bei der Deklaration und bei der Definition habe ich es einheitlich, das ist es jeweils ein 'string&', aber beim Aufruf der Funktion, so habe ich's gelernt oder zumindest bisher verstanden, benutze ich dann nur 'string'.

    Liege ich da falsch?



  • gboelter schrieb:

    Also bei der Deklaration und bei der Definition habe ich es einheitlich, das ist es jeweils ein 'string&'

    Dann ist es ja gut. In der ersten Version war es noch ein normaler String, keine Referenz. Das ist für die anderen hier nicht immer nachzuvollziehen, weil du Dinge änderst, aber dann nicht den kompletten relevanten Code zeigst.

    aber beim Aufruf der Funktion, so habe ich's gelernt oder zumindest bisher verstanden, benutze ich dann nur 'string'.

    Beim Aufruf gibt man den Typ doch gar nicht an 😕



  • bwbg schrieb:

    ... In Bezug auf mein Posting von oben solltest du dein Projekt folgendermaßen aufteilen ...

    Hallo Heiko,

    Danke fuer Deine Muehe mit den Beispielen, genau so habe ich's gemacht, mindestens 3 x ueberprueft, aber die Fehlermeldung bleibt.

    Ich denke mal, da kollidiert irgendwo was ganz anderes miteinander.

    Ich werde mir nachher mal ein Stueck jungfraeulichen Code schreiben und dass mit den Headerdateien dann dort mal ausgiebig testen. Wenn's dann dort klappt, dann werde ich meinen urspruenglichen Code mal Stueck fuer Stueck auskommentieren und dann hoffentlich zu dem Punkt kommen, wo der Fehler nicht mehr auftritt.

    Dann bin ich hoffentlich schlauer!

    See you later ...

    Guenther



  • Ich habe den Fehler gefunden und der ist mehr als abenteuerlich:

    Nachdem mir so langsam die Uebersichtlichkeit abhanden gekommen war, hatte ich mir Unterverzeichnisse fuer die diversen Dateitypen angelegt, so auch ein Verzeichnis "/mylibs" und genau das war das Problem.

    Unter Linux. das wusste ich bis heute auch nicht, kann der Name eines Unterverzeichnisses naemlich Leerzeichen enthalten, und zwar nicht nur mittendrin, nein, auch am Ende. Und so hatte ich durch einen dummen Fehler platzlich statt "/mylibs" ein Verzeichnis mit dem Namen "/mylibs " Und genau das war der Grund, warum gcc bzw. g++ ploetzlich das Spinnen anfing, wenn auch leider mit einer wenig zutreffenden Fehlermeldung. Der konnte naemlich tatsaechlich einige Dateien nicht finden, die fuer mich aber ganz offensichtlich am richtigen Ort vorhanden waren.

    Und da ich nun schon seit den Morgenstunden vergebens nach diesem Fehler gesucht habe, ich langsam entsprechend genervt war, sind mir so gewisse Ungereimtheiten natuerlich auch nicht mehr aufgefallen.

    Sorry, wenn ich Euch damit nun den halben Tag genervt habe, zumal der Thread im Nachhinein betrachtet eigentlich wohl eher in's Linux Forum gehoert haette.

    Trotzdem nochmals Herzlichen Dank an alle, die versucht haben mir auch hier wieder zu helfen.

    So, jetzt geht's in Bett, denn in 5 Stunden geht's fuer drei Tage nach Singapore. Drei Tage ohne Rechner, mal sehen ob ich das ueberlebe ... 😉

    Gruss

    Guenther


Anmelden zum Antworten