Compilez sous GNU/Linux !

Formation

En Semi-présenciel Paris

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Méthodologie

    En semi-présentiel

  • Lieu

    Paris

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Les sites et dates disponibles

Lieu

Date de début

Paris ((75) Paris)
Voir plan
7 Cité Paradis, 75010

Date de début

Consulter

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Le programme

Introduction du cours

Bonjour à tous, petits développeurs linuxiens.

Vous trouvez votre IDE limité, moche, lourd ? Ou simplement vous aimeriez comprendre qu'est-ce qui se passe derrière quand vous compilez ? Vous êtes un défenseur de la console façe aux outils clickodrome ? Vous n'envisagez pas de coder sans vim ou emacs ? Ce tutoriel est fait pour vous !

A l'issue de ce tutoriel, vous serez capable de compiler vos programmes avec une simple console, grâce aux merveilleux outils GNU que sont gcc et make.

Le compilateur GCC sous LinuxUn peu de culture

GCC signifie GNU Compiler Collection, autrefois un compilateur C ("GNU C Compiler") devenu multilangage, est un compilateur sous Linux, permettant de compiler du C, du C++, du Java, et j'en passe...
Pour plus de détails, : gcc sur wikipedia.

Je prendrai comme exemple la compilation en C sous Debian & consorts, mais vous pourrez utiliser les informations de ce tuto pour d'autres langages et sous d'autres distributions !

Compilez avec GCCInstaller GCC

Tout d'abord, avant d'entrer dans le vif du sujet, il faut que vous ayez gcc installé !

Sous Ubuntu ou Debian, vous pouvez faire (en root) :

apt-get install build-essential

Ceci installera gcc (pour langage C) et g++ (pour langage C++), mais aussi make qui sera utile pour la suite !

Pour les autres, vous avez sûrement un gestionnaire de paquets. Recherchez donc les paquets gcc et g++ (pour java, prenez gcj, pour fortran prenez g77 ou gfortran).

Utiliser gcc

gcc s'utilise en console (c'est en trois lettres, ça commence par g mais ce n'est pas gui !). C'est une commande qui prend des arguments :
gcc [arguments] [fichiers à compiler] (-ofichier de sortie)

Sans arguments, gcc fait toute la compilation jusqu'à l'exécutable.
L'argument -o permettra de spécifier le nom du fichier de sortie, quels que soient les autres arguments, et donc quel que soit son type !

Imaginons que notre projet soit constitué d'un main.c gérant le programme et d'un fonctions.c (avec fonctions.h) pour les fonctions qu'il appelle !

gcc main.c fonctions.c -o Programme

Ceci créera l'exécutable Programme basé sur main.c et fonctions.c.

Lorsque les headers sont dans le même répertoire que les sources, il est inutile de les préciser.

Et en C++ ?
Eh bien c'est pareil, sauf que vous utiliserez g++ au lieu de gcc :

g++ main.cpp fonctions.cpp -o Programme

Pour lancer le programme, il suffit de taper :

./ProgrammeLes arguments de GCC

La liste est non-exhaustive. Le nombre d'arguments de la fonction gcc est astronomique ! Je ne liste ici que les plus courants (et j'en oublie probablement).

-c : indique à GCC de ne pas linker.
Vous obtiendrez alors un fichier objet (.o).

Exemple :

gcc -c main.c -o main.o

-v : mode verbeux.
Affiche plus de détails.
Si vous voulez tout savoir : les infos sur le processus de compilation, le MD5 de la cible obtenue, ...

-I : spécifie le ou les répertoire(s) des headers.
Indique à gcc où rechercher les fichiers .h.

Par exemple, si vos .c sont dans le dossier sources et vos .h sont dans le dossier headers, il vous faudra entrer :

