Forum: Compiler & IDEs Frage zur Projektorganisation bei defines


von Cyblord -. (cyblord)


Lesenswert?

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

von Sven P. (Gast)


Lesenswert?

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

von Kali (Gast)


Lesenswert?

>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.

von Kali (Gast)


Lesenswert?

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.

von Sven P. (Gast)


Lesenswert?

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.

von Cyblord -. (cyblord)


Lesenswert?

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

von Kali (Gast)


Lesenswert?

>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?

:-)

von Cyblord -. (cyblord)


Lesenswert?

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

von Kali (Gast)


Lesenswert?

>>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.

von Kali (Gast)


Lesenswert?

>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.

von Cyblord -. (cyblord)


Lesenswert?

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

von Kali (Gast)


Lesenswert?

>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
Noch kein Account? Hier anmelden.