Inclusione condizionata di librerie ...

Ecco qui un bel problemino ...

... vorrei scrivere un singolo programma che, nel caso venga compilato per ATtiny85 includa la libreria "TinyWireM", mentre, nel caso venga compilato per ATmega328p includa la libreria "Wire" ... così da compilare senza errori in funzione del target dove deve essere eseguito ...

Occhio a dare una risposta troppo d'impulso ... ]:smiley:

Guglielmo

Devo cercarti i particolari o posso risponderti in generale?
Esiste una variabile di sistema che determina il Controller in uso.

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
codice per ATmega328...
#else
Codice per gli altri Controller
#endif

Controlla un po la libreria fastSPI.
Non so come si chiama la variabile per il ATtiny85 ma se Ti serve solo l' uno o l' altro basta controllare se non é un ATmega328p

Ciao Uwe

Grazie Uwe, ma ... avevo ben evidenziato di NON rispondere troppo d'impulso ... ]:smiley:

La soluzione

#if defined( __AVR_ATtiny85__ )
   #include <TinyWireM.h>
#else
   #include <Wire.h>
#endif

... è ovviamente quella che uno da d'impulso, ma ... metti la libreria TinyWireM nella tua cartella delle librerie, scrivi un semplice programmino, che non fa nulla (setup e loop anche vuoti), ma che in testa contiene quel "#if defined", e prova a compilarlo per Arduino UNO ... avrai una bella sorpresa !!! ]:smiley: ]:smiley: ]:smiley:

Ecco ... ti risparmi la fatica di scriverlo, compila questo per Arduino UNO ...

#if defined( __AVR_ATtiny85__ )
   #include <TinyWireM.h>
#else
   #include <Wire.h>
#endif

void setup() {}

void loop() {}

Altre idee che invece funzionano ??? XD

Guglielmo

@ elrospo : Non ho ben capito cosa vorresti che l'IDE facesse ... ma comunque l'argomento di questo thread è ...

... il funzionamento del "#ifdef" o "#if defined" assieme alla "#include" :wink:

Grazie,

Guglielmo

Ciao Guglielmo
Parli in indovinelli. :wink:

In questo momento non posso fare prove perché non ho nessuna board definita con un ATtiny85 e non ho tempo di farlo.
In questo momento nella compilazione la libreria mi da un sacco di errori di registri non definite indipendentemente si includo la libreria in modo non condizionato o condizionato.
Da quel poco che so dedurre é che sembra che la libreria venga inclusa indipendentemente dalla condizione #if.

prendendo come esempio la libreria FastSPI_LED dovrebbe funzionare:

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
  #include <pins_arduino.h>
#else
  #include "WProgram.h"
  #include <pins_arduino.h>
#include "wiring.h"
#endif
#include "avr/interrupt.h"
#include "avr/io.h"
#include "FastSPI_LED.h"
...
// some spi defines
// Duemilanove and mini w/328
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
#define SPI_PORT PORTB
#define SPI_DDR  DDRB
#define SPI_PIN  PINB
#define SPI_MOSI 3       // Arduino pin 11.
#define SPI_MISO 4       // Arduino pin 12.
#define SPI_SCK  5       // Arduino pin 13.
#define SPI_SSN  2       // Arduino pin 10.
#define DATA_PIN 11
#define SLAVE_PIN 12
#define CLOCK_PIN 13
#define LATCH_PIN 10
#define TIMER_AVAILABLE 1

Ciao Uwe

uwefed:
Ciao Guglielmo
In questo momento non posso fare prove perché non ho nessuna board definita con un ATtiny85 e non ho tempo di farlo.
In questo momento nella compilazione la libreria mi da un sacco di errori di registri non definite indipendentemente si includo la libreria in modo non condizionato o condizionato.

NON ti serve l'ATtiny85 ... sei già caduto sul problema, tanto è vero che mi dici "... mi da un sacco di errori di registri non definite indipendentemente se includo la libreria in modo non condizionato o condizionato" ... :grin: :grin: :grin:

E' proprio questo il punto ...
... come vedi anche se la "#if defined", ma anche la "#ifdef", escludono una certa condizione, questa ... viene comunque compilata ... con i casini che ne conseguono e, con il fatto che quindi ... NON riesci a compilare il codice !!!