gcc sources/*.c -I headers -o Programme

-pipe : avec cette option, GCC ne génère pas de fichier temporaire entre chaque étape.
Utilise des tubes (comme les « | » en shell) de façon à ne générer que le fichier cible.

-Ox : indique le degré d'optimisation (x varie de 1 a 6).
gcc optimise votre code, c'est-à-dire qu'il va modifier le code source de façon à ce que le programme ait le même résultat par le chemin le plus court. En somme, il dit « t'aurais mieux fait de programmer cette fonction comme ça ! ».
Plus le degré est fort, plus l'optimisation est bonne, mais plus la compilation est longue et gourmande en mémoire !

Remplacez x par s (-Os) et gcc organisera votre code de manière à ce qu'il soit le plus court possible.

-w : supprime tous les avertissements.
Je suis un tueur en programmation, je suis plus un gamin ! Na !

-W : GCC plus exigeant quant aux warnings.
Si votre programme se compile mais ne fait pas ce qu'il devrait faire, essayez avec cet argument !

-Wall : GCC est encore plus exigeant !
La solution ultime !
Attention tout de même : avec cette option, le compilateur peut trouver des erreurs dans des bibliothèques externes qu'on utilise !

-Werror : tous les warnings deviennent des erreurs.
Seul le code parfait compilera !

-g : mode Debugger.
Ajoute des informations de déboggage à l'exécutable. Ces informations peuvent être utilisées par le deboggueur GDB. A noter que vous trouverez un tutoriel sur GDB sur ce site : http://www.siteduzero.com/tutoriel-3-3 [...] avec-gdb.html

-o [fichier] : spécifie la cible.
J'en ai parlé plus haut, sachez simplement que le fichier cible peut être aussi bien un exécutable qu'un fichier objet ou que-sais-je, suivant les autres arguments.
Enfin, c'est un argument comme un autre, vous n'êtes pas obligés de le mettre à la fin comme je l'ai fait :

gcc -o main.o -c main.c

équivaut à :

gcc -c main.c -o main.o

Personnellement, je le mets à la fin car ça me semble plus clair, mais c'est vous qui choisissez !

Si vous ne spécifiez pas de cible, la cible par défaut sera a.out dans le cas d'un exécutable, (nom du fichier c).o dans le cas d'un objet.

C'est tout ?

Vous en voulez plus ? Tapez man gcc en console.
Pour les anglophobes, vous avez la même chose en français en cliquant ici.
Tous les arguments y sont... De quoi perdre la tête !

Sous debian, pour avoir le man, il vous faut le paquet gcc-doc dans les dépôts non-free (licence GFDL).

Compiler des bibliothèques avec GCC

Le compilateur gcc vous permet aussi de compiler les bibliothèques (certains disent "librairies", car "library" en anglais).

Il existe deux types de bibliothèques : les bibliothèques statiques et les bibliothèques dynamiques.

Les bibliothèques statiques

Une bibliothèque statique (généralement d'extension .a) est une bibliothèque qui sera intégrée à l'exécutable lors de la compilation.
L'avantage est que l'exécutable produit est autonome et ne nécessite rien de plus pour fonctionner. La bibliothèque se comporte comme un autre fichier objet.

Si vous voulez faire une bibliothèque statique avec machin.c et machin.h, il suffit de faire :

gcc -c machin.c -o machin.o ar -q libmachin.a machin.o

La première commande crée le fichier objet (ça, on connait). La commande ar archive tout simplement ce fichier.
Pour plus de détails, lisez man ar en français.

La bibliothèque se liera comme n'importe quel fichier objet :

gcc bidule1.o bidule2.o bidule3.o libmachin.a -o ProgrammeLes bibliothèques dynamiques

Les bibliothèques dynamiques - .so (Sharing Object) sous Linux ou .dll (Dynamic Link Library) sous Windows - sont des bibliothèques qui ne sont pas intégrées à l'exécutable lors de l'édition de liens. L'exécutable appelle alors la bibliothèque pour exécuter les fonctions.
Il en ressort plusieurs avantages :

  • si la bibliothèque est utilisée par plusieurs programmes, elle n'est chargée qu'une fois en mémoire ;

  • l'exécutable est plus léger ;

  • on peut la mettre à jour sans recompiler le programme (à condition de ne pas modifier le header).

En revanche, il faudra fournir la bibliothèque, sans quoi le programme ne pourra pas fonctionner.

Pour créer une bibliothèque dynamique, il faut utiliser

gcc -c -fPIC truc -o truc.o gcc -shared -fPIC truc.o -o libtruc.so

L'option -fPIC (Position Independent Code) compile sans indiquer d'adresse mémoire dans le code, car en fonction du programme qui l'utilisera, les adresses pourront être différentes. Ceci évitera des conflits entre les bibliothèques.

L'option -shared indique que c'est une bibliothèque partagée (autre façon de dire dynamique).

On compilera encore de la même manière (avec -fPIC en plus, par sécurité) :

gcc -fPIC bidule1.o bidule2.o bidule3.o libtruc.so -o Programme

Hélas, l'exécutable n'est pas prêt à être utilisé. En effet, lorsqu'un programme appelle une bibliothèque, Linux cherche si la bibliothèque est installée dans un répertoire par défaut, mais pas dans le répertoire courant.

Pour pouvoir utiliser ce programme, il y a 2 solutions :

  • LA MAUVAISE : copier la bibliothèque dans /lib ou dans /usr/lib

    cp libtruc.so /lib

    (nécessite d'être root)
    On laisse ces répertoires aux programmes fournis et suivis par la distribution Linux. On ne pollue pas le système avec nos programmes personnels.
    Pour les programmes personnels (ou du voisin, ou que-sais-je), on utilise le répertoire /usr/local.
    On copiera donc les bibliothèques dans /usr/local/lib !
    Hélas, ce répertoire ne sera pas trouvé non plus par le système lorsque le programme appellera la bibliothèque !

  • On utilisera donc :

  • LA BONNE MÉTHODE : utiliser la variable LD_LIBRARY_PATH. Cette variable donne les autres chemins où sont appelés les bibliothèques. Elle est sous la forme chemin1:chemin2:chemin3. Vous pouvez voir sa valeur en utilisant :

    echo $LD_LIBRARY_PATH

    Généralement par défaut, elle n'est pas définie, la commande affichera alors un blanc. Pour ajouter un dossier, il suffit de mettre

    export LD_LIBRARY_PATH=chemin:$LD_LIBRARY_PATH

    Pour indiquer le répertoire courant, utilisez le point (.).

Si vous ne voulez pas refaire la manip après chaque démarrage du système, éditez le fichier /home/moi/.profile (n'affecte que l'utilisateur "moi") ou bien /etc/profile (affecte tous les utilisateurs, nécessite donc d'être root pour le modifier).
Rajoutez la ligne export LD_LIBRARY_PATH=chemin:$LD_LIBRARY_PATH, et voilà !

Remarquez, vous pouvez le faire en une ligne de commande :

echo export LD_LIBRARY_PATH=chemin:$LD_LIBRARY_PATH >> ~/.profile

Cependant, ceci rajoutera la ligne à la fin du fichier. Les fichiers .profile (s'il existe) et /etc/profile étant structurés, il est préférable de les éditer à la main.

Les noms usuels

J'ai donné comme nom à mes exemples libmachin.a et libtruc.so. J'aurais très bien plus les appeler machin.lib et truc.dll : on est sous Linux, tout est permis !

Cependant, on utilisera plutôt par convention, des noms du même type que mes exemples. De plus, cela vous permettra de compiler en utilisant les options -l et -L :

  • -lmachin pour libmachin.a ou -ltruc pour libtruc.so,
    -l rajoute automatiquement lib devant et .a ou .so derrière ;

  • -Lchemin pour indiquer le chemin ;
    non nécessaire si le chemin est /lib ou /usr/lib (mais ça ne devrait pas !) ou dans LD_LIBRARY_PATH.

Exemple :

gcc -fPIC bidule.o -L. -lbidule -o Programme

gcc créera l'exécutable Programme en liant l'objet bidule.o avec la bibliothèque libbidule.so (ou libbidule.a s'il ne trouve pas le so), située dans le répertoire courant.

Mettre à jour une bibliothèqueld -soname

Maintenant, vous savez faire des bibliothèques dynamiques ; mais comment différencier deux versions de la même bibliothèque et faire en sorte que la nouvelle version fonctionne avec un programme compilé avec la première version ?

Par exemple, je compile le programme bidule avec la bibliothèque libtruc.so.1.1. Plus tard, je veux installer (pour un autre programme) libtruc.so.1.2. Mais je veux que le programme bidule puisse l'utiliser.

On utilise pour cela l'option -Wl,-soname, pour définir le lien libtruc.so.1 comme cela :

gcc -Wl,-soname, libtruc.so.1 -o libtruc.so.1.1

Ceci créera la bibliothèque libtruc.so.1.1, à partir de libtruc.so.1, et cette bibliothèque sera reconnue comme libtruc.so.1 !

Quelques explications

Je ne vous l'avais pas dit, mais gcc ne fait pas l'édition de liens ! Il appelle pour cela la commande ld !
Pour passer des options à ld avec gcc on utilise -Wl,option,

L'option -soname libtruc.so.1 permettra à l'OS de reconnaître une bibliothèque comme s'appelant libtruc.so.1.
Le nom libtruc.so.1 sera intégré dans la cible (libtruc.so.1.1) et sera lu par ldconfig.

ldconfig

ldconfig crée des liens symboliques entre les -soname et les bibliothèques concernées.

Il inspecte les bibliothèques dans les emplacements suivants :

  • /lib

  • /usr/lib

  • les chemins indiqués dans /etc/ld.so.conf (vous pouvez l'éditer si vous êtes root) ;

  • les chemins de LD_LIBRARY_PATH.

Il crée pour chaque bibliothèque un lien ayant comme nom le -soname et ayant comme cible la bibliothèque. Si deux bibliothèques ont le même -soname, il fera le lien vers la version la plus récente.

Faites attention aux points suivants :

  • le nom de la bibliothèque doit être du type libnom.so.version pour être reconnue par ldconfig ;

  • si vous éditez /etc/ld.so.conf, vous n'avez plus besoin de LD_LIBRARY_PATH ;

  • une bibliothèque de ce type ne sera pas reconnue avec l'option -l, qui nécessite un type libnom.so (sans rien derrière) ;

  • il existe certaines conventions : pour mettre à jour une bibliothèque il faut que les prototypes des fonctions soient identiques, si vous rajoutez une fonction à cette bibliothèque, il faudra mettre à votre bibliothèque -soname libtruc.so.2 ! Elle sera alors...

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Compilez sous GNU/Linux !

Prix sur demande