[résolu] un fichier cpp, 2 compilateurs (g++ et avr-g++)

un fichier cpp, 2 compilateurs (g++ et avr-g++) [résolu] - C++ - Programmation

Marsh Posté le 09-05-2013 à 13:14:11    

Bonjour.
 
À mes heures perdues je programme des microprocesseurs AVR en C++ pour des applications robotiques.
Pour mon dernier projet j'aimerais faire un petit simulateur sur PC en C++ également.
 
Comme ces 2 programmes sont écrits en C++, il y a beaucoup de code qui est un commun pour la puce est pour le simulateur.
 
Je voudrais donc compiler le programme destiné au microprocesseur 2 fois, avec 2 compilateurs différents :
- une fois pour la puce avec avr-g++
- une fois pour le simulateur avec g++
 
Il y aurait donc une partie du code qui est commune, qui appelle des fonctions destinées soit à g++ soit à avr-g++.
Exemple de 'code' qui permet de faire clignoter une led (pour simplifier je ne traite pas les pauses) :
 

Code :
  1. // partie commune
  2. for(int i=0 ; i<10 ; i++) {
  3.    led_on();
  4.    led_off();
  5. }
  6. // code pour la puce :  
  7. void led_on() {digitalWrite(13, HIGH);}
  8. void led_off() {digitalWrite(13, LOW);}
  9. // code pour le simu :  
  10. void led_on() {/*on dessine un rond rouge dans l'interface graphique*/}
  11. void led_off() {/*on efface le rond rouge*/}


 
Le compilo 'choisirait' ensuite la fonction qui lui convient.
 
Je ne sais pas trop comment m'y prendre...
 
Nathanaël

Message cité 1 fois
Message édité par natha31 le 12-05-2013 à 20:33:23
Reply

Marsh Posté le 09-05-2013 à 13:14:11   

Reply

Marsh Posté le 09-05-2013 à 13:42:52    

natha31 a écrit :

Bonjour.
 
À mes heures perdues je programme des microprocesseurs AVR en C++ pour des applications robotiques.
Pour mon dernier projet j'aimerais faire un petit simulateur sur PC en C++ également.
 
Comme ces 2 programmes sont écrits en C++, il y a beaucoup de code qui est un commun pour la puce est pour le simulateur.
 
Je voudrais donc compiler le programme destiné au microprocesseur 2 fois, avec 2 compilateurs différents :
- une fois pour la puce avec avr-g++
- une fois pour le simulateur avec g++
 
Il y aurait donc une partie du code qui est commune, qui appelle des fonctions destinées soit à g++ soit à avr-g++.
Exemple de 'code' qui permet de faire clignoter une led (pour simplifier je ne traite pas les pauses) :
 

Code :
  1. // partie commune
  2. for(int i=0 ; i<10 ; i++) {
  3.    led_on();
  4.    led_off();
  5. }
  6. // code pour la puce :  
  7. void led_on() {digitalWrite(13, HIGH);}
  8. void led_off() {digitalWrite(13, LOW);}
  9. // code pour le simu :  
  10. void led_on() {/*on dessine un rond rouge dans l'interface graphique*/}
  11. void led_off() {/*on efface le rond rouge*/}


 
Le compilo 'choisirait' ensuite la fonction qui lui convient.
 
Je ne sais pas trop comment m'y prendre...
 
Nathanaël


 
 
Bonjour !
 
Pour faire propre, je vous propose deux possibilités, qui correspondent à ce que l'on rencontre le plus souvent :  
 
* Des directives de précompilation  
 

Code :
  1. // partie commune
  2. for(int i=0 ; i<10 ; i++) {
  3.    led_on();
  4.    led_off();
  5. }
  6. void led_on()
  7. {
  8. #ifdef SIMULATEUR
  9.   /*on dessine un rond rouge dans l'interface graphique*/
  10. #else
  11.   digitalWrite(13, HIGH);
  12. #endif
  13. }
  14. void led_off()
  15. {
  16. #ifdef SIMULATEUR
  17.   /*on efface le rond rouge*/
  18. #else
  19.   digitalWrite(13, LOW);
  20. #endif
  21. }


 
Et vous compilez la partie g++ avec l'option -DSIMULATEUR
 
* Des fichiers séparés pour les codes spécifiques (ce que fait Qt, par exemple) :  
 
Fichier gestionled.cpp

Code :
  1. // partie commune
  2. for(int i=0 ; i<10 ; i++) {
  3.    led_on();
  4.    led_off();
  5. }


 
 
Fichier gestionled_hard.cpp