Guglielmo

P.S. : E' ovvio che dia un sacco di errori ... quelli sono registri del ATtiny85 che non esistono su Arduino UNO ... e difatti, NON essendo definito AVR_ATtiny85 non dovrebbe compilare quella lib ... invece ... :roll_eyes:

gpb01:

#if defined( __AVR_ATtiny85__ )

#include <TinyWireM.h>
#else
  #include <Wire.h>
#endif

void setup() {}
void loop() {}

Cioè stà roba mi compila tutte e due ?
Qui allore è l'IDE che "sbaglia" dicendo al compilatore di prenderle tutte e due.

gpb01:
Altre idee che invece funzionano ??? XD

Si, rivedere il codice dell'IDE che analizza lo sketch per capire quali librerie compilare :grin:

P.S. hai provato sia con ide 1.0.5 che con 1.5.5 ?

Forse usare una define che modifichi un unico #include ma non ho mai provato

#if defined( __AVR_ATtiny85__ )
   #define  WIRELIB TinyWireM.h
#else
   #define WIRELIB Wire.h
#endif
#include <WIRELIB>

Anche se non sò come possa l'IDE analizzare corretamente questa se già non riesce con quella precedente

EDIT: compilare, compila (sia 1.0.5 che 1.5.5) , non so se funzia.

No Nid ... non compila correttamente, ma credo che tu non te ne accorgi perché probabilmente hai il "verbose" non attivo ... mettilo attivo in compilazione e vedrai ... :wink:

La strada che indichi si chiama "Computed Includes" ... ed è la seconda strada che ho provato anche io subito dopo aver visto il problema con la include normale, ma ... purtroppo non va neanche quella ... :frowning:

Non da errore, ma da warning perché ... non trova il file da includere ... :frowning: :frowning: :frowning:

Il problema del "#ifdef" in realtà, secondo me, deriva da questo ...

gcc OnLineDocs ... la frase di mezzo :

"Even if a conditional fails, the controlled text inside it is still run through initial transformations and tokenization. Therefore, it must all be lexically valid C."

... che, secondo me, va letto come : "Anche se la condizione è falsa, il testo in essa contenuto (cioè quello che uno mette dentro al #ifdef) viene comunque trattato, per cui deve essere sintatticamente valido per il C."

Chiaramente, la libreria TiniWireM.h contiene cose che in C sono sintatticamente valide se il processore è il ATtiny85, ma non più valide se il processore è un altro e ... li casca l'asino.

Guglielmo

Edit : la cosa è indipendente dalla versione del IDE che si usa e ... anche dalla Toolchain (provato anche con la 3.4.3)

gpb01:
"Even if a conditional fails, the controlled text inside it is still run through initial transformations and tokenization. Therefore, it must all be lexically valid C."

Mi sembra una cosa stupida. Se non la voglio includere c'e' un motivo. Perchè analizzarla comunque?
Un conto è una define per una macro o una costante per debug, ma comunque non mi interessa ne faccia l'analisi.
Alquanto strana come "decisione" del gcc.

nid69ita:
Mi sembra una cosa stupida. Se non la voglio includere c'e' un motivo. Perchè analizzarla comunque?
...

Nid, concordo con te, e purtroppo questa cosa crea dei bei casini che, credo vadano ad aggiungersi a quelli che già crea di perse l'IDE.
Ad esempio ... il fatto che nei "Computed Includes" non trova i files (... perché non sa seguire più le path) ... ho idea che sia qualche cosa introdotto dall' IDE e non da gcc :wink:

Guglielmo

il problema è probabilmente quello che fa l'ide qunado tagliuzza le cose per crare il file main in cpp a partire dall'INO.

Attivate le scritte di debug e controllate in che cartella temporanea compila, entrate nella cartella e cercate il main() (nomesckecth.cpp se ricordo bene) e verificate cosa è successo alle ifdef.

