Go Down

Topic: Recette de cuisine pour la compilation séparée (Read 262 times) previous topic - next topic

MicroQuettas

Bonjour à toutes et à tous,

Comme toutes celles et ceux qui se sont lancés dans le découpage "propre" d'un programme en modules fonctionnels avec chacun un fichier .h et un .cpp, j'ai rencontré certaines difficultés... pour ne pas dire des difficultés certaines...
J'ai fini par y arriver et me suis écrit une petite recette de cuisine que j'applique depuis pour y parvenir sans (trop de) peine.

Devant le nombre de posts sur le sujet, j'ai mis à jour la dite recette et vous la propose ci-jointe, en espérant qu'elle soit utile à certains.

C'est une recette de cuisine et en tant que telle elle peut (doit) être améliorée. C'est pour cela que je publie le code source du document.

Il y a aussi un exemple qui illustre la recette, inclus zippé dans le présent post et entre balises dans le suivant.

Tous les commentaires et suggestions d'améliorations sont les bienvenues.

Bonnes bidouille,

MicroQuettas

MicroQuettas

Et maintenant, le code de l'exemple...

1- Le fichier CompMod_00a.ino :

Code: [Select]

/**********************************************************************
                Exemple de compilation modulaire
               
************************* Marqueur ***********************************/
#define _PointIno_ true

//#include <pgmspace.h>  /* Pour ESP8266 */

#include "Module_1.h"

/*********************** defines and const **************************/
#define C_MaxBf 48    /* Taille du tampon */

/*********************** Variable globale ***************************/
char G_Bf[C_MaxBf];

/*******************************************************************/

void setup()
  {
  // put your setup code here, to run once:

  /* Initialise serial link */
  Serial.begin(9600);

  delay(1000);

  Serial.println(F("\r\nBonjour\r\n"));

  Prep_1();
  Serial.println(G_Bf);

  Prep_2();
  Serial.println(G_Bf);

  Serial.println(F("\r\nAu revoir"));

  }

void loop()
  {
  // put your main code here, to run repeatedly:

  /* Reste vide puisque tout a été fait dans le setup() */
 
  }

 


2- Le fichier Glovar.h

Code: [Select]

/**********************************************************************
                Exemple de compilation modulaire
               
************************* Marqueur ***********************************/
#ifndef _GloVar_
#define _GloVar_ true

/*********** Variable globale accessible à d'autres modules **********/
#ifndef _PointIno_
extern char G_Bf[];    /* C'est une déclaration, surtout pas de
                        * dimension */
#endif

/************************** End of code ******************************/
#endif  /* _GloVar_ */


3- Le fichier Module_1.h

Code: [Select]

/**********************************************************************
                Exemple de compilation modulaire

************************* Marqueur ***********************************/
#ifndef _Module1_
#define _Module1_ true

/*************************** Protypes ********************************/
void Prep_1();
void Prep_2();

/************************** End of code ******************************/
#endif  /* _Module1_ */


4- Le fichier Module_1.cpp

Code: [Select]

/**********************************************************************
                Exemple de compilation modulaire

************************* Marqueur ***********************************/
#define _Module1_CPP_ true


#include <Arduino.h>
//#include <pgmspace.h>    /* Pour ESP8266 */

#include "GloVar.h"
#include "Module_2.h"

#include "Module_1.h"

/************************** Fonctions ********************************/
void Prep_1()
  {
  strcpy_P(G_Bf, G_Str1);  /* G_Bf est définie dans le .ino
                            * G_Str1 est définie dans Module_2 */
  }

void Prep_2()
  {
  Prep_3();       /* Prep_3 est dans Module_2 */
  }

/************************** End of code ******************************/


5- Le fichier Module_2.h

Code: [Select]

/**********************************************************************
                Exemple de compilation modulaire

************************* Marqueur ***********************************/
#ifndef _Module2_
#define _Module2_ true

/*********** Variable globale accessible à d'autres modules **********/
#ifndef _Module2_CPP_
extern char* G_Str1;
#endif