Code :
  1. void led_on()
  2. {
  3.   digitalWrite(13, HIGH);
  4. }
  5. void led_off()
  6. {
  7.   digitalWrite(13, LOW);
  8. }


 
Fichier gestionled_simu.cpp

Code :
  1. void led_on()
  2. {
  3.   /*on dessine un rond rouge dans l'interface graphique*/
  4. }
  5. void led_off()
  6. {
  7.   /*on efface le rond rouge*/
  8. }


 
A titre personnel, je préfère la deuxième solution, qui est aussi plus lisible si vous utilisez plusieurs plates-formes en plus du code de simulation, mais c'est une affaire de goût.
 
Bonne continuation !

Reply

Marsh Posté le 09-05-2013 à 16:31:35    

ouah super ! !
Merci merci beaucoup !
 
Pour une solution ou l'autre, je verrais à l'usage.
La 2ème solution me parait en effet plus lisible, mais dans les cas ou la fonction ne fait qu'une ligne par exemple, je préférais la 1ere solution pour éviter d'avoir des fichiers en pagaille.
 
Du coup pour la 2ème solution, je suppose qu'il suffit d'ajouter les fichiers hard ou simu à la compil ?
genre (en simplifiant la commande de compilation) :

Code :
  1. avr-g++ gestionled.cpp gestionled_hard.cpp
  2. g++ gestionled.cpp gestionled_simu.cpp


 
Natha

Reply

Marsh Posté le 09-05-2013 à 16:44:49    

Tout à fait ! Je ne l'ai pas précisé dans mon message précédent, mais c'est bien le cas, la liste des fichiers à compiler dépend alors de la plate-forme.
 
Bon courage !
 
Edit : après réflexion, la deuxième solution me paraît plus intéressante aussi car elle permet de mieux séparer les couches "métier" des couches "drivers", qui attaquent le matériel (ou l'interface du simulateur).


Message édité par Farian le 09-05-2013 à 16:48:14
Reply

Marsh Posté le 09-05-2013 à 23:27:23    

Ok, par conte du coup je ne comprends pas trop comment faire mon #include dans mon gestionled.cpp, vu que le nom change...
 
Est-ce que je peux faire ça ?
 

Code :
  1. #ifdef SIMULATEUR
  2. #include gestionled_simu.h
  3. #else
  4. #include gestionled_hard.h

Reply

Marsh Posté le 10-05-2013 à 00:27:29    

Tout à fait !
 
En revanche, les fonctions et structures d'interface devraient être les mêmes, non ? (Ou alors j'ai raté quelque chose :) ).
 
Les fonctions et structures spécifiques peuvent être déclarées dans des fichiers inclus uniquement par les .cpp spécifiques, cela permet de n'avoir que du commun dans la partie "métier".

Reply

Marsh Posté le 10-05-2013 à 10:47:44    

Citation :

En revanche, les fonctions et structures d'interface devraient être les mêmes, non ?


Pas compris, tu peux détailler ou donner un exemple?
 

Citation :

Les fonctions et structures spécifiques peuvent être déclarées dans des fichiers inclus uniquement par les .cpp spécifiques


Pas compris non plus...

Reply

Marsh Posté le 10-05-2013 à 11:23:37    

Dans l'exemple que vous avez donnée, les fonctions d'interface entre la couche métier et la couche driver sont les mêmes : led_on() et led_off().
 
De la même façon, on pourrait imaginer que les structures (par exemple des paramètres) soient les mêmes aussi, que le programme utilise les drivers matériels ou le simulateur.
 
Pour moi, dans le code commun (métier), on ne doit jamais se poser la question de savoir si on appelle une fonction driver du matériel cible ou celle du simulateur, on appelle simplement une fonction driver dont la signature est la même quel que soit le "matériel" derrière.
 
Donc, partant de là, au niveau du code commun, on n'a pas à avoir de #ifdef SIMULATEUR ou autres choses du genre.
 
En revanche, dans le code spécifique du matériel cible, par exemple, on peut avoir besoin de définir un type de structure partagé entre plusieurs fichiers .cpp du matériel. Ce type de structure serait alors décrit dans un fichier .h spécifique au matériel considéré et inclus uniquement par les .cpp de gestion de ce matériel (marche aussi pour la définition des IHM pour la partie "simulateur", par exemple).
 
J'espère avoir été clair, sinon, ce n'est pas bien grave non plus, cela ne remet pas en cause le principe :)
 
Bonne continuation !

Reply

Marsh Posté le 10-05-2013 à 18:53:09    

Citation :

