Salut,
A moins de vouloir fouiller dans le contenu des fichiers -- ce qui peut parfois s'avérer intéressant
-- tu n'as pas vraiment besoin de t'en inquiéter.
Si ce qui t'inquiète, c'est de savoir comment le compilateur fait pour les retrouver, dis toi simplement que c'est du ressort des développeurs du compilateur et qu'ils font particulièrement bien leur travail
.
Mais pour faire simple, un compilateur est généralement composé de trois grandes parties :
un préprocesseur, qui prendra en charge toutes les instructions qui commencent par # (dont la fameuse directive #include
), un "front end", qui est l'exécutable qui se chargera de la reconnaissance d'un langage spécifique et qui générera une représentation commune du code rencontré, et enfin un "back end" qui se chargera de convertir cette représentation commune en code binaire exécutable (en passant éventuellement par une étape en assembleur).
Le front end indiquera au préprocesseur la liste des chemins d'accès qu'il connait comme étant susceptibles de contenir des fichiers d'en-tête et le préprocesseur utilisera cette liste lorsqu'il devra gérer les directives #include.
Les front end disposent de plusieurs sources pour connaitre les chemins d'accès qui les intéressent :
- Certains sont directement codés en dur dans le front end
- D'autres peuvent être indiqués dans les fichiers specs,
- D'autres encore peuvent être définis par les variables d'environnement C_INCLUDE_PATH et / ou CPLUS_INCLUDE_PATH
- Et d'autres enfin peuvent être définis grâce à l'option -I<chenmin vers le dossier contenant les fichiers d'en-tête>
Tu peux obtenir l'affichage de toutes les informations en utilisant l'option -v (--verbose) sous une forme proche de
ou de (spécifique C++)
Mais, comme cela donnera énormément d'informations, tu préféreras sans doute le faire dans un fichier vide créé pour l'occasion. Cela se traduirait par les instructions
1 2
| touch test.cpp // crée un fichier nommé "test.cpp" vide juste pour cette occasion
g++ -v test.cpp |
et là, tu obtiendra un affichage assez important dont une bonne partie aura pour objectif de se plaindre du fait d'une référence non définie sur la fonction main() (ce qui est normal, vu que le fichier est vide
).
Tu peux donc demander à g++ de se contenter d'effectuer le traitement du préprocesseur en rajoutant l'option -E.
Cela prendrait donc la forme de
1 2
| touch test.cpp // crée un fichier nommé "test.cpp" vide juste pour cette occasion
g++ -v -E test.cpp |
et tu obtiendras une sortie fort proche de
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
| Using built-in specs.
COLLECT_GCC=g++
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.1-10ubuntu9' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9)
COLLECT_GCC_OPTIONS='-v' '-E' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.8/cc1plus -E -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE test.cpp -mtune=generic -march=x86-64 -fstack-protector -Wformat -Wformat-security
ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/4.8"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/4.8
/usr/include/x86_64-linux-gnu/c++/4.8
/usr/include/c++/4.8/backward
/usr/lib/gcc/x86_64-linux-gnu/4.8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
# 1 "test.cpp"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "test.cpp"
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-E' '-shared-libgcc' '-mtune=generic' '-march=x86-64' |
La première ligne t'indique qu'il utilise les spécifications interne uniquement (à moins que tu n'aies fourni un fichier specs indiqué plus tôt)
Suit la ligne qui indique l'outil qui est utilisé (g++ en l'occurrence) et la cible pour laquelle l'exécutable sera créé (x86_64-linux-gnu)
Puis viennent les options de configurations utilisées pour la compilation du compilateur (hé oui, un compilateur n'est qu'une application comme une autre, qui doit être compilée comme une autre
)
Ensuite, c'est au tour de l'affichage du modèle de thread utilisé (Thread model: posix)et de la version du compilateur (gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9) )
Puis, c'est au tour des options de compilations qui sont utilisée sous la forme de
1 2
| COLLECT_GCC_OPTIONS='-v' '-E' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/4.8/cc1plus -E -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE test.cpp -mtune=generic -march=x86-64 -fstack-protector -Wformat -Wformat-security |
Tu remarquera que l'on repère les deux options -v et -E que l'on a indiqué, mais que d'autres options ont été automatiquement rajoutée (tout ce qui suit le '-E'
).
Ce sont des options qui ont été retrouvées dans le fichier specs (s'il existe) ou dans l'équivalent "interne" du front end
Les lignes
1 2 3
| ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/4.8"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../x86_64-linux-gnu/include" |
t'indiquent qu'il ignore volontairement un certain nombre de dossiers qui apparaissent plusieurs fois dans la liste des dossiers à utiliser 
Ensuite vient l'information qui t'intéresse :
1 2 3 4 5 6 7 8 9 10 11
| #include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/4.8
/usr/include/x86_64-linux-gnu/c++/4.8
/usr/include/c++/4.8/backward
/usr/lib/gcc/x86_64-linux-gnu/4.8/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list. |
Les deux premières lignes t'indiquent que les dossiers seront utilisés aussi bien sur une directive #include "fichier.h" que sur une directive #include <fichier.h>
Toutes les lignes suivantes indiquent à chaque fois un dossier dans lequel le compilateur ira chercher les fichiers d'en-tete.
Les lignes
1 2 3 4 5 6 7 8
| # 1 "test.cpp"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "test.cpp" |
présentent le résultat du passage du préprocesseur sur le fichier que l'on a indiqué.
Tu remarqueras que, bien que notre fichier était vide à l'origine, le préprocesseur a quand même réussi à lui taper quelques lignes 
On termine par la synthèse des chemins qui sont utilisés lorsqu'on recherche des applications et des exécutables sous la forme de
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/
par les chemins qui seront utilisés lorsque l'on recherchera des bibliothèques sous la forme de
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.8/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../:/lib/:/usr/lib/
et enfin par certaines options de compilation spécifiques (il ne serait pas étonnant qu'elles fussent définies à plusieurs endroits) sous la forme de
COLLECT_GCC_OPTIONS='-v' '-E' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
Partager