Forum: Mikrocontroller und Digitale Elektronik AVR-Studio: Clean, Compile, Built


von GB (Gast)


Lesenswert?

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)
von Karl H. (kbuchegg)


Lesenswert?

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.
von GB (Gast)


Lesenswert?

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  !?!
von Karl H. (kbuchegg)


Lesenswert?

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.
von Barny (Gast)


Lesenswert?

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.
von GB (Gast)


Lesenswert?

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.
von Karl H. (kbuchegg)


Lesenswert?

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.
von GB (Gast)


Lesenswert?

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?
von Karl H. (kbuchegg)


Lesenswert?

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
int  ledOn;
6
char uart_buffer[30];
7
8
void uart_init( void )
9
{
10
  ....
11
}
12
13
void uart_putc( char c )
14
{
15
  ....
16
}
17
18
void uart_puts( const char* c)
19
{
20
  ...
21
}
22
23
int main()
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
void uart_init( void )
4
{
5
  ....
6
}
7
8
void uart_putc( char c )
9
{
10
  ....
11
}
12
13
void uart_puts( const char* 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
static char uart_buffer[30];
4
5
void uart_init( void )
6
{
7
  ....
8
}
9
10
void uart_putc( char c )
11
{
12
  ....
13
}
14
15
void uart_puts( const char* 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
void uart_init( void );
5
void uart_putc( char c );
6
void uart_puts( const char* 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
int  ledOn;
7
8
int main()
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.
von Knut (Gast)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

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.
von Ernst B. (puravida)


Lesenswert?

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
von Karl H. (kbuchegg)


Lesenswert?

Ernst B. schrieb:
> 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
3
>
>
> #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_
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
von Ernst B. (puravida)


Lesenswert?

Danke!
von GB (Gast)


Lesenswert?

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