/*************************** Prototypes ******************************/
void Prep_3();

/************************** End of code ******************************/
#endif  /* _Module2_ */


5- Le fichier Module_2.cpp

Code: [Select]

/**********************************************************************
                Exemple de compilation modulaire

************************* Marqueur ***********************************/
#define _Module2_CPP_ true

#include <Arduino.h>
//#include <pgmspace.h>     /* Pour ESP8266 */

#include "GloVar.h"

#include "Module_2.h"

/******************** Données en progmem ****************************/
const char P_Str1[] PROGMEM = \
  "Les sanglots longs de l'automne";
const char P_Str2[] PROGMEM = \
  "bercent mon coeur d'une langueur monotone";
/* 01234567890123456789012345678901234567890
   0         1         2         3         4   42 char avec le \0 */

/********** Variable globale permettant l'accès au progmem **********/
char* G_Str1 = (char*) P_Str1; /* Conversion explicite de type
                                * (cast) pour éviter un warning
                                * à la compilation, depuis un tableau
                                * de const char
                                * vers un pointeur sur char
                                */

/*************************** Fonctions ******************************/
void Prep_3()
  {
  strcpy_P(G_Bf, P_Str2);   /* G_Bf est définie dans le .ino */
  }

/************************** End of code ******************************/


Et voilà, c'est simple, mais cela montre les possibilités, qui sont vraiment intéressantes en termes de clarté, modularité et surtout réemploi.

Bonne bidouille...

MicroQuettas

hbachetti

Apparemment dans ce topic : organisation clair d'un code , une solution alternative a été trouvée.

Il est apparemment possible avec l'IDE ARDUINO de travailler sur un projet plusieurs fichiers .ino tout en se passant de fichiers .h et de fichiers .cpp
Il n'y a aucun prototype de fonction, ni de déclaration "extern" nulle part.

Sincèrement je ne savais même pas que c'était possible.

C'est une solution assez peu classique, et certainement liée très fortement à l'IDE ARDUINO.

J'ai essayé d'importer les sources dans VSCode et donc PlatformIO :

Code: [Select]
2_setup.ino:9:3: error: 'stepper1' was not declared in this scope

Cela veut clairement dire qu'en dehors de l'IDE ARDUINO cette solution ne marche pas.

On ne parlera même pas d'essayer avec d'autres environnements C / C++, ou un Makefile, pas la peine de rêver.

Autre inconvénient de cette manière de travailler :
Comment fait-on si l'on veut extraire d'un tel projet un ou plusieurs fichiers source pour les transformer en librairie ?
Il va bien falloir renommer le .ino en .cpp et créer un .h ?
Alors pourquoi ne pas le faire dès le départ ?

Je veux bien admettre que cette manière de travailler convienne à un débutant qui ne comprend pas les principes de base du C, mais je déconseille fortement cette méthode à toute personne un tant soit peu motivée pour apprendre l'art et la manière de développer correctement en C / C++.

Cet avis n'engage que moi bien entendu.

Cordialement
Henri
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

hbachetti

#3
Jun 09, 2019, 08:23 am Last Edit: Jun 10, 2019, 12:17 am by hbachetti
Autre remarque :

Avec PlatformIO, le fichier source principal s'appelle main.cpp à la création du projet, et on peut le renommer sans problème :

Code: [Select]

#include <Arduino.h>

void setup() {
  // put your setup code here, to run once:
}

void loop() {
  // put your main code here, to run repeatedly:
}


Comme on peut le voir cela oblige à inclure Arduino.h (ce que PlatformIo fait automatiquement).

Est-ce un inconvénient ?
Non, tout au plus une manière normale de travailler en C.

Avec PlatformIO Il n'y a pas non plus d'obligation de nommage du style "Le répertoire doit porter le même nom que le sketch". Cette obligation est à mon sens d'une débilité profonde (tout comme l'extension .ino d'ailleurs) et aurait pu disparaître depuis longtemps sans gêner personne ...
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

Go Up