Hallo Leute, habe eine etwas allgemeine Frage. Und zwar wie macht man es richtig. Viele libs werden ja durch #defines konfiguriert. z.B. für Port-Definitionen usw. Ist aber ein Projekt mal kompiliert, sind die Makros expandiert und schon fest im Code drinn und könnnen nicht mehr verändert werden. Kopiere ich direkt die .c Datei in das Projekt, so hab ich viele Kopien davon und Änderungen an der lib, gehen an den bisherige Projekten vorbei. Ein Blick in die delay.h (welche ja das F_CPU Makro benötigt) zeigt, dass hier der Code direkt in der Header-Datei steht. Es gibt also gar keine .c Datei und somit kann die delay.h immer eingebunden werden und vorher kann das F_CPU Makro definiert werden. Aber ist das so sauber, den Code komplett in den Header? Was ist da bei größeren Dingern als der kleinen delay loops? Also wie macht man eine Lib, welche an nur einer Stelle liegt (wegen Wartung z.B.) und von vielen Projekten verwendet wird, und für jedes Projekt trotzdem andere Port-Definitonen erhalten kann. viele grüße cyblord
Julian V. schrieb: > Kopiere ich direkt die .c Datei in das Projekt, so hab ich viele Kopien > davon und Änderungen an der lib, gehen an den bisherige Projekten > vorbei. Jein. Sofern du die Quelldateien sauber modularisierst, kannst du die ja in einem zentralen Bibliotheksstamm halten. Beim Übersetzen landet das Objektmodul dann halt im jeweiligen Projektstamm und ist aktuell. Dazu gibts Makefiles. > Ein Blick in die delay.h (welche ja das F_CPU Makro benötigt) zeigt, > dass hier der Code direkt in der Header-Datei steht. Hat da aber andere Gründe. > Also wie macht man eine Lib, welche an nur einer Stelle liegt (wegen > Wartung z.B.) und von vielen Projekten verwendet wird, und für jedes > Projekt trotzdem andere Port-Definitonen erhalten kann. Zum Beispiel so:
1 | /eda/lib/display.c |
2 | /eda/lib/display.h |
3 | /eda/lib/delay.h |
4 | |
5 | /eda/projects/testproject/main.c |
6 | /eda/projects/testproject/main.h |
7 | /eda/projects/testproject/ports.h |
Dann den Bibliotheksstamm in den Suchpfad aufnehmen (Option -I beim gcc). Dann findet die 'display.h' ihre 'ports.h', egal wo sie liegt. Und wenn dann übersetzt wird, landen die Objektmodule etwa da:
1 | /eda/projects/testproject/main.o |
2 | /eda/projects/testproject/display.o |
>Viele libs werden ja durch #defines konfiguriert. z.B. für >Port-Definitionen usw. Welche denn? Von Libraries, in deren Quellcode ein Port in Form einer Konstante festgelegt wird, (egal ob per define oder nich) würde ich die Finger lassen. Das halte ich für schlechten Stil. Von daher ist die Frage nicht relevant. >Also wie macht man eine Lib, welche an nur einer Stelle liegt (wegen >Wartung z.B.) und von vielen Projekten verwendet wird, und für jedes >Projekt trotzdem andere Port-Definitonen erhalten kann. Die enthalten Funktionen so schreiben, dass sie Ports und ähnliche varianten als Parameter verwenden und nicht als Konstanten.
Svens Vorschlag geht natürlich auch, bezieht sich aber strenggenommen nicht auf Libraries auch wenn da im Pfad "lib" steht. Eine Library wird im letzten Schritt nur noch dazugelinkt. Bei Svens Variante, die ich durchaus für sinnvoll halte, wird der Code komplett neu kompiliert.
Ja klar. Das Problem ist, dass auf dem AVR (ich schließe drauf wegen 'F_CPU') solche Dynamik kaum rentabel ist. Natürlich könnte man den Hardware-Kram über Zeiger oder Funktionen kapseln, aber beim AVR ist die Codegröße doch eher überschauber. Zumal sich an dieser Art von Konfiguration i.d.R. ja nicht jeden Tag etwas ändert.
Erstmal danke für eure Antworten! Ja sorry es geht natürlich um AVR-GCC, ich habe gar nicht realisiert dass dieses Unterforum ja nur GCC heißt. Die Quelldateien mittels -I einzubinden habe ich bereits versucht. Auf diese Weise kann ich die Header auch korrekt einbinden, aber der Compiler meldet trotzdem: undefined reference to 'meineFunction'. Obwohl die dazugehörige .c Datei im selben Verzeichniss ist wie Header-Datei (welche ja gefunden wird). Was mache ich falsch? @Kali: Du hast natürlich recht, sowas ist kein guter Stil. Aber nehmen wir mal eine Lib zum ansteuern von einem Display. Wie würde man da vorgehen? Eine Init-Funktion welche sämtlichen Ports übergeben bekommt und die werden dann im Speicher gehalten in Form von Variablen? Obwohl sie sich ja im ganzen Programmablauf nie ändern? Kommt mir halt übertrieben vor. Deshalb aber meine Frage, wie macht mans richtig. Gibts zu deiner Methode irgendwo ein Codebeispiel von einer lib die Ports auf diese Weise bekommt? gruß cyblord
>Die Quelldateien mittels -I einzubinden habe ich bereits versucht. ... Was >mache ich falsch? Lies mal die Compiler-Dokumentation, bitte. -I ist dafür da, den inlucde-Pfad, also den der h-Dateien anzugeben. Damit kriegst Du keine Quellcode (c) Dateien in Dein Projekt. Das geht mit dem entsprechenden Menu in AVRStudio bzw. dem Makefile. >Aber nehmen wir mal eine Lib zum ansteuern von einem Display. Wie würde man >da vorgehen? Siehe meine erste Antwort. >Eine Init-Funktion welche sämtlichen Ports übergeben bekommt und die >werden dann im Speicher gehalten in Form von Variablen? Nochmal meine Antwort lesen bitte. Wo steht da was von Variablen? Ich schrieb Parameter . Und es gibt da noch das const Attribut. >Gibts zu deiner Methode irgendwo ein Codebeispiel von einer lib die Ports >auf diese Weise bekommt? Netter Versuch. He he he. Aber ich habe zuerst gefragt. Du: >Viele libs werden ja durch #defines konfiguriert. Ich: >Welche denn? :-)
Mein Beispiel war ja delay.h. Dort wird über Makros konfiguriert. Ich wusste das -I für Header gedacht ist, aber genau das hat Sven vorgeschlagen. Darum dachte ich es müsste wohl auch gehen so die Sourcen einzubinden. gruß cyblord
>>Eine Init-Funktion welche sämtlichen Ports übergeben bekommt und die >>werden dann im Speicher gehalten in Form von Variablen? >Nochmal meine Antwort lesen bitte. Wo steht da was von Variablen? Ich >schrieb Parameter . Und es gibt da noch das const Attribut. Na gut. Das ist vielleicht ein wenig überschlau von mir. Schau Dir mal die Sachen in der Codesammlung an. Z.B. die LCD-Routinen oder Peter Danneggers Tastenentprellung oder Software-UART. Sie werden über defines konfiguriert. Das sind aber alles keine Libraries bzw. nicht dazu gedacht, als Library verwendet zu werden. Sie werden jedesmal neu mit dem Projekt kompiliert. Wenn Du mit defines arbeiten willst, weil das effizienter als eine Lib ist (was es zweifellos ist, trotz const etc.) dann musst Du die eben skizzierte Technik verwenden. Eine andere Wahl hast Du nicht. In Deinem ersten Posting hast Du ausdrücklich von Libraries gesprochen. Darauf muss die Antwort einfach sein, das man mit Parametern arbeitet. Das ist das einzig sinnvolle um trotzdem Flexibilität zu haben. Deswegen, wenn Du fragst: >Aber nehmen wir mal eine Lib zum ansteuern von einem Display. Wie würde >man da vorgehen? dann muss man, unter der Voraussetzung, das Parameter nicht verwendet werden sollen, schlicht sagen, man würde keine Lib nehmen. Tut mir leid. So ist es nunmal.
>Mein Beispiel war ja delay.h. Dort wird über Makros konfiguriert. Nun gut. aber wofür ist das ein Beispiel? Das ist weder ein Beispiel für eine Library noch (im engeren Sinne) für einen mitkompilierten Code. Vielmehr ist das ein Sonderfall, in dem Makroexpansion benutzt wird. >Ich wusste das -I für Header gedacht ist, aber genau das hat Sven >vorgeschlagen. Darum dachte ich es müsste wohl auch gehen so die Sourcen >einzubinden. Entschuldige bitte, aber warum dachtest Du das? Sven hat nur geschrieben, das die H-Datei damit gefunden wird. Von den C-Dateien hat er nichts gesagt. Wie aus seiner Aussage zu schliessen ist, das damit die C-Dateien auch gehandelt werden, kann ich mir absolut nicht erklären.
Gut gut, dann gehen wir mal weg vom Begriff "libs". Dieser ist an der Stelle natürlich falsch, weil libs schon übersetzt sind. Dann werde ich wohl meine Pseudo-Libs (in Form von Quellcode) an einem Zentralen ort halten und schauen wie ich die Quelltexte von dort korrekt einbinde. Ich benutze btw. Eclipse. Und Makefiles selber machen ist da eigentlich nicht mehr nötig. Eine entsprechende Konfiguration sollte es da irgendwo geben. Ich dachte nur dieses Problem würde öfters auftauchen und dafür gäbe es eine elegante Lösung. Trotzdem würde mich ein Beispiel Interessieren wie man möglichst Ressourcenschonend Port-Definitionen per const Parametern festlegt. Denn ich möchste die ja nicht bei jedem Funktionsaufruf wieder alles übergeben, sondern nur einmal und dann sollen die Ports festgelegt sein. gruß cyblord
>Trotzdem würde mich ein Beispiel Interessieren wie man möglichst >Ressourcenschonend Port-Definitionen per const Parametern festlegt. >Denn ich möchste die ja nicht bei jedem Funktionsaufruf wieder alles >übergeben, sondern nur einmal und dann sollen die Ports festgelegt sein. Ich muss bekennen, das der Tip mit const hier nicht greift. Denn zu irgendwelchen Optimierungen wird das nicht führen. Nur dazu, das überprüft wird ob ein Parameter verändert wird. Tut mir leid, wenn ich Dich da irregeführt habe. Eine Lösung, die die Übergabe der Parameter vermeidet, aber nicht effizient ist, wäre eine Konfigurationsfunktion zu schreiben, welche Ports etc. in Variablen zwischenspeichert. Die Library-Funktionen greifen dann auf diese Variablen anstelle der Parameter zu. Betrachte das Thema mal mit ein wenig Abstand: * Libs werden, wie Sven schon bemerkt hat, in dem Zusammenhang mit Ports etc. auf Mikrocontrollern nicht oder unter Inkaufnahme von Ineffizienzen verwendet. * Defines lassen sich mit Libs nicht (in dem hier gemeinten Sinne) verwenden, denn defines müssen erst noch durch den Compiler, libs aber nicht. * avr-libc darf nicht streng als Library im enegeren Sinne verstanden werden. Sie ist ein Konglomerat aus Teilen, die eine echte Library sind und Sourcecode der mit defines konfigurierbar ist (z.B. _delay).
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.