Hallo,
kann jemand mit relativ einfachen Worten erklären, was die Schritte
Clean, Compile und Build bz. Build All beim AVR-Studio bewirken?
(was Kompilierung bedeutet weiss ich natürlich; mir ist aber nicht ganz
klar, wie die drei oben genannten Begriffe hier zusammenhängen, würde es
gerne verstehen)
Damit aus einem Quelltext ein ausführbares Programm entsteht, müssen
mehrere Schritte abgearbeitet werden.
Kein µC versteht zb direkt C. Alles was er kann ist seine
Maschinensprache. Also müssen alle Anweisungen, die der Programmierer in
C geschrieben hat, erst einmal in diese einfachere Maschinensprache
übersetzt werden.
Das ist die Aufgabe des Compilers.
Jetzt teilt man aber ein komplettes C-Programm sinnvollerweise in
mehrere C-Files auf. Jedes wird für sich getrennt compiliert. Nach dem
Compilieren hat man also einen Satz von getrennt übersetzten Einheiten.
Zudem ist nicht alles, was in einem Programm vom Programmierer benutzt
wurde in diesen compilierten Bruchstücken enthalten. Zb wird der
Compiler nicht jedesmal die Routinen für 32 Bit Arithmetik neu
erstellen, sondern er nimmt einfach an, dass es sie gibt. Diese nicht
vom Compiler erstellten Programmteile liegen in Form von Libraries vor
(vorcompilierte Bruchstücke, die in einem gemeinsamen File aufbewahrt
werden).
Jetzt betritt der Linker die Bühne.
Aufgabe des Linkers ist es, die Einzelteile einzusammeln und aus diesen
Einzelteilen ein komplettes Programm zusammenzustellen. Dazu benutzt der
Linker die vom vom Compiler erstellten Übersetzungen der C-Files des
Programmierers und ergänzt diese noch mit den Routinen aus den
Libraries.
Compilieren bedeutet also: ein einzelnes File übersetzen
Unter einem Build versteht man den kompletten Vorgang, also compilieren
und linken, so dass hinten ein komplettes ablauffähiges Programm heraus
kommt.
Dieser Prozess hat natürlich die übersetzen Einzelteile hinterlassen.
Die Files, die der Compiler erzeugt hat müssen klarerweise übrig
bleiben, denn sie werden ja vom Linker gebraucht. Ein Clean bedeutet
jetzt nichts anderes, als das Wegräumen dieses "Schuttes", das löschen
der Zwischenfiles, die auf dem Weg zum endgültigen ablauffähigen
Programm entstanden sind.
Vielen Dank für die ausführliche und verständliche Antwort!
Ein paar Fragen habe ich noch:
Was ist denn der Unterschied zwischen Build und Build all?
Was passiert, wenn man vergisst, Clean zu benutzen?
Also ist die "normale" Reihenfolge bei der Arbeit mit dem AVR-Studio
Compile - Built - Clean !?!
GB schrieb:> Was ist denn der Unterschied zwischen Build und Build all?
Bei einem Projekt mit 5000 C-Files ist es natürlich ein wenig aufwändig,
wenn die Projektverwaltung bei einem Build immer alle 5000 Files durch
den Compiler jagt. C ist ja ausdrücklich so designed worden, dass dies
nicht notwendig ist. Die Projektverwaltung ('make') stellt fest, welche
Files sich geändert haben, und compiliert nur diejenigen bei denen sich
diese Änderung auch auswirkt.
Als Beispiel: Würde man das Projekt, in dem ich involviert bin, komplett
neu kompilieren, dann würde das auf meiner Maschine ungefähr 4 Stunden
dauern. Das macht bei uns ein Server jede Nacht, tagsüber, wenn ich
entwickle, brauch ich nur die Files compilieren, bei denen sich
Codeänderungen auch tatsächlich auswirken.
Build: nur geänderte Datein nachcompilileren
Build All: auf jeden Fall alles compilieren
> Was passiert, wenn man vergisst, Clean zu benutzen?
Nix.
Du belegst ein bischen Platz auf der Platte.
> Compile - Built - Clean !?!
No.
Der normale Weg ist: Build
(und es heißt Build, mit weichem D. engl: to build - bauen
build ist ein unregelmässiges engl. Verb. build - built - built.
built heißt also: er baute/er hat gebaut.)
Wenn du fertig mit deinem Projekt bist und es für das nächste halbe Jahr
einmottest, kannst du einen Clean machen, damit die momentan nicht mehr
gebrauchten Zwischendateien auch gelöscht werden. Die müssen dann eben
beim nächsten Build wieder neu erstellt werden. Nach einem Clean läuft
ein Build auf einen Build All hinaus, weil ja dann tatsächlich alles
neu gemacht werden muss.
Ich verwende bei kleineren Projekten regelmäßig Clean / Build all, weil
schon ein paar mal Änderungen nicht erkannt wurden und teilweiser alter
Code verwendet wurde.
Da meine Projekte relativ klein sind, bedeutet das Clean / Build All nur
einen Mehraufwand von ein paar Sekunden.
Das Problem, dass ein Build all mehrere Stunden beansprucht werde ich
und die meißten Hobby-Programmierer eher selten haben.
Danke für die Antworten!
Karl Heinz Buchegger schrieb:> No.> Der normale Weg ist: Build
Und wann klickt man Compile?
> (und es heißt Build, mit weichem D. engl: to build - bauen> build ist ein unregelmässiges engl. Verb. build - built - built.> built heißt also: er baute/er hat gebaut.)
(War ein Tippfehler, hatte es darüber mehrmals richtig. Nicht
aufgepasst, was?!! ;O))
Barny schrieb:> Ich verwende bei kleineren Projekten regelmäßig Clean / Build all, weil> schon ein paar mal Änderungen nicht erkannt wurden und teilweiser alter> Code verwendet wurde.
Aha!? Ok, da werde ich mal drauf achten.
GB schrieb:> Danke für die Antworten!>>> Karl Heinz Buchegger schrieb:>> No.>> Der normale Weg ist: Build>> Und wann klickt man Compile?
Wenn du ein einzelnes File kurzfristig compilieren möchtest, ohne dass
es dir auf einen durchlaufenden Buildprozess ankommt. Zb wenn du
feststellen willst, ob du einen Syntaxfehler auch wirklich behoben hast
ehe du dich dem nächsten Fehler zuwendest.
Ich benutze Compile zb auch um festzustellen, ob und wenn ja welche
Variablen ich noch nicht definiert habe. Der Compiler sagt es mir in
Form einer Fehlermeldung :-)
Aber ob du an dieser Stelle Compile benutzt oder Build, ist ziemlich
irrelevant. Höchstens, wenn man ein Header File verändern muss und dann
das zugehörige C-File einzeln nachcompiliert, ist es noch nützlich. Ein
Build würde alle vom Header File abhängigen C-Files nachcompilieren, die
mich aber zum jetzigen Zeitpunkt noch gar nicht interessieren, weil ich
mich zunächst nur auf das C-File zum Header-File konzentriere.
Im Zweifelsfall lieber Build als Compile
Vor dem Brennen des Programms in den AVR auf jeden Fall noch einen
Build. Nur um sicher zu gehen.
Und wie Barny schon schrieb: Ab und zu ein Build All kann nicht schaden,
zumal es bei der AVR Programmierung praktisch kein Zeitverlust ist.
Danke Dir für den ausführlichen Hinweis!
Bis jetzt mache ich es so, dass ich für ein Programm immer nur ein
C-File nehme, das dann manchmal ziemlich lang und unübersichtlich wird.
Karl Heinz Buchegger schrieb:> Jetzt teilt man aber ein komplettes C-Programm sinnvollerweise in> mehrere C-Files auf.
Wie kann man das in der Praxis machen?
Noch eine Frage aus reiner Neugierde:
Karl Heinz Buchegger schrieb:> Bei einem Projekt mit 5000 C-Files ist es natürlich ein wenig aufwändig,> wenn die Projektverwaltung bei einem Build immer alle 5000 Files durch> den Compiler jagt. C ist ja ausdrücklich so designed worden, dass dies> nicht notwendig ist. Die Projektverwaltung ('make') stellt fest, welche> Files sich geändert haben, und compiliert nur diejenigen bei denen sich> diese Änderung auch auswirkt.
Du programmierst aber dann keine µController, oder?
GB schrieb:> Danke Dir für den ausführlichen Hinweis!>> Bis jetzt mache ich es so, dass ich für ein Programm immer nur ein> C-File nehme, das dann manchmal ziemlich lang und unübersichtlich wird.>> Karl Heinz Buchegger schrieb:>> Jetzt teilt man aber ein komplettes C-Programm sinnvollerweise in>> mehrere C-Files auf.>> Wie kann man das in der Praxis machen?
Funtkionale Gruppen identifizieren und die in ein eigenes C-File
verfrachten. Alles was zu den Funktionen unmittelbar noch dazugehört
wandert auch mit den Funktionen mit.
Für das C-File dann ein Header File erstellen.
Beides, C-File + Header File in die Projekt-Verwaltung mit aufnehmen.
Beispiel:
du hast zb
1
#include<avr/io.h>
2
3
....
4
5
intledOn;
6
charuart_buffer[30];
7
8
voiduart_init(void)
9
{
10
....
11
}
12
13
voiduart_putc(charc)
14
{
15
....
16
}
17
18
voiduart_puts(constchar*c)
19
{
20
...
21
}
22
23
intmain()
24
{
25
...
26
uart_init();
27
28
...
29
}
also einen Haufen von Funktionen, die sich um die UART drehen. Klarer
Fall für ein Modul, eine funktionale Gruppe.
Also ab mit den Funktionen in ein File UART.C
1
#include<avr/io.h>
2
3
voiduart_init(void)
4
{
5
....
6
}
7
8
voiduart_putc(charc)
9
{
10
....
11
}
12
13
voiduart_puts(constchar*c)
14
{
15
...
16
}
zusätzlich gehört auch noch die globale Variable uart_buffer zu diesem
Modul. So wird nur innerhalb der uart Funktionen benutzt. Ausserhalb
dieser Funktionen muss kein anderer Programmteil darauf zugreifen. ->
wandert ebenfalls in uart.c
1
#include<avr/io.h>
2
3
staticcharuart_buffer[30];
4
5
voiduart_init(void)
6
{
7
....
8
}
9
10
voiduart_putc(charc)
11
{
12
....
13
}
14
15
voiduart_puts(constchar*c)
16
{
17
...
18
}
um diese Funktionen in main benutzen zu können, braucht es noch ein
Header-File, in dem die Funktionen und ihre Signaturen definiert werden
UART.h
1
#ifndef UART_H_INCLUDED
2
#define UART_H_INCLUDED
3
4
voiduart_init(void);
5
voiduart_putc(charc);
6
voiduart_puts(constchar*c);
7
8
#endif
in main.c wird nun einfach das Header File included, damit dort bekannt
ist
* welche Funktionen es gibt
* wie die Argumentliste aussieht
(in Uart.c kommt sinnvollerweise ebenfalls ein #include von uart.h rein.
Das ermöglicht dem Compiler die Überprüfung, ob das Headerfile auch mit
den tatsächlichen Funktionen übereinstimmt)
1
#include<avr/io.h>
2
#include"uart.h"
3
4
....
5
6
intledOn;
7
8
intmain()
9
{
10
...
11
uart_init();
12
13
...
14
}
Nach schnell die beiden Files uart.c und uart.h zur Projekt hinzugefügt
(entweder ins Makefile eintragen oder beim AVR-Studio zum Projektbaum
hinzufügen)
und schon sollte wieder alles compilieren.
> Du programmierst aber dann keine µController, oder?
:-)
Nein.
µC Programmierung ist ein Hobby von mir.
Berufsmässig sinds momentan PC. Ich hab aber bis zum Mainframe schon so
ziemlich jede Rechnerklasse programmiert.
Warum lagert man Prototypen manchmal mit extern aus?
Worin besteht der Unterschied wenn ich den Prototyp mit extern oder
nicht extern
in meinen Header schreibe.
Knut
Knut schrieb:> Warum lagert man Prototypen manchmal mit extern aus?> Worin besteht der Unterschied wenn ich den Prototyp mit extern oder> nicht extern> in meinen Header schreibe.
was macht 'extern'.
Es unterscheidet eine Defintion von einer Deklaration.
Etwas von der Form
int i;
ist eine Definition (Speicher wird tatsächlich dafür allokiert).
Etwas von der Form
extern int i;
ist eine Deklaration (hier wird kein Speicher allokiert. Der Compiler
nimmt einfach nur zur Kentniss, dass es ein i gibt und das es vom Typ
int ist. Aber wo dieses i existiert ist damit nicht gesagt)
Dafür braucht man extern.
Bei Funktionen ist es jetzt so
So etwas
void foo( void )
{
...
}
kann nur eine Definition sein. Hier wird die Funktion ja tatsächlich
implementiert.
So etwas
void foo( void );
kann nur eine Deklaration sein, denn hier wird die Funktion selber ja
nicht implementiert. Der Prototyp sagt nur aus, dass es eine Funktion
dieses Namens gibt und wie seine Argumenttypen und Rückgabetypen sind.
Fazit: Bei Funktionen kann der Compiler aufgrund der äusseren Form
Defintionen von Deklarationen unterscheiden. Daher ist hier ein
explizites extern nicht notwendig. Du kannst eines machen, wenn du
willst, kannst es aber auch einfach weglassen. Es macht keinen
Unterschied.
Darf ich mich auch bitte mit einer Frage anschließen:
Was hat es damit auf sich:
1
#ifndef UART_H_INCLUDED
2
#define UART_H_INCLUDED
#ifndef und #define ist mit bekannt aber ich kenne den Teil aus den
Header-Dateien bisher nur in der Form:
1
#ifndef XYZ_H_
2
#define XYZ_H_
Was hat es mit dem INCLUDED auf sich? Kann man irgendwo was zur Syntax
dazu nachlesen? Wie zum Beispiel, wofür stehen die Unterstriche und
wofür muß das überhaupt so eingebunden werden?
Danke
LG
Ernst
Ernst B. schrieb:> Darf ich mich auch bitte mit einer Frage anschließen:>> Was hat es damit auf sich:>>
1
>#ifndefUART_H_INCLUDED
2
>#defineUART_H_INCLUDED
3
>
>> #ifndef und #define ist mit bekannt aber ich kenne den Teil aus den> Header-Dateien bisher nur in der Form:>>
1
>#ifndefXYZ_H_
2
>#defineXYZ_H_
3
>
>
ist genau das gleiche.
Ich nenne halt meine Konstanten für die Include-Guards hinten noch mit
einem _INCLUDED, damit ich nicht Gefahr laufe, gleiche Namen zu
vergeben.
> Was hat es mit dem INCLUDED auf sich? Kann man irgendwo was zur Syntax> dazu nachlesen? Wie zum Beispiel, wofür stehen die Unterstriche und
es ist einfach nur ein Name. Mehr steckt da nicht dahinter.
> wofür muß das überhaupt so eingebunden werden?
Als Include Guard, damit der Inhalt der Header Datei in einer
Übersetzungseinheit nur einmal compiliert wird.
http://en.wikipedia.org/wiki/Include_guard
Karl Heinz Buchegger schrieb:> Funtkionale Gruppen identifizieren und die in ein eigenes C-File> verfrachten. Alles was zu den Funktionen unmittelbar noch dazugehört> wandert auch mit den Funktionen mit.>> Für das C-File dann ein Header File erstellen.
Danke für das Beispiel!!! Werde es in den nächsten Tagen testen!