Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Librairie statique et Préprocesseur

8 réponses
Avatar
requinham
Bonjour,

je travaille sur deux projets qui ont une grande partie semblable,
cette partie devrais =EAtre grouper dans une librairie statique (.lib)
le probl=E8me c'est que j'ai fusionn=E9 les parties du code en ajoutant
des #ifdef pour s=E9lectionner dans chaque section diff=E9rente le code
correspondant au projet qui est en cour de compilation. je me suis
trouv=E9, alors avec des probl=E8mes pour compiler ma librairie statique
vue que je n'est pas d=E9fini les valeurs pr=E9processeur.

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 =E0
assimiler avec l'exemple.

supposant que j'ai deux projet qui calcule le premier a+b et le
deuxi=E8me a-b et ce en choisissant l'op=E9rateur
dans la librairie je voudrai mettre ainsi

#ifdef PRJ1_COMPILATION
operator =3D '+';
#else
#ifdef PRJ2_COMPILATION
operator =3D '-';
#endif
#endif
switch (operator)
{
case '+': return a+b;
case '-': return a-b;
}


je voudrais maintenant sans d=E9finir ni PRJ1_COMPILATION ni
PRJ2_COMPILATION compiler ma .lib et le choix devrais etre fait =E0 la
compilation des projets ?

Merci

8 réponses

Avatar
Samuel DEVULDER
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 ?



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.
Avatar
Antoine Leca
requinham écrivit :
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.



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...

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



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.

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;
}



Ç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).

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 ?



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
Avatar
Richard
Le 12/05/2010 15:53, requinham a écrit :

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 ?



Pourquoi ne pas faire deux bibliothèques et choisir la bonne
bibliothèque à l'édition des liens ?

--
Richard
Avatar
requinham
On 12 mai, 17:59, Antoine Leca wrote:
requinham écrivit :

> 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.

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...

> 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

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.

> 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;
> }

Ça ne peut pas marcher, tu as un conflit gigantesque qui est
fondamentalement que C est un langage compilé, donc la fabrication de l a
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).

> 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 ?

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 traite r 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 l e
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 n om 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 es t
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ér ations
élémentaires, et tu définis alors des types abstraits : c'est la ba se
d'un large pan de la programmation actuelle, les composants.

Antoine



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.
Avatar
Richard
Le 12/05/2010 23:09, requinham a écrit :


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 voudrai
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
Avatar
requinham
On 12 mai, 23:42, Richard wrote:
Le 12/05/2010 23:09, requinham a écrit :





> 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 voudrai
> 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 qu i
> ne sont pas définie ie qui vont être définie par la suite car c'e st ç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 utilisan t
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



Eventuellement ce ne sont pas les meme car comme vous me l'avez
expliqué, ça n'a pas de sens mais il y a une autre solution qui m'a
été proposée c'est d'envisager une autre approche: celle de créer
réellement deux fonctions, et de choisir celle qui correspond grâce
aux symboles préprocesseurs:

int function_prj1(int a, int b)
{
return a +b;
}
int function_prj2(int a, int b)
{
return a-b;
}
#if defined (PRJ1_COMPILATION)
#define function(x, y) function_prj1(x,y)
#elif defined (PRJ2_COMPILATION)
#define function(x, y) function_prj2(x,y)
#endif


qui sera, simplement, utilisé sous la forme de
Code :

void foo()
{
/*...*/
int result=function(5,9);
}
Avatar
Antoine Leca
requinham écrivit :
mon probleme est de compiler une librairie statique
avec deux symbole préprocesseur qui ne sont pas définie



C'est bien cela que je ne comprend absolument pas.

Compiler signifie geler l'état du code à un moment donné dans une forme
différence, celle d'un objet binaire (qui est ensuite ranger dans la
bibliothèque). Si par la suite tu veux modifier ce code (en changeant un
symbole du préprocesseur), l'objet binaire (et donc la bibliothèque) ne
correspond plus et donc devient en quelque sorte inutile.

Si on va un peu plus loin, on peut compiler deux fois et créer deux
objets binaires, ou deux jeux d'objets binaires (deux bibliothèques),
qui dépendent de valeurs différentes des symboles préprocesseurs, le
reste restant (!) identiques.
Mais si définit une troisième valeur différente, ces objets binaires ne
servent plus à rien...


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.



OK, erreur classique et courante, confondre une bibliothèque et le
fichier d'entête : ce sont deux choses différentes !

Le fichier d'entête représente la partie publique, ou interface : c'est
le rassemblement de tous les éléments nécessaires pour que d'autre codes
utilisent la dite bibliothèque ; ainsi l'ensemble des fichiers .h
fournis par le compilateur rassemble l'ensemble des informations
nécessaires à l'utilisation des bibliothèques fournies par le compilateur.
Le binaire de la bibliothèque (qui est ce que l'on désigne le plus
souvent comme la bibliothèque elle-même, car c'est ce qui contient la
substantifique moelle) est, comme expliqué ci-dessus, le résultat de la
compilation du code source, et est destiné à être lié ultérieurement
avec le code utilisateur. Cette bibliothèque est stockée dans un fichier
qui porte l'extension .a ou .lib (statiques) ou .so ou .dll
(dynamiques), selon le système et la manière d'utiliser le compilateur.

La fabrication de la bibliothèque intervient en amont, à partir de son
propre code source, qui n'est plus utile par la suite dans le processus
(et n'est donc pas fourni dans de nombreux cas aux utilisateurs).


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



Parce que là tu regardes une situation plus élaborée que la situation
simple qui est celle décrite ci-dessus.
Windows peut être considéré comme une bibliothèque, juste beaucoup plus
grande ! Et de la même façon tu as des fichiers .h, des fichiers .dll
qui contiennent la bibliothèque proprement dite, et le code source n'est
pas disponible.
Seulement voilà, Windows existe depuis plus de vingt ans, et il y a des
variations qui ont été crées à partir d'un tronc commun : Win32 et WinCE
sont deux variantes importantes, avec peu de différences entre elles au
niveau de l'interface et beaucoup de points communs. Afin de renforcer
auprès des développeurs l'idée marketing qu'il s'agit fondamentalement
de la même chose, les programmeurs de Microsoft ont donc intégré l'union
(au sens de la théorie des ensembles) des interfaces dans les fichiers
.h, et les #ifdef servent à réduire à la variante visée l'interface
visible pour une compilation donnée ; mais de leur côté, les
bibliothèques (qui ont été compilées bien avant) sont totalement
séparées, ici au point même que les compilateurs sont physiquement
différents et donc vont piocher automatiquement la « bonne » bibliothèque.

Si tu veux faire un truc du même genre, tu doit donc fournir deux
bibliothèques .lib (une pour chaque «projet»), et au moment de la
compilation, le développeur final devra indiquer laquelle des deux
bibliothèques il souhaite lier avec le reste de son code. S'il n'y a pas
de différences entre les interfaces publiques des deux projets, le
fichier .h utilisé par le développeur final n'aura pas de #ifdef ;
si par contre il y a des différences, un type qui change, ou un
paramètre en plus pour une des fonctions, alors tu peux utiliser soit
des .h différents (c'est le plus clair), soit des #ifdef qui fondent les
différences dans un seul fichier, mais permette la sélection d'une seule
variante au moment d'une compilation donnée : reste alors au développeur
la responsabilité d'apparier correctement les -DPRJ=<n> avec les
biblio<n>.lib au moment de la compilation.


Antoine
Avatar
requinham
On 13 mai, 11:07, Antoine Leca wrote:
requinham écrivit :

> mon probleme est de compiler une librairie statique
> avec deux symbole préprocesseur qui ne sont pas définie

C'est bien cela que je ne comprend absolument pas.

Compiler signifie geler l'état du code à un moment donné dans une f orme
différence, celle d'un objet binaire (qui est ensuite ranger dans la
bibliothèque). Si par la suite tu veux modifier ce code (en changeant u n
symbole du préprocesseur), l'objet binaire (et donc la bibliothèque) ne
correspond plus et donc devient en quelque sorte inutile.

Si on va un peu plus loin, on peut compiler deux fois et créer deux
objets binaires, ou deux jeux d'objets binaires (deux bibliothèques),
qui dépendent de valeurs différentes des symboles préprocesseurs, l e
reste restant (!) identiques.
Mais si définit une troisième valeur différente, ces objets binaire s ne
servent plus à rien...

> 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.

OK, erreur classique et courante, confondre une bibliothèque et le
fichier d'entête : ce sont deux choses différentes !

Le fichier d'entête représente la partie publique, ou interface : c'e st
le rassemblement de tous les éléments nécessaires pour que d'autre codes
utilisent la dite bibliothèque ; ainsi l'ensemble des fichiers .h
fournis par le compilateur rassemble l'ensemble des informations
nécessaires à l'utilisation des bibliothèques fournies par le compi lateur.
Le binaire de la bibliothèque (qui est ce que l'on désigne le plus
souvent comme la bibliothèque elle-même, car c'est ce qui contient la
substantifique moelle) est, comme expliqué ci-dessus, le résultat de la
compilation du code source, et est destiné à être lié ultérieur ement
avec le code utilisateur. Cette bibliothèque est stockée dans un fich ier
qui porte l'extension .a ou .lib (statiques) ou .so ou .dll
(dynamiques), selon le système et la manière d'utiliser le compilateu r.

La fabrication de la bibliothèque intervient en amont, à partir de so n
propre code source, qui n'est plus utile par la suite dans le processus
(et n'est donc pas fourni dans de nombreux cas aux utilisateurs).

> 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

Parce que là tu regardes une situation plus élaborée que la situati on
simple qui est celle décrite ci-dessus.
Windows peut être considéré comme une bibliothèque, juste beaucou p plus
grande ! Et de la même façon tu as des fichiers .h, des fichiers .dll
qui contiennent la bibliothèque proprement dite, et le code source n'es t
pas disponible.
Seulement voilà, Windows existe depuis plus de vingt ans, et il y a des
variations qui ont été crées à partir d'un tronc commun : Win32 e t WinCE
sont deux variantes importantes, avec peu de différences entre elles au
niveau de l'interface et beaucoup de points communs. Afin de renforcer
auprès des développeurs l'idée marketing qu'il s'agit fondamentalem ent
de la même chose, les programmeurs de Microsoft ont donc intégré l' union
(au sens de la théorie des ensembles) des interfaces dans les fichiers
.h, et les #ifdef servent à réduire à la variante visée l'interfa ce
visible pour une compilation donnée ; mais de leur côté, les
bibliothèques (qui ont été compilées bien avant) sont totalement
séparées, ici au point même que les compilateurs sont physiquement
différents et donc vont piocher automatiquement la « bonne » biblio thèque.

Si tu veux faire un truc du même genre, tu doit donc fournir deux
bibliothèques .lib (une pour chaque «projet»), et au moment de la
compilation, le développeur final devra indiquer laquelle des deux
bibliothèques il souhaite lier avec le reste de son code. S'il n'y a pa s
de différences entre les interfaces publiques des deux projets, le
fichier .h utilisé par le développeur final n'aura pas de #ifdef ;
si par contre il y a des différences, un type qui change, ou un
paramètre en plus pour une des fonctions, alors tu peux utiliser soit
des .h différents (c'est le plus clair), soit des #ifdef qui fondent le s
différences dans un seul fichier, mais permette la sélection d'une se ule
variante au moment d'une compilation donnée : reste alors au développ eur
la responsabilité d'apparier correctement les -DPRJ=<n> avec les
biblio<n>.lib au moment de la compilation.

Antoine



Merci pour ces précieuses informations maintenant tout est claire
grâce à toi :)