Se sono scomparse, e trovate entrambe le include, alloa aprite un bug (se state usando l'ultima versione di ide, si intende! se no aggiornate)

lesto:
il problema è probabilmente quello che fa l'ide qunado tagliuzza le cose per crare il file main in cpp a partire dall'INO.

NO lesto, questa volta la colpa, se così la vogliamo chiamare (... visto che mi sembra cosa ben documentata) è di gcc ...

Se si mette il "verbose" e si segue quello che fa, all'inizio prende il programma, c'aggiunge qualche cosa ed inizia a creare un primo obj ...

Dato questo :

#ifdef PIPPO
   #include "TinyWireM.h"
#endif

void setup() {}

void loop() {}

... nella directory temporanea lo trovi modificato così :

#line 1 "sketch_jan28a.ino"
#ifdef PIPPO
   #include "TinyWireM.h"
#endif

#include "Arduino.h"

void setup();
void loop();
#line 5
void setup() {}

void loop() {}

... come vedi il "#ifdef" rimane ... :wink:

Guglielmo

Come primissima riga metti un

char foo;

Cosi almeno eviti l'errore dell'IDE già segnalato e non ancora risolto, neanche sulla 1.5.6 in sviluppo.

Non funziona neanche con la mia proposta.
E' un errore del preprocessore dell'IDE. :sweat_smile:

a me

#if defined( __AVR_ATmega328P__ )
   #include "asd1.h"
#else
   #include "asd2.h"
#endif

void setup(){
}

void loop(){
}

funziona, arduino 1.0.5 su windows.

viene comunque trattato

credo che intenda sintatticamente, non che viene elaborato. la #ifdef usata così è normale, ed è usata anche nelle librerie arduino. potrebbe essere che il fatto che Arduino.h sia incluso DOPO sia il problema?

Ho riletto, ma non ho capito qual'è l'intento. Per un compilatore C il preprocessore si limita a includere o meno del codice limitatamente al codice testato con #if, ciò non influisce sulle altre compile unit che se non hanno #if vengono compilate e questo è corretto.

Normalmente quando si ha un sorgente compatibile con più di una libreria si deve creare un configure parametrizzato che permetta di configurare il build per compilare la libreria da cui dipende e per fare la fase di collegamento. Questo è possibile farlo con IDE che offrono strumenti di configurazione esterni che possono essere configurati dal file di progetto.

Nel mio caso con qtcreator ho queste righe nel file di progetto:

INCLUDEPATH += $PWD/../lib/tc
DEPENDPATH += $PWD/../lib/tc
INCLUDEPATH += .

LIBS += -L$OUT_PWD/../lib/tc/ -ltc

Includo il path di ricerca header lib/tc, abilito la dipendenza nei confronti di /lib/tc, includo il path di ricerca header locale, LIBS +=..... mi permette di specificare delle librerie da linkare al codice compilato.
Potrei mettere LIBS +=... in una condizione simile a if elseif che in base al valore di una variabile sceglie cosa linkare, in realtà posso usare strutture condizionali ovunque rendendo il codice configurabile attraverso una o più
variabili o anche una sola, es contains(WhatBuilt, ALL) { } else { contains(WhatBuild, DEMO} ecc.

Mentre credo che l'ide di Arduino abiliti o meno la compilazione di librerie aggiuntive grazie al preprocessore
interno che però non è in grado di fare il lavoro che svolge il preprocessore C++, quindi include la libreria per compilarla e linkarla ma il preprocessore C non include l'header.

Comunque, se il problema c'è di sicuro non riguarda GCC in quanto il comportamento è standard.

Ciao.

MauroTec:
...
Comunque, se il problema c'è di sicuro non riguarda GCC in quanto il comportamento è standard.

Non sembrerebbe Mauro, anche dalla documentazione gnu che ho postato ...

"Even if a conditional fails, the controlled text inside it is still run through initial transformations and tokenization. Therefore, it must all be lexically valid C."

... e difatti è proprio quello che fa ... solo che facendolo, la cosa crea problemi !

Questo è il codice che mi interessa, visto che sto scrivendo del codice che vorrei poter compilare sia per ATtiny85 che per ATmega328p e che usa il protocollo I2C :

#if defined( __AVR_ATtiny85__ )
   #include <TinyWireM.h>
#else
   #include <Wire.h>
#endif

void setup() {

// non ha importanza

}

void loop() {

// non ha importanza

}

... ora provate voi a compilarlo senza errori né warning :wink:

Guglielmo

@Lesto : E non puoi mica girartela come ti pare ... certo che ti funziona, in quel modo non sei grado di produrre l'errore. Usa la libreria e l'include che ho messo io (che su 328p crea errore) e allora vedrai ...

Allora, tanto per dare un po' più di dettagli ...

L'IDE prende il codice sopra scritto, c'aggiunge qualche riga e lo trasforma così (sketch_jan28a.cpp) :

#line 1 "sketch_jan28a.ino"
#if defined( __AVR_ATtiny85__ )
   #include <TinyWireM.h>
#else
   #include <Wire.h>
#endif

#include "Arduino.h"
void setup();
void loop();
#line 7
void setup() {

// non ha importanza

}

void loop() {

// non ha importanza

}

A questo punto lancia avr-g++ ... e salta fuori il problema perché, nonostante la "#if defined" comunque ".... the controlled text inside it is still run through initial transformations and tokenization" :

/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=105 -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/arduino/cores/arduino -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/arduino/variants/standard -I/Users/gpb01/Documents/Arduino/libraries/TinyWireM -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/libraries/Wire /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/build2261937910410504608.tmp/sketch_jan28a.cpp -o /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/build2261937910410504608.tmp/sketch_jan28a.cpp.o 
/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=105 -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/arduino/cores/arduino -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/arduino/variants/standard -I/Users/gpb01/Documents/Arduino/libraries/TinyWireM -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/libraries/Wire -I/Users/gpb01/Documents/Arduino/libraries/TinyWireM/utility /Users/gpb01/Documents/Arduino/libraries/TinyWireM/TinyWireM.cpp -o /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/build2261937910410504608.tmp/TinyWireM/TinyWireM.cpp.o 
/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=105 -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/arduino/cores/arduino -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/hardware/arduino/variants/standard -I/Users/gpb01/Documents/Arduino/libraries/TinyWireM -I/Applications/Arduino 1.0.5.app/Contents/Resources/Java/libraries/Wire -I/Users/gpb01/Documents/Arduino/libraries/TinyWireM/utility /Users/gpb01/Documents/Arduino/libraries/TinyWireM/USI_TWI_Master.cpp -o /var/folders/td/xjbgg2n97rl9wsy40_rsj90h0000gn/T/build2261937910410504608.tmp/TinyWireM/USI_TWI_Master.cpp.o 
/Users/gpb01/Documents/Arduino/libraries/TinyWireM/USI_TWI_Master.cpp:26:2: error: #error Clock frequency non supported
/Users/gpb01/Documents/Arduino/libraries/TinyWireM/USI_TWI_Master.cpp: In function 'void USI_TWI_Master_Initialise()':
....
....

... quindi, darei la colpa proprio a avr-g++ :slight_smile:

Guglielmo

Quando una caratteristica viene confusa per bug, di questo si tratta.

"Even if a conditional fails, the controlled text inside it is still run through initial transformations and tokenization. Therefore, it must all be lexically valid C"

Questo significa che anche se il test fallisce il parser e il tokenizer e quindi il controllo degli errori è attivo e questa è una caratteristica. Diversamente scopriresti di aver scritto includ "stoca> solo quando la ifdef da esito positivo.
Quindi se ci sono errori di scrittura o di altra natura sia che il test dia o meno validità il parser ecc fa il suo lavoro e questo è utile o no.

Il problema che si presenta e proprio quello che ho descritto, cioè il codice sorgente della libreria viene comunque incluso in quanto il preprocessore di Arduino non è in grado di valutare l'espressione #ifdef ....
Ricorda che il preprocessore di arduino viene eseguito sul codice prima che il preprocessore C++ possa operare.

Uso spesso Gcc è ti posso garantire che non si tratta di un bug.

Ciao.

Così?

#if defined( __AVR_ATtiny85__ )
   #include <TinyWireM.h>
#endif

#if defined( __AVR_ATmega328P__ )
   #include <Wire.h>
#endif

void setup() {

// non ha importanza

}

void loop() {

// non ha importanza

}