Forum: Compiler & IDEs Bedingte Kompilierung


von ALex (Gast)


Lesenswert?

Hi,

ich arbeite mit AVR Studio und möchte abhänging vom Device meinen 
Quellcode compilieren. Dazu möchte ich "MCU" auswerten und zwischen 
ATMEGA und ATTINY unterscheiden.

Meine Frage: gibt es eine möglichkeit, bei #if bzw. #ifdef usw. zu 
schauen, ob in "MCU" ATTINY oder ATMEGA steht und den Rest (bei ATMEGA 
32,16,8 usw.) auszublenden, durch Wildcards oder ähnlich??

Gruß, Alex

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Nein, wildcards gibt es nicht.  Du musst schon einzeln testen:
1
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__)
2
#  define THIS megaTHIS
3
#elif defined(__AVR_ATtiny13__) || defined(__AVR_ATtiny261__)
4
#  define THIS tinyTHIS
5
#else
6
#  error "Unknown MCU type"
7
#endif

von mikro_sven (Gast)


Lesenswert?

Hallo,

da häng ich mich doch gleich mit dran, wenn so ein Thema schonmal offen 
ist:

Ich habe ein ähnliches Problem, ich will eine Initialisierung meines 
verwendeten Controllers vornehmen. Dazu will ich über eine Art 
"Case-Struktur" entscheiden, welcher Controller gewählt wurde und nur 
den dafür zutreffenden Code compilieren lassen. Die restlichen Cases 
brauch ich aber ja nicht im Code, würde nur Platz verschwenden.

Nun dachte ich an eine Bibliothek, die ich dann ins eigentliche Programm 
einbinde. Im Hauptprogramm wird dann beispielsweise über
1
#define mcu tiny25
der Controller festgelegt. In der Bibliothek würde ich dann - wie oben 
beschrieben - über ifdefs den linker entscheiden lassen, welchen 
Init-Code er compiliert. Aber das kann doch unglaublich umfangreich 
werden, oder nicht?

Jetzt hab ich aber mit C leider noch nicht allzu große Erfahrung und 
frage mich, ob das überhaupt Funktioniert bzw. guter Stil ist, oder ob 
man besser anders vorgeht. Könnte man das ganze auch über ein Makefile 
lösen und wenn, wie sollte man da am Besten vorgehen? Ich habe schon 
einige Beispiele über Makefiles gelesen (u. a. auch den Exkurs im 
GCC-Tutorial), aber bedingte Compilierungen hab ich da nicht gefunden.

Viele Grüße und Danke für eure Vorschläge!

Sven

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Könnte man im Makefile nach WinAVR-Vorlage so lösen:

# fuer alle controller
SRC=wieauchimmer.c egal.c foo.c
# controllerspezifischer code
ifeq($(MCU),atmega128)
SRC+=codefueratmega128.c
endif
ifeq($(MCU),atmega16)
SRC+=codefueratmega16.c
endif

Vgl. z.B. http://www.siwawi.arubi.uni-kl.de/avr_projects/#avrprog_boot

Ob das nun übersichtlicher ist, als den Preprocessor zu bemühen, mag 
jeder selbst entscheiden. Meist sind die Unterschiede nicht so gross, 
dass eigene Quellcodedateien benötigt werden.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> In der Bibliothek würde ich dann - wie oben beschrieben -
> über ifdefs den linker entscheiden lassen, welchen
> Init-Code er compiliert.

Das geht so nicht. Präprozessoranweisungen wie #ifdef werden vom 
Präprozessor ausgewertet, und dessen Resultat landet im Compiler. Der 
Linker bekommt Präprozessoranweisungen nie zu sehen.

Dein Ansatz kann -leicht abgewandelt- dennoch funktionieren:
Den Prozessorspezifischen Code packst Du in eigene Module (mindestens 
eines pro Prozessor) und die darin enthaltenen Funktionen benennst Du 
entsprechend eindeutig, also beispielsweise

  m128_init in m128.c
  m32_init in m32.c
  m16_init in m16.c

etc.

Die alle übersetzt Du und packst sie in eine Library. Etwaig verwendete 
globale Variablen müssen ebenfalls dieser Nomenklatur gehorchen.

Dein diese Library nutzender Code bindet eine Headerdatei ein, in der 
per Präprozessoranweisungen aus dem generischen "init" der jeweils zu 
verwendende Name erzeugt wird:

  #if defined(_AVR_ATmega16_)
  #define init m16_init
  #endif

  #if defined(_AVR_ATmega128_)
  #define init m128_init
  #endif

Dein Code ruft "init" auf; durch die Präprozessoranweisung wird das 
korrekte implementierungsabhängige "init" daraus gemacht und der Linker 
linkt aus der Library das Modul, in dem der zugehörige Code enthalten 
ist.

So ginge es.

von G. L. (sprintersb)


Lesenswert?


von mikro_sven (Gast)


Lesenswert?

Danke für eure Antworten!

@rufus: Gute Idee! Zum testen habe ich mir die entsprechenden Module und 
die Library erstellt. Das Header-File (msp_init.h) sieht nun so aus:
1
int msp430_1_init(void);
2
int msp430_2_init(void);
3
int msp430_3_init(void);
4
5
#if defined(_MSP430_1_)
6
#define init msp430_1_init
7
#endif
8
9
#if defined(_MSP_430_2_)
10
#define init msp430_2_init
11
#endif
12
13
#if defined(_MSP_430_3_)
14
#define init msp430_3_init
15
#endif

Meine Main hab ich so geschrieben:
1
#include "msp_init.h"
2
#define MSP430_1
3
4
int main(void)
5
{
6
  init();
7
}

Nun bekomme ich leider einen Fehler, dass "init" nicht definiert ist. 
Verstehe ich das richtig, dass der Präprozessor im Header-File bei den 
Präprozessoranweisungen in meinem Fall 'init' mit 'msp430_1_init' 
ersetzt, da ich in der Main ja gesagt habe '#define MSP430_1'? Dann 
würde im Code ja statt der Funktionsaufruf 'init();' der Aufruf 
'msp430_1_init();' erfolgen.

Ich komm da grad nicht drauf...

Viele Grüße
Sven

von Oliver (Gast)


Lesenswert?

#include "msp_init.h"
#define MSP430_1

ist wohl die falsche Reihenfolge.

Generell wäre es auch sinnvoll, ein #if...#elif..#else error "no device 
defined"-Konstrukt zu verwenden, dann bekommst du eine aussagekräftige 
Fehlermeldung.

Oliver

von mikro_sven (Gast)


Lesenswert?

Perfekt! Danke, das war's. Warum sieht man solche Kleinigkeiten alleine 
nur so schwer?!

Nur zur Info: Zusätzlich muss ich in der Main ja überhaupt
1
#define _MSP430_1_

statt
1
#define MSP430_1

schreiben ;-)

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.