Pour moi, dans le code commun (métier), on ne doit jamais se poser la question de savoir si on appelle une fonction driver du matériel cible ou celle du simulateur, on appelle simplement une fonction driver dont la signature est la même quel que soit le "matériel" derrière.
 
Donc, partant de là, au niveau du code commun, on n'a pas à avoir de #ifdef SIMULATEUR ou autres choses du genre.


Oui tout à fait, sauf pour le #include comme je disais.
 

Citation :

En revanche, dans le code spécifique du matériel cible, par exemple, on peut avoir besoin de définir un type de structure partagé entre plusieurs fichiers .cpp du matériel. Ce type de structure serait alors décrit dans un fichier .h spécifique au matériel considéré et inclus uniquement par les .cpp de gestion de ce matériel (marche aussi pour la définition des IHM pour la partie "simulateur", par exemple).


 
Ok j'ai compris. Le fichier gestionled_hard.cpp peut appeler par exemple un fichier io.h qui gère les entrées/sorties de la puce, lequel peut éventuelleemnt être appelé par d'autres fichiers (gestioncapteur_hard.cpp, gestionmoteur_hard.cpp, ...)
 
J'aime bien parler par exemples :).

Reply

Marsh Posté le 10-05-2013 à 21:57:52    

C'est exactement ça pour le deuxième point, le fichier "io.h", qui est spécifique au matériel n'est appelé que par des fichiers *_hard.cpp, mais que les codes communs ou du simulateur n'ont pas à utiliser.
 
En revanche, pour le premier, je ne vois pas quelles pourraient être les différences entre gestionled_simu.h et gestionled_hard.h, en tous cas les différences que gestionled.cpp a besoin de connaitre.
 
Mais c'est du pinaillage / de l'intégrisme, je vous l'accorde :)


Message édité par Farian le 10-05-2013 à 21:58:45
Reply

Marsh Posté le 10-05-2013 à 21:57:52   

Reply

Marsh Posté le 12-05-2013 à 04:29:35    

Citation :

En revanche, pour le premier, je ne vois pas quelles pourraient être les différences entre gestionled_simu.h et gestionled_hard.h, en tous cas les différences que gestionled.cpp a besoin de connaitre.


 
En effet, excellente remarque ! :jap:
gestionled_simu.h et gestionled_hard.h sont identiques ce sont les .cpp qui changent.
Du coup pas besoin du #ifdef SIMULATEUR, ce ne sera que le nom du fichier que l'on va changer à la compilation.
 

Citation :

Mais c'est du pinaillage / de l'intégrisme, je vous l'accorde :)


Comme quoi ça peut parfois être utile, ça m'a permis d'avancer dans mon raisonnement.
 
Merci beaucoup Farian en tout cas !

Reply

Marsh Posté le 12-05-2013 à 04:31:59    

Cela me parait plus cohérent comme ça :)
 
Bonne continuation à vous et amusez-vous bien !

Reply

Marsh Posté le 13-05-2013 à 20:48:21    

Juste pour compléter, si tu fais de l'objet tu peux aussi faire ça avec l'héritage :
 

Code :
  1. class BaseGestionLed
  2. {
  3. // ...
  4. void fonctionCommune()
  5. {
  6. // partie commune
  7. for(int i=0 ; i<10 ; i++)
  8. {
  9.    led_on();
  10.    led_off();
  11. }
  12. }
  13. virtual void led_on() = 0;
  14. virtual void led_off() = 0;
  15. // ...
  16. };
  17. class HardGestionLed : public BaseGestionLed
  18. {
  19. // ...
  20. virtual void led_on()
  21. {
  22. digitalWrite(13, HIGH);
  23. }
  24. virtual void led_off()
  25. {
  26. digitalWrite(13, LOW);
  27. }
  28. // ...
  29. };
  30. class SoftGestionLed : public BaseGestionLed
  31. {
  32. // ...
  33. virtual void led_on()
  34. {
  35. /*on dessine un rond rouge dans l'interface graphique*/
  36. }
  37. virtual void led_off()
  38. {
  39. /*on efface le rond rouge*/
  40. }
  41. // ...
  42. };


 
Et tu instancie tes classes avec une Factory. Ca peut être intéressant si ton code est déjà object avec beaucoup de code commun.. Après chacun choisi ce qui est le mieux adapté ^^
 
Après je sais pas comment tu compiles, mais passer par un générateur de Makefile type CMake ou SCons peut te faciliter la tâche pour créer plusieurs targets directement en fonction du compilateur, etc, etc


Message édité par abuzor le 13-05-2013 à 20:53:00
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed