Include mit oder ohne ".."?



  • Hi,

    in größeren Projekten gibt es Ordner. Folglich kommt es vor, dass ich aus:

    /someProject/someFolder/file.h

    heraus eine Datei:

    /someProject/someOtherFolder/otherFile.h

    inkludiere.

    Macht ihr das via

    #include "../someotherFolder/otherFile.h"
    

    oder

    #include "otherFile.h"
    

    ?

    Letzteres klappt ja zumindest in Visual Studio, wenn die Datei im Projekt eingefügt ist. Der Nachteil liegt darin, dass es Doppeldeutigkeiten geben kann, wenn es mehrere Dateien mit demselben Namen, jedoch in anderen Verzeichnissen gibt.

    Der Vorteil ist: Wenn ich im Zuge eines Refactoring die Ordnerstrukturen ändere, ist es erheblicher Aufwand die Pfade bei den Includes überall anzupassen, das vermeide ich mit dem Auslassen des Pfades.

    Wie handhabt ihr das?



  • Ich mache das mit Unterordnern, ich aber noch Anfänger.



  • Ich vermeide Zugriff von einem Unterordner auf Dateien in einen anderen Unterordner.



  • Ich benutze relative Pfade weil damit Eindeutigkeit hergestellt werden kann und man -I compiler switches reduziert. Damit wird dann der Compile Vorgang ein wenig übersichtlicher. Hilft wenn über mehrere dutzend Header-Files includiert wird und man dann noch den überblick behalten will.

    Aber.

    Ich benutze in größeren Projekten ein UML-Tool und lasse mir den Code erzeugen wobei die includes prktischerweise gleich mit generiert werden. Ich habe also keinen Pflegeaufwand.

    Es hat halt seine Vor- und Nachteile.



  • simbad schrieb:

    Ich benutze relative Pfade weil damit Eindeutigkeit hergestellt werden kann

    Relative Pfade sind nicht eindeutig



  • Meter schrieb:

    Der Nachteil liegt darin, dass es Doppeldeutigkeiten geben kann, wenn es mehrere Dateien mit demselben Namen, jedoch in anderen Verzeichnissen gibt.

    Echt?

    Also ich sehge "nachbar.h" als besser an als "../../heimatort/eigenestrasse/nachbar.h".
    Sieht direkter aus und macht es einfacher, eine Sippe mal woandershin zu tun.



  • meier.h

    ../berlin/meier.h
    ../hamburg/meier.h
    ../salzburg/meier.h

    Es ist eine Frage der Anwendung. Man kann, sofern es nötig ist, durch die Verwendung von relativen Pfaden in der Quelle Eindeutigkeit herstellen.

    Wer immer die Quelle liesst muss nicht erst eine Analyse von Config-Scripten und Makefiles durchführen um herauszufinden welcher meier denn gemeint ist.

    Man hat leider bezüglich der Organisation von Dateien in einem Projekt nicht immer die freie Wahl. Da gibt es die wildesten Konstrukte und Entwickler die das dann bis aufs Messer verteidigen.

    Es wird nicht für alle Situationen das richtige sein. Ich fände es auch besser die Dateien von vornherein so zu benennen das es keine Probleme gibt, oder die Software in sich so zu organisieren das man alles übersichtlich zusammen hat.

    Das war hier aber nicht die Frage.



  • Eine Symbol, also eine Klasse oder Funktion, gehört in das gleiche Verzeichnis wie sein Namespace.

    Habe ich eine Funktion foo im namespace bar , dann gehört die Deklaration der Funktion in den Header <bar/foo.h> . Und genau so wird das immer referenziert. Will ich die Funktion in einen anderen Namespace verschieben, dann muss ich eben die Datei wie auch alle includes und alle Aufrufe der Funktion foo ändern. Ich verwende übrigens nie ein "using namespace". Die Funktion würde ich immer mit bar::foo() aufrufen.

    Ein solches Refactoring mache ich nicht so oft. Es gibt Refactoringtools, die einen unterstützen. Mein bevorzugtes Refactoringtool ist perl . Sicher nicht das beste aber mit Sicherheit das Vielseitigste 😃 .

    Man kann mit dem Compilerflag -I steuern, wo die Header zu suchen sind. Die Header einer Library stehen immer gemeinsam in einem eigenen Verzeichnis.

    Wenn die o.g. Funktion in der Lib libbaz zu finden ist, dann ergeben sich immer die Compilerflags -I$BAZDIR/include und die Linkflags -L$BAZDIR/lib -lbaz oder so ähnlich.



  • Evtl. bin ich ja blind oder naiv, aber mMn. ist es doch eindeutig.
    include mit Gänsefüßchen sucht zuerst nach dem absoluten angegebenen Pfad bevor es sich auf die Suche in den übergebenen include_directories macht. Somit ist es eindeutig, wenn die Datei im selben Verzeichnis liegt.
    Habe ich mehrere gleich benannte header in unterschiedlichen directories, z.B.
    <toplevel>/berlin/meier.h
    <toplevel>/hamburg/meier.h
    <toplevel>/salzburg/meier.h
    Dann übergeb ich -I<toplevel> an den Compiler und binde mit #include <berlin/meier.h> ein.



  • Hi,

    erstmal vielen Dank und frohe Weihnachten!

    Ich vermeide Zugriff von einem Unterordner auf Dateien in einen anderen Unterordner.

    Ist das nicht total unrealistisch? Wenn ich z.B. eine mvc-Struktur habe, habe ich auf der ersten Ebene die Ordner model, view und controller. Dass der Controller auf View und Model zugreifen sollte, ist doch klar, also muss das bekannt sein.

    @WoIstDasProblem
    Das gefällt mir. Dann kann man bzgl. des Projektpfads absolute Pfade verwenden und muss beim Verschieben einer Datei nicht ganz so viel ändern.

    @tntnet
    Ich nutze in manchen Projekten QT, da klappt das mit den Namespaces nicht so gut.



  • In einem Projekt mit sehr verschachtelter Ordnerstruktur (die jeweils ihre .cpp un .h-Dateien enthalten) haben wir das so:
    Im Makefile scannt ein find-Befehl alle Ordner rekursiv nach Header-Dateien durch. Von diesen werden dann Hard-Links in einem Verzeichnis mit Namen "Includes" erstellt, und das wird beim Compileraufruf mit einem einzigen -I eingebunden.

    Dadurch braucht einen nicht zu interessieren, wo (relativ zur aktuellen Datei) nun das jeweilige Headerfile liegt.
    Ziel war, sehr schmerzfrei einfach neue Unterordner mit Sources und Headerdateien im Projekt zufügen oder diese verschieben zu können, ohne laufend das Makefile oder die #include-Angaben im Projekt ändern zu müssen (und ohne dass die IDE das makefile anpasst).
    Geht natürlich nur, wenn jede Header-Datei einen einmaligen Namen hat. So sind alle Headers projektweit ohne relative Pfadangaben einbindbar.

    "Alle Headers einer Library in einem Verzeichnis" geht deshalb nicht, weil teilweise aus einigen Basisklassen(headers) und den jeweiligen Ableitungen eigene Treiber-Libraries erstellt werden, spätestens dann hat man beim Einbinden der Basisklassen wieder die "../" und "../../" im Spiel.



  • Hi,

    das klingt auch nicht schlecht, wobei das natürlich ne Bombe ist.

    "Alle Headers einer Library in einem Verzeichnis" geht deshalb nicht, weil teilweise aus einigen Basisklassen(headers) und den jeweiligen Ableitungen eigene Treiber-Libraries erstellt werden, spätestens dann hat man beim Einbinden der Basisklassen wieder die "../" und "../../" im Spiel.

    Das verstehe ich nicht. Wieso geht nicht <topfolder>/dir1/dir2/file.h ?



  • Ich beziehe mich auf die Aussage von "tntnet" ("Die Header einer Library stehen immer gemeinsam in einem eigenen Verzeichnis."), was grundsätzlich sicher auch der richtige Ansatz ist - wenn das Projekt es zulässt und sich nicht viel ändert.
    Beispiel:
    Ein Gerätetreiber (abgebildet als eine Library) benötigt die Basisklasse, ggf. eine Kind-Klasse und letztlich die eigenen Sources. Ein anderer Treiber entsprechend. Ordnerstruktur also so (die .cpp und .h-Dateien in den jeweiligen Verzeichnissen):

    Verkehrsmittel
      + Fahrzeug
          + PKW
          + LKW
    

    Die eine Library soll aus den Klassen Verkehrsmittel, Fahrzeug und PKW bestehen, die andere aus Verkehrsmittel, Fahrzeug und LKW.

    Meter schrieb:

    Wieso geht nicht <topfolder>/dir1/dir2/file.h ?

    Angenommen, ich bin in der Header-Datei der Kind-Kind-Klasse: dann müsste ich schreiben:

    #include "../../Verkehrsmittel.h"
    

    oder so. Geht schon, wollten wir aber nicht. Statt dessen einfach

    #include "Verkehrsmittel.h"
    

    oder umgekehrt, angenommen, die Basisklasse wäre eine Factory und weiß über ihre Kindklassen, dann bräuchte man

    #include "./Fahrzeug/PKW.h"
    

    Wollten wir auch nicht.
    Oder man gibt alle Pfade einzeln mit -I an. Wollten wir auch nicht.



  • Hi,

    also folder == namespace gefällt mir jetzt sehr gut.

    Aber wenn man umstrukturiert in großen Projekten, ist das Ändern u.U. trotzdem aufwendig.

    Habt ihr Skripte, um automatisch namespaces nach Foldern zu erstellen? Denkbar wäre ja:

    // some header in /module1/submodule2/specialFunctions
    
    //* namespaceStart
    
    //* /namespaceStart
    
    //* namespaceEnd
    
    //* /namespaceEnd
    

    zwischen den jeweiligen starts und ends automatisch über ein Skript die Einträge zu erstellen. Oben also die drei verschachtelten namespaces module1, submodule2, specialFunctions und im unteren Bereich nur das Schließen davon.

    Da gefällt mir das package mgmt in Java besser.

    Habt ihr das irgendwie automatisiert?



  • Benutzt ihr bei großen Projekten nichts zur Automatisierung?



  • Nein ist auch ne Antwort 😋


Anmelden zum Antworten