Librairie statique et Préprocesseur
Le
requinham
Bonjour,
je travaille sur deux projets qui ont une grande partie semblable,
cette partie devrais être grouper dans une librairie statique (.lib)
le problème c'est que j'ai fusionné les parties du code en ajoutant
des #ifdef pour sélectionner dans chaque section différente le code
correspondant au projet qui est en cour de compilation. je me suis
trouvé, alors avec des problèmes pour compiler ma librairie statique
vue que je n'est pas défini les valeurs préprocesseur.
ma question est comment pourrais je compiler cette librairie avec tous
les scenarii possible pour en choisir un lors de la compilation du
projet.
bon je donne un petit exemple pour comprendre car c'est facile à
assimiler avec l'exemple.
supposant que j'ai deux projet qui calcule le premier a+b et le
deuxième a-b et ce en choisissant l'opérateur
dans la librairie je voudrai mettre ainsi
#ifdef PRJ1_COMPILATION
operator = '+';
#else
#ifdef PRJ2_COMPILATION
operator = '-';
#endif
#endif
switch (operator)
{
case '+': return a+b;
case '-': return a-b;
}
je voudrais maintenant sans définir ni PRJ1_COMPILATION ni
PRJ2_COMPILATION compiler ma .lib et le choix devrais etre fait à la
compilation des projets ?
Merci
je travaille sur deux projets qui ont une grande partie semblable,
cette partie devrais être grouper dans une librairie statique (.lib)
le problème c'est que j'ai fusionné les parties du code en ajoutant
des #ifdef pour sélectionner dans chaque section différente le code
correspondant au projet qui est en cour de compilation. je me suis
trouvé, alors avec des problèmes pour compiler ma librairie statique
vue que je n'est pas défini les valeurs préprocesseur.
ma question est comment pourrais je compiler cette librairie avec tous
les scenarii possible pour en choisir un lors de la compilation du
projet.
bon je donne un petit exemple pour comprendre car c'est facile à
assimiler avec l'exemple.
supposant que j'ai deux projet qui calcule le premier a+b et le
deuxième a-b et ce en choisissant l'opérateur
dans la librairie je voudrai mettre ainsi
#ifdef PRJ1_COMPILATION
operator = '+';
#else
#ifdef PRJ2_COMPILATION
operator = '-';
#endif
#endif
switch (operator)
{
case '+': return a+b;
case '-': return a-b;
}
je voudrais maintenant sans définir ni PRJ1_COMPILATION ni
PRJ2_COMPILATION compiler ma .lib et le choix devrais etre fait à la
compilation des projets ?
Merci

Poser une question


