IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Organisation des sources pour du multiplateforme


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 90
    Par défaut Organisation des sources pour du multiplateforme
    Bonjour à tous,

    Je ne savais pas vraiment où poster cela, cela relève plus de comment (ré)organiser (ou pas) un projet qui va un peu grossir. Peut-etre qu'il n'y a pas de solutions ^^
    J'ai développé un programme pour AVR avec 4 librairies, des fichiers de configuration ou de définition, répartie dans différents repertoires et sous répertoires (cela n'a peut etre pas beaucoup d'importances).

    Actuellement, le programme supporte l'attiny85, l'attiny84 et l'AT Mega 168/328. Pour les parties spécifiques, j'utilise les options du precompileur à savoir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #if defined(__AVR_ATtiny85__)
    [...]
    #elif defined(__AVR_ATtiny84__)
    [...]
    #elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
    J'ai ces "#if defined" dans un peu tous les fichiers à chaque fois qu'une partie est spécifique à tel ou tel AVR. Pour l'instant c'est encore à peu pret lisible même si je trouve que la multicompatibilité devient un peu lourd.

    Là, je veux porter mon programme pour STM32 et cela devient un peu la merde ^^ Car si entre les AVR il y a beaucoup de points commun, pour le STM32 du peu que j'ai lu, il a ses propres caractéristiques. Si je prends la lecture interne de la tension, j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    uint16_t hwCPUVoltage(void)
        {
     
            // Measure Vcc against 1.1V Vref
        #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
            ADMUX = (_BV(MUX5) | _BV(MUX0));
        #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
            ADMUX = (_BV(MUX3) | _BV(MUX2));
        #else
            ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
        #endif
     
            delay(20);
     
            // Do conversion
            ADCSRA |= _BV(ADSC);  
            while (bit_is_set(ADCSRA,ADSC)) {}; 
     
            uint16_t Vcc = (1126400UL) / ADC;   //1.1V*1024
            powerADC(false);
     
            return Vcc;
        };
    Cela devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    uint16_t hwCPUVoltage(void)
        {
    #if defined(__AVR__)
            // Measure Vcc against 1.1V Vref
        #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
            ADMUX = (_BV(MUX5) | _BV(MUX0));
        #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
            ADMUX = (_BV(MUX3) | _BV(MUX2));
        #else
            ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
        #endif
     
            delay(20);
     
            // Do conversion
            ADCSRA |= _BV(ADSC);  
            while (bit_is_set(ADCSRA,ADSC)) {}; 
     
            uint16_t Vcc = (1126400UL) / ADC;   //1.1V*1024
            powerADC(false);
    #elif defined(__STM32__)
     
    [...]
    Code spécifique STM32
    [...]
    #endif
            return Vcc;
        };
    Et heu, là c'est un exemple simple sur quelques lignes, mais sur certaines librairies, j'ai quasiment tout à réécrire pour le passage en STM32 (entre autres l'utilisation des GPIO via les registres). Mon problème c'est que cela nuit pas mal à la lisibilité du code en rajoutant beaucoup de lignes "pour rien".
    Ma question est donc : est-ce qu'il y a un moyen d'organiser tout cela pour que cela soit plus claire ? (j'ai un petit écran, cela parait con mais je ne peux afficher que 38 lignes), soit en exportant des morceaux de conditions (mais quid de l'organisation des fichiers ?) soit en ... ?

    Je ne sais pas si je suis très clair

    Question annexe, j'ai 2 fichiers, un de conf et un avec que des #define que j'utilise sur ce projet mais également un autre. Est-ce qu'il y a un moyen avec GIT de faire correspondre les deux pour avoir un suivi ?
    En gros, projet1 et projet2 sont sur GITHUB, mais si j'update dans projet1, cela n'update pas dans projet2 (il faudrait comme un ln sous linux)

    Merci, si ce n'est pas claire, je peux préciser sans problème.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 129
    Billets dans le blog
    149
    Par défaut
    Bonjour,

    Pour le premier problème (je n'ai pas la réponse pour le second), la solution sera de non pas mettre des #ifdef partout, mais d'avoir un fichier par plateforme. L'idée est d'obtenir un projet comme suit:
    • un fichier .h, indiquant les signatures des fonctions (non dépendant de la plateforme). Dans votre cas, il pourrait s'appeler voltage.h et contenir la signature uint16_t hwCPUVoltage(void);.
    • un fichier .cpp par plateforme, contenant la définition de hwCPUVoltage. Le fichier s'appelera surement voltage_attiny.cpp et un autre voltage_stm32.cpp.

    Ensuite, c'est au niveau de votre système de compilation (CMake/Makefile) de dire à GCC : OK, aujourd'hui, on compile du STM32, donc tu prendra le fichier voltage_stm32.cpp pour compiler.
    Du point de vue du reste du programme, vous n'avez qu'à inclure voltage.h, et ça marche.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Je soutiens cette direction. J'ajouterai qu'éventuellement, ca peut aider d'avoir un dossier de fichiers d'implémentation par architecture, si le cas se présente sur beaucoup de fichiers.

    Par exemple:
    • include/project/*.h
    • src/common/main.c
    • src/attiny/shared/code.c
    • src/attiny/85/voltage.c
    • src/attiny/84/voltage.c
    • src/atmega/shared/code.c
    • src/atmega/168/voltage.c
    • src/atmega/328/voltage.c
    • src/stm32/voltage.c


    Comme ca, les instructions de compilations ressembleront (en beaucoup moins sale) à gcc -Iinclude src/common/*.c src/attiny/shared/*.c src/attiny/84/*.c -o program-attiny84.

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 90
    Par défaut
    Bonjour,

    Merci de vos réponses. De ce que je comprends, c'est de faire l'inverse de ce que je fais actuellement. L'idée de faire un rep par architecture est intelligent, il faut juste que je revois tout mais c'est pas le plus long.
    Pour la commande gcc, je ne crois pas avoir le controle avec l'IDE arduino, mais cela se feinte au pire.

    Si je comprends bien, pour etre sur

    Actuellement, j'ai un répertoire comme suit :
    1. mon_objet.h
    2. dautresfichiers




    Dans "mon_objet.h", j'ai :
    1. Func1 (générique)
    2. Func2 (générique)
    3. Func_Voltage (spécifique)


    Cela deviendrait pour l'architecture:
    1. mon_objet.h
    2. src\Func_voltage_global.h
    3. src\AVR\attiny\Func_voltage.h
    4. src\AVR\Nano\Func_voltage.h
    5. src\STM32\Func_voltage.h
    6. dautresfichiers


    Dans mon_objet.h cela devient (avec #define ARCHI "STM32" en amont) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    [...]
     
    #include src\Func_voltage_global.h
     
    [...]
    Dans Func_voltage_global.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    uint16_t hwCPUVoltage(void)
        {
     
    #include "src\ARCHI\voltage.h"
     
            return Vcc;
        };

  5. #5
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Non, pas vraiment.
    À commencer parce que visiblement, tu n'as pas bien compris la notion de fichier d'en-tête (ou "header").

    Il y a quelques mécaniques importantes qui entre en jeu.
    Premièrement, un #include agit exactement comme un copier-coller (récursif), AVANT la compilation a proprement parler: à la phase de préprocesseur. C'est à dire à la phase de manipulation du code source.

    Une fois cela fait, tout se passe comme si tu avais écrit des fichiers .c autonomes.

    Deuxièmement, il y a la règle de la définition unique (ODR: One Definition Rule): toute chose ne peut être définie qu'une seule fois. Et ce, sur l'ensemble d'un programme.
    Il ne peut pas y avoir deux définitions de la même fonction, sous peine de recevoir le chatiment mérité: "line X, redefinition of the function bidule(). line Y: previous definition here." (dans le même fichier) ou "link error: multiple definitions of bidule()." (dans des fichiers différents).

    Enfin toute utilisation d'une chose (fonction, structure, variable) requiert qu'elle ait été déclarée auparavant.

    Pour éviter les erreurs, si je veux utiliser la fonction utilitaire() dans fichier_a.c et fichier_b.c, il faut absoluement que cette fonction soit déclarée dans les deux, avant leurs utilisations respective, et de la même manière.

    La meilleure solution consiste a dupliquer la déclaration. Avant le préprocesseur (car il y a bien eu un avant), on copiait la déclaration dans les deux fichiers. Depuis (et ca date), on l'écrit dans un fichier intermédiaire, qu'on inclue dans les deux: le copier-coller est automatisé, donc les deux copies sont nécessairement identiques.
    Par convention, ces fichiers intermédiaires sont appelés en-tête, et nommé .h, car ils sont utilisés en en-tête des fichiers de source. Dans l'absolu, ils pourraient s'appeler n'importe comment.

    Cependant, en vertu de l'ODR, il faut absoluement que les fichiers inclus ne contiennent que des déclarations. (dans l'absolu, si le fichier risque d'être inclus plusieurs fois, mais il ne faut jamais compter dessus)

    Dans func_voltage.h, tu déclares la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     #include <stdint.h>
    uint16_t hwCPUVoltage(void);

    La version actuelle de ton implémentation est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    uint16_t hwCPUVoltage(void)
    {
    #if defined(__AVR__)
            // Measure Vcc against 1.1V Vref
        #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
            ADMUX = (_BV(MUX5) | _BV(MUX0));
        #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
            ADMUX = (_BV(MUX3) | _BV(MUX2));
        #else
            ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
        #endif
     
            delay(20);
     
            // Do conversion
            ADCSRA |= _BV(ADSC);  
            while (bit_is_set(ADCSRA,ADSC)) {}; 
     
            uint16_t Vcc = (1126400UL) / ADC;   //1.1V*1024
            powerADC(false);
    #elif defined(__STM32__)
     
    [...]
    Code spécifique STM32
    [...]
    #endif
            return Vcc;
        };
    Que tu aurais aussi pu présenter d'une autre façon:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    #if defined(__AVR__)
    uint16_t hwCPUVoltage(void)
    {
            // Measure Vcc against 1.1V Vref
        #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
            ADMUX = (_BV(MUX5) | _BV(MUX0));
        #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
            ADMUX = (_BV(MUX3) | _BV(MUX2));
        #else
            ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
        #endif
     
            delay(20);
     
            // Do conversion
            ADCSRA |= _BV(ADSC);  
            while (bit_is_set(ADCSRA,ADSC)) {}; 
     
            uint16_t Vcc = (1126400UL) / ADC;   //1.1V*1024
            powerADC(false);
     
    [...]
    Code spécifique STM32
    [...]
            return Vcc;
        };
     
    #elif defined(__STM32__)
     
    uint16_t hwCPUVoltage(void)
    {
            // Measure Vcc against 1.1V Vref
        #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
            ADMUX = (_BV(MUX5) | _BV(MUX0));
        #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
            ADMUX = (_BV(MUX3) | _BV(MUX2));
        #else
            ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
        #endif
     
            delay(20);
     
            // Do conversion
            ADCSRA |= _BV(ADSC);  
            while (bit_is_set(ADCSRA,ADSC)) {}; 
     
            uint16_t Vcc = (1126400UL) / ADC;   //1.1V*1024
            powerADC(false);
     
    [...]
            // Code spécifique STM32
    [...]
            return Vcc;
        };
    #endif
    Et ce que nous t'avons proposé, c'est de répartir cette seconde façon dans deux fichiers:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include "func_voltage.h"
     
    #ifndef __AVR__
    #error("this source file is for AVR")
    #endif
     
    uint16_t hwCPUVoltage(void)
    {
            // Measure Vcc against 1.1V Vref
        #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
            ADMUX = (_BV(MUX5) | _BV(MUX0));
        #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
            ADMUX = (_BV(MUX3) | _BV(MUX2));
        #else
            ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
        #endif
     
            delay(20);
     
            // Do conversion
            ADCSRA |= _BV(ADSC);  
            while (bit_is_set(ADCSRA,ADSC)) {}; 
     
            uint16_t Vcc = (1126400UL) / ADC;   //1.1V*1024
            powerADC(false);
            return Vcc;
        };
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #include "func_voltage.h"
     
    #ifndef __STM32__
    #error("this source file is for STM32")
    #endif
     
    uint16_t hwCPUVoltage(void)
    {
        // Code spécifique STM32
        return Vcc;
    };

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    90
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 90
    Par défaut
    Citation Envoyé par ternel Voir le message
    Non, pas vraiment.
    À commencer parce que visiblement, tu n'as pas bien compris la notion de fichier d'en-tête (ou "header").
    Effectivement, j'ai oublié de préciser qu'il y a quelques "problèmes" historiques de conception. A la base j'avais commencé mon projet via l'IDE arduino et j'avais un problème de compilation de mes librairies (je ne sais plus exactement quoi, mais le process de base ne me convenait pas). Donc pour continuer à utiliser l'IDE arduino et biaiser les options de compilations, j'ai utilisé des .h qui ne sont pas des vraiment des headers, mais pas vraiment non plus des .c.
    Forcément le projet à grossi, ce qui fait que je suis passé à VSCode, mais j'ai toujours l'IDE arduino pour la compilation. Donc je me tape toujours l'ancienne archi de compilation. Il faudrait que je passe tout sous VSCode/plateformeIO pour avoir le controle des commandes de gcc et refaire tout proprement.

    C'est plus ou moins en cours

    Merci pour les réponses, j'ai commencé à travailler dessus. Effectivement, je ne sais pas pourquoi j'ai mis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    uint16_t hwCPUVoltage(void)
        {
     
    #include "src\ARCHI\voltage.h"
     
            return Vcc;
        };
    Alors que j'ai fait ta version dans mes modifications

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. récupération des sources pour compilation manuelle
    Par piotrr dans le forum NetBeans
    Réponses: 12
    Dernier message: 01/03/2008, 08h59
  2. Besoin des sources pour apt-get update ?
    Par byloute dans le forum Debian
    Réponses: 1
    Dernier message: 06/11/2006, 11h25
  3. Réponses: 5
    Dernier message: 13/10/2006, 16h22
  4. [Struts][Module] : Organisation des sources
    Par anaon dans le forum Struts 1
    Réponses: 5
    Dernier message: 27/04/2006, 15h07
  5. [Conception] - Organisation des pages pour une requete.
    Par ShinJava dans le forum PHP & Base de données
    Réponses: 14
    Dernier message: 24/10/2005, 15h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo