OVH Cloud OVH Cloud

Question sur la compilation

58 réponses
Avatar
Michaël Delva
Bonjour à tous,

j'ai une petite question sur la compilation:

J'ai un fichier .H où sont déclarées 3 fonctions A, B et C, et le .CPP où
se trouvent leurs implémentations.

J'ajoute le .CPP au projet, et dans le code du projet je n'utilise pas la
fonction C.

Quel est le comportement du compilateur: est-ce que la fonction C est quand
même incluse dans l'EXE?

Je me pose la question car avec mon compilo (Borland 6) quand je suis en
mode debug je ne peux pas ajouter de points d'arrets sur le code des
fonctions ou classes que je n'utilise pas.

Et enfin (plus spécifique Windows), est-ce le même principe pour les DLLs?
(Mais pourquoi ne serait-ce pas le cas?)

Merci d'avance...

10 réponses

1 2 3 4 5
Avatar
James Kanze
Matthieu Moy writes:

|> "Alain Naigeon" writes:
|> > a écrit dans le message news:
|> >

|> >> Une phase préprocesseur séparé est très coûteuse en temps de
|> >> compilation ; il exige de faire le même boulot (la découpe en
|> >> tokens) deux fois.

|> > Je te crois évidemment, mais j'ai du mal à comprendre :
|> > 1) je repère et je développe les directives commençant
|> > par un #, et elles seules, et je les intègre au reste qui
|> > n'est pas du tout analysé ;
|> > 2) l'analysateur du compilateur reçoit ce source, et
|> > commence la "tokenisation".

|> #define a b

|> int main() {
|> int a = 42;
|> }

|> Le préprocesseur va remplacer le `a' de "a = 42", mais pas le `a' de
|> "main", et pour ça, il faut "tokeniser".

|> Par contre, le temps de compil n'est quand même pas essentiellement
|> du au découpage en jetons,

Tu as des mésures ? J'en ai pas avec C++, mais dans la passé, avec un
compilateur C, sans optimisation, la tokenisation représentait environ
40% du temps CPU total. Sans parler du fait que faire avec deux
processus séparés, ça veut dire passer les données par le disque, avec
des lectures et des écritures en plus.

|> après, il y a l'analyse syntaxique, le typage, les optims et la
|> génération de code qui sont quand même particulièrement longs.

Pour un langage simple comme le C, c'est quand même la tokenisation qui
prend le temps. C'est quand même la seule phase où on est obligé à
traiter les caractères. Et même si le traitement est plus facile que ce
qu'on fait avec des tokens par la suite, il y en a bien plus.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Avatar
James Kanze
Loïc Joly writes:

|> wrote:
|> > Loïc Joly wrote in message

|> >>Ce qui peut être assez gênant. Quelqu'un sait-il pourquoi la norme
|> >>laisse de côté ces points qui pourtant peuvent avoir une influence
|> >>sur la sémantique d'un programme ?

|> > Parce que la façon d'invoquer un programme et de lui passer des
|> > paramètres dépend de toute façon étroitement du système où on se
|> > trouve. Sous Unix, par exemple, j'ai typiquement toutes ses
|> > informations dans mes fichiers de make, que j'édite avec vim ou
|> > emacs. Sous Windows, avec Visual Studio, il est plus fréquent de
|> > définir un projet avec l'interface graphique. Comment veux-tu
|> > formuler quoique ce soit qui permet des modèles de spécification
|> > aussi différents ?

|> Je ne parlais pas de la syntaxe des appels, mais de la spécification
|> du comportement de la phase de lien.

Le comportement en est bien spécifié : §2.1/8,9.

|> On défini déjà la notion de fichier objet et d'édition de lien.

Pas vraiment, mais passons.

|> Le point qui ne m'apparait pas clair, c'est la façon dont on choisi
|> les variables et fonctions qui peuvent disparaitre.

Tu dois dire à l'implémentation qu'est-ce qui fait partie de ton
programme, et qu'est-ce qui n'en fait pas partie. C'est partie des
commandes à l'implémentation. Donc, défini par l'implémentation.

|> A moins que ce soit ma lecture du standardese qui soit déficiente,
|> "Library components are linked to satisfy external references to
|> functions and objects not defined in the current translation." me
|> semble un peu vague.

Oui et non. Ça réfère à un concepte bien connu, celui de bibliothèque.
Je suppose qu'il aurait pu dire que l'inclusion d'un composant, c'est du
tout ou rien. Mais ça laisserait ouvert la question, qu'est-ce que c'est
qu'un composant. En fait, un composant, c'est ce que le système défini
comme composant.

Enfin, dans la pratique, je n'ai jamais entendu parler d'un système qui
ne faisait pas ce qu'on s'attendait. Ou bien, une unité de traduction
(pour parler le langage de la norme) fait partie du programme
entièrement, ou bien elle n'en fait pas partie du tout.

|> Je n'apprécie en particulier pas qu'un même fichier objet inclus
|> directement ou par l'intermédiaire d'une bibliothèque puisse
|> produire des exécutables aux comportements différents.

Est-ce que tu en as un exemple où c'est le cas ?

À l'exception près des comportements indéfinis ou non spécifiés,
évidemment. Typiquement, l'ordre d'initialisation des objets à durée de
vie statique dépendra d'une façon non spécifiée de l'ordre que les
objets sont incorporé. Ordre qui à son tour peut dépendre de si l'objet
est spécifié directement ou tirer d'une bibliothèque. (Une autre
dépendence, c'est ce qui suit immédiatement une variable statique en
mémoire. Ce qui peut aussi faire une différence de comportement si tu
t'amuse à dépasser les bornes de l'objet.

Mais je ne crois pas que ce soient les différences dont tu parles.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Avatar
Matthieu Moy
James Kanze writes:

Tu as des mésures ? J'en ai pas avec C++, mais dans la passé, avec un
compilateur C, sans optimisation, la tokenisation représentait environ
40% du temps CPU total. Sans parler du fait que faire avec deux
processus séparés, ça veut dire passer les données par le disque, avec
des lectures et des écritures en plus.


Mini benchmark avec gcc sur un "hello, world" (donc, en gros, on
compile stdio.h ...)

0,01 sec pour le préprocesseur
0,03 sec pour la compilation (-> assembleur)
0,10 sec pour la compilation + assemblage (-> fichier objet).
0,60 sec pour la compilation complete (-> executable).

Dans ce ca là en tous cas, le préprocesseur est bien négligeable
devant le reste de la compil. Mais je ne sais pas à quel point c'est
représentatif ...

--
Matthieu

Avatar
Gabriel Dos Reis
Matthieu Moy writes:

| James Kanze writes:
|
| > Tu as des mésures ? J'en ai pas avec C++, mais dans la passé, avec un
| > compilateur C, sans optimisation, la tokenisation représentait environ
| > 40% du temps CPU total. Sans parler du fait que faire avec deux
| > processus séparés, ça veut dire passer les données par le disque, avec
| > des lectures et des écritures en plus.
|
| Mini benchmark avec gcc sur un "hello, world" (donc, en gros, on
| compile stdio.h ...)

Tu as oublié de préciser la version de GCC en question. Voir mon autre
message. Je suggèrerais fortement que tu google un peu avec des mots
clés comme Zack Weinberg, Neil Booth, GCC cpplib, benchmark. Cela te
donnera une idée de ce qui s'est passé.

À la dernière réunion de Kona, Paul Mensondies a exprimé (pendant
une conversion de café) sa satisfaction de voir le nouveau
préprocesseur de GCC -- et surtout impressionné par sa justesse et sa
vitesse. Il s'est plaint de la lenteur de celui de EDG (tu n'as qu'à
voir ce qu'il fait avec CPP dans Boost pour comprendre). Et la réponse
ne s'est pas vait attendre ; la dernière version de EDG met en avant
comme "feature/improvement", le fait qu'ils ont amélioré la
performance de leur préprocesseur.
Au moins, il y a des gens qui mésurent et voient des différences.

-- Gaby
Avatar
Loïc Joly
James Kanze wrote:
|> Je n'apprécie en particulier pas qu'un même fichier objet inclus
|> directement ou par l'intermédiaire d'une bibliothèque puisse
|> produire des exécutables aux comportements différents.

Est-ce que tu en as un exemple où c'est le cas ?


Du code comme suit :

// Factory.h

typedef Object* (*creationFunction)();

class RegisterInFactory
{
RegisterInFactory(string s, creationFunction f)
{
Factory::instance.register(s, f)
}
};

// MyObject.cpp

Object *createMyObject()
{
return new MyObject;
}

RegisterInFactory dummy("MyObject", &createMyObject);
// On n'utilise dummy nulle part...

Avec Visual C++ 6, la variable globale dummy existe bien quand on lie
l'objet directement, mais pas quand MyObject est dans une bibliothèque.
Donc ma factory ne contient pas les mêmes objets. Il existe néanmoins
une option de compilation qui permet de dire au lieur d'include cette
instance, mais il faut pour ça connaître son nom décoré, ce qui est un
peu lourd à mon sens.

--
Loïc

Avatar
Alain Naigeon
"Jean-Marc Bourguet" a écrit dans le message news:


Et les utilisations de macros?


"Christophe de VIENNE" a écrit dans le message
news: newscache$x9jqyh$3l2$

Tu oublie les substitutions dues aux #define,


"Gabriel Dos Reis" a écrit dans le message
news:

Faire un pré-processsing séparé veut dire que [...]


"Matthieu Moy" a écrit dans le message
news:
#define a b

int main() {
int a = 42;
}



Bon, ça va, 4 contre 1, je me rends. J'aurai au moins
appris quelque chose.

--

Français *==> "Musique renaissance" <==* English
midi - facsimiles - ligatures - mensuration
http://anaigeon.free.fr | http://www.medieval.org/emfaq/anaigeon/
Alain Naigeon - - Strasbourg, France

Avatar
Matthieu Moy
Gabriel Dos Reis writes:

Tu as oublié de préciser la version de GCC en question.


3.2.3

J'ai à peu près les mêmes résultats avec un 2.95.

(et merci pour les précisions :-)

--
Matthieu

Avatar
Jean-Marc Bourguet
Loïc Joly writes:

A moins que ce soit ma lecture du standardese qui soit déficiente,
"Library components are linked to satisfy external references to
functions and objects not defined in the current translation." me
semble un peu vague.


J'ai toujours compris ce "Library" comme faisant reference a la
bibliotheque standard.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
kanze
Matthieu Moy wrote in message
news:...
James Kanze writes:

Tu as des mésures ? J'en ai pas avec C++, mais dans la passé, avec
un compilateur C, sans optimisation, la tokenisation représentait
environ 40% du temps CPU total. Sans parler du fait que faire avec
deux processus séparés, ça veut dire passer les données par le
disque, avec des lectures et des écritures en plus.


Mini benchmark avec gcc sur un "hello, world" (donc, en gros, on
compile stdio.h ...)

0,01 sec pour le préprocesseur
0,03 sec pour la compilation (-> assembleur)
0,10 sec pour la compilation + assemblage (-> fichier objet).
0,60 sec pour la compilation complete (-> executable).

Dans ce ca là en tous cas, le préprocesseur est bien négligeable
devant le reste de la compil. Mais je ne sais pas à quel point c'est
représentatif ...


C'est intéressant.

D'abord, nos mésures, alors, ne concernait que le compilateur, pas
l'édition de liens. C'est donc possible que les éditions de liens
pesaient aussi autant alors. Bien que je le doute ; on avait bien moins
de bibliothèques. Des expériences plus tard me fait penser que la
plupart du temps lors des éditions de liens, c'est les accès disques.

Pour la reste, tu ne dis pas exactement ce que tu es en train de
mésurer. Est-ce qu'avec un préprocesseur séparé, par exemple ? Si oui,
tu fais déjà la tokenisation deux fois, une fois dans le préprocesseur,
et une deuxième dans le compilateur proprement dit. Et évidemment,
l'assembleur a son propre phase de tokenisation.

Je suis en effet intrigué du fait que dans la génération de l'objet,
c'est l'assembleur qui prend le plus de temps. Ça fait bien penser qu'un
des aspects critiques, c'est les temps de lecture -- c'est bien
l'assembleur qui lit les plus de données. Est-ce que ce serait encore le
cas que même avec un langage aussi compliqué que le C++, c'est les
entrées/sorties qui prédomine ?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
kanze
Loïc Joly wrote in message
news:<c9o225$sif$...
James Kanze wrote:

|> Je n'apprécie en particulier pas qu'un même fichier objet inclus
|> directement ou par l'intermédiaire d'une bibliothèque puisse
|> produire des exécutables aux comportements différents.

Est-ce que tu en as un exemple où c'est le cas ?


Du code comme suit :

// Factory.h

typedef Object* (*creationFunction)();

class RegisterInFactory
{
RegisterInFactory(string s, creationFunction f)
{
Factory::instance.register(s, f)
}
};

// MyObject.cpp

Object *createMyObject()
{
return new MyObject;
}

RegisterInFactory dummy("MyObject", &createMyObject);
// On n'utilise dummy nulle part...

Avec Visual C++ 6, la variable globale dummy existe bien quand on lie
l'objet directement, mais pas quand MyObject est dans une
bibliothèque.


Et qu'est-ce que tu as fait pour dire à VC++ que MyObject fasse partie
de ton programme ? Si tu ne lui as pas dit que MyObject.cpp (ou l'objet
qui en sort) fasse partie de ton programme, c'est normal que le
compilateur ne le prend pas en compte.

Donc ma factory ne contient pas les mêmes objets. Il existe néanmoins
une option de compilation qui permet de dire au lieur d'include cette
instance, mais il faut pour ça connaître son nom décoré, ce qui est un
peu lourd à mon sens.


Je ne dis pas le contraire. Mais enfin, je ne comprends pas où tu veux
en venir. On est parti de ce qu'exige, ou de ce que devait exiger, la
norme. Tu n'aimes pas la syntaxe que fournit VC++ pour préciser qu'une
unité de compilation spécifique fasse partie de ton programme. Alors,
est-ce que tu veux que la norme précise la syntaxe nécessaire pour
invoquer les commandes de compilation ? (En passant, c'est pareil sur
les Unix que je connais. Il y a une option à l'éditeur de liens pour
créer un symbole non défini arbitraire. Seulement, évidemment, il faut
lui donner le nom que connaît l'éditeur de liens, et non le nom qui
apparaît dans le programme.)

Je suppose que la norme pourrait être plus clair, mais à mon avis,
l'intention est claire, §2.1/9 : « Library components are linked to
satisfy external references to functions and objects not defined in the
current translation. » Autant que je vois, MyObject.cpp ne contient pas
de symbole qui correspond à un « external references functions and
objects not defined in the current translation ». Ça serait donc une
erreur de l'incorporer s'il fasse partie d'une bibliothèque, *au*
*moins* qu'on a dit explicitement au compilateur qu'on le veut. VC++ est
conforme à cet égard. De même que tout autre compilateur dont je me suis
servi. Depuis plus de trente ans. C'est la définition classique de
comment un éditeur de liens traite une bibliothèque.

Et je répète : dans ce cas-ci, le comportement de ton programme n'a pas
changé selon qu'un objet se trouve dans une bibliothèque ou non. Le
comportement a changé du fait que tu as changé l'ensemble des objets
dans le programme. Tu as démandé quelque chose d'autre à
l'implémentation ; c'est donc normal qu'elle t'as donné quelque chose
d'autre. Et moi, j'ai du mal à comprendre de quoi tu te plains. Tu n'as
pas dit au compilateur que MyObject doit faire partie de ton programme.
Comment veux-tu qu'il sache que tu le veux ? Ils sont idiotes, des
ordinateurs. Ils font ce que tu leur démandes, et non ce que tu veux, ou
ce dont tu as besoin.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


1 2 3 4 5