Tu dois faire passer ton operator en paramètre de ta fonction, ou en
variable globale (eventuellement privée avec une fonction set_operator()
publique). Ensuite tu positionne va var globale directement ou avec la
fonction d'init, c'est selon:
extern char operator;
/* ou mieux à mon sens
static char operator = '+'; // valeur par defaut
int init_prj(char operator2) {
operator = operator2;
}
*/
int foo(int a, int b) {
switch(operator) {
case '+': return a+b;
case '-': return a-b;
default: /* erreur */
}
}
En fait: je dis la variable "operator", mais peut être qu'une struct
globale représentant les "settings" variables entre projets serait mieux.
L'idée est donc de ne plus utiliser le macro-processeur, mais de faire
des tests sur PRJ1/PRJ2 ou d'autres params: tu passes en API tes params
issues du preprocesseur.
sam.
Normalement, jusque là c'est facile : tu compiles deux fois, une fois
pour chaque projet, et tu rassembles le résultat dans la bibliothèque ;
seule difficulté, comment sélectionne-t-on le « bon » module ?
Le problème, c'est que c'était avec uniquement les explications
ci-dessus, sans tenir compte de ce qui suit...
Explicite ce que tu entends par « choisir l'opérateur », parce que ce
n'est pas clair : je vois de multiples manière de faire cela, depuis
#define/-D jusqu'à COM en passant par les bibliothèques dynamiques.
Ça ne peut pas marcher, tu as un conflit gigantesque qui est
fondamentalement que C est un langage compilé, donc la fabrication de la
bibliothèque vient *après* la compilation de chaque module, qui
*dépendent* elles-mêmes des définitions du préprocesseur ;
si tu veux utiliser les définitions comme moyen d'action, tu te places
donc en amont du processus (autrement dit tu forces celui qui choisis
ces variables à recompiler tout ce qui en dépend).
Une bibliothèque n'est pas une fin en soi, c'est un outil pour la
compilation structurée (en petits morceaux, de plusieurs projets) ; si
la construction de la bibliothèque intervient _après_ la construction
complète des programmes, la bibliothèque n'a strictement aucun intérêt.
La manière « normale » (mais déjà passablement laide) de traiter cela
avec des #ifdef ressemble plutôt à
#ifdef PRJ1_COMPILATION
#define operateur +
#elif defined PRJ2_COMPILATION
#define operateur -
#else
#error on ne sait pas quel projet est traité !
#endif
{
return a operateur b;
}
Ce qui donne deux morceaux de code qui font bien ce que tu veux, d'un
côté une addition de l'autre une soustraction. Mais c'est très laid !
Comme dit plus haut, le souci c'est de savoir comment choisir l'un ou
l'autre.
En C, les objets d'une bibliothèque sont atteignables par leurs noms
(pas par leurs types ou je-ne-sais-quoi) et que par conséquent ce doit
être soit des fonctions (le plus courant) soit des variables globales.
La méthode logique est de supprimer totalement ce code « variant » de la
bibliothèque pour le garder en dehors ; et dans la bibliothèque, on le
remplace par des appels indirects ; supposons que la bibliothèque au
sein de la quelle tu as le code variable définisse deux actions, genre
/* Biblio.h */
action1(typeparamA, typeparamB);
action2(typeparamA, typeparamB, typeparamB);
Tu vas transformer ta bibliothèque pour ressembler à
/* Biblio.h */
typedef /*...*/ type_opér;
typedef type_opér (*p_opération)(type_opér, type_opér);
action1(typeparamA, typeparamB, p_opération);
action2(typeparamA, typeparamB, typeparamB, p_opération);
Au niveau des projets, tu auras alors d'un côté :
/* PRJ1 */
type_opér opération(type_opér a, type_opér b)
{
return a+b;
}
action1(param1, param2, &opération);
et de l'autre
/* PRJ2 */
type_opér opération(type_opér a, type_opér b)
{
return a-b;
}
action1(param1, param2, &opération);
action2(param1, param2, param3, &opération);
NB : le fait que les deux fonctions « opération » aient le même nom n'a
rien d'obligatoire.
Et dans le code de la bibliothèque, tu remplaces tout le code avec des
#ifdef par
action1(typeparamA a, typeparamB b, p_opération p_opér);
/* ... */
return (*p_opér)(a,b);
}
On peut aller encore plus loin et garder le switch que tu avais
ci-dessus, et faire alors dépendre à l'exécution la fonction qui est
passée comme paramètre, un truc du genre
switch( je_ne_sais_quoi ) {
case PRJ1:
action1(param1_a, param2, &opération_prj1);
break;
case PRJ2:
action1(param1_b, param2, &opération_prj2);
action1(param1_b, param2, param3, &opération_prj2);
break;
}
Et pas l'ombre d'un #ifdef à l'horizon !
Du côté de la bibliothèque, tu peux étoffer le concept des opérations
élémentaires, et tu définis alors des types abstraits : c'est la base
d'un large pan de la programmation actuelle, les composants.
Antoine
Pourquoi ne pas faire deux bibliothèques et choisir la bonne
bibliothèque à l'édition des liens ?
--
Richard
Merci pour ta réponse, cependant j'ai penser à trouver une solution
qui pourra écarter l'éventualité de deux lib séparées car je voud rai
bien avoir une seule sinon j'ai rien fait car je parlerai plus de
partie commune...
ce que j'avais ecrit comme exemple est un bout de code trivial que
j'ai inventé en écrivant le problème afin de faciliter la
compréhension car si tu veux bien on pourra dire que mon probleme est
de compiler une librairie statique avec deux symbole préprocesseur qui
ne sont pas définie ie qui vont être définie par la suite car c'est ça
l'utilité de la libririe statique garder un ensemble de code
précompiler et l'inclure en utilisant les header. je me demande alors
comment fond dans les sources de bcoup de programmes dans lesquels on
nous livre des .lib avec des fichiers d'entete dans lesquelle on
trouve definition de plusieurs symbole comme notre cas et qu'on peux
compiler toujours peux importe les symbole définis comme les sources
de windows :
#if defined (WIN32)
...
#elif defined (WINCE)
...
#endif
pourtant on a une seule lib livré. bref du coup j'ai pensé qu'il y a
qque détails qui m'échappe.
Tu es sûr que les bibliothèques sont les mêmes sur les PDA utilisant
WINCE et les PC utilisant WIN32 ?
J'ai des programmes avec du code comme ça :
#if defined (__linux__)
...
#elif defined (__APPLE__)
...
#elif define (_WIN32)
...
#endif
Et les bibliothèques livrés sous ces différents OS ne sont, bien
évidemment, pas les mêmes.
--
Richard