Langue: 日本語 | Español | Français | Português | 中文 | English
Précédent | Suivant | Sommaire | Version originale anglaise (gnu.org)

13 Intégrer GNU make (interaction avec d’autres programmes)

GNU make est souvent utilisé comme un composant parmi d’autres au sein d’un ensemble d’outils plus vaste, tel qu’un environnement de développement intégré (IDE) ou une chaîne de compilation. Le rôle de make est de lancer des commandes et de déterminer si elles ont réussi ou non : aucun mécanisme d’intégration particulier n’est nécessaire pour remplir ce rôle. Toutefois, il est parfois pratique de lier make plus étroitement aux autres parties du système. Cela concerne aussi bien l’interaction avec les outils de plus haut niveau (ceux qui invoquent make) qu’avec ceux de plus bas niveau (ceux que make invoque).

13.1 Partager des tâches (job slots) avec GNU make

GNU make possède la capacité d’exécuter plusieurs recettes (recipe) en parallèle (voir Exécution parallèle) et même de plafonner le nombre total de tâches (job) parallèles à travers les invocations récursives de make (voir Communiquer des options à un sous-make). Certains outils que make invoque sont eux aussi capables d’exécuter plusieurs opérations en parallèle, soit au moyen de plusieurs threads, soit au moyen de plusieurs processus. On peut les enrichir pour qu’ils participent au mécanisme de gestion des tâches de GNU make, afin de garantir que le nombre total de threads/processus actifs sur le système ne dépasse pas le nombre maximal de slots accordés à GNU make.

GNU make utilise une méthode appelée « jobserver » pour contrôler le nombre de tâches actives à travers les invocations récursives. L’implémentation concrète du jobserver varie d’un système d’exploitation à l’autre, mais certains principes fondamentaux restent toujours valables.

Premièrement, make fournit à ses processus enfants, par le biais de l’environnement, les informations nécessaires pour accéder au jobserver, dans la variable d’environnement MAKEFLAGS. Les outils qui souhaitent participer au protocole du jobserver doivent analyser cette variable d’environnement et y trouver le mot commençant par --jobserver-auth=. La valeur de cette option décrit comment communiquer avec le jobserver. L’interprétation de cette valeur est décrite dans les sections ci-dessous.

Notez que la variable MAKEFLAGS peut contenir plusieurs occurrences de l’option --jobserver-auth=. Seule la dernière occurrence est pertinente.

Deuxièmement, toute commande que make démarre dispose d’un slot de tâche implicite qui lui est réservé avant son lancement. Tout outil qui souhaite participer au protocole du jobserver peut supposer qu’il peut toujours exécuter une tâche sans avoir à contacter le jobserver.

Enfin, il est essentiel que les outils participant au protocole du jobserver rendent au jobserver exactement le nombre de slots qu’ils en ont obtenus, et ce avant de se terminer, même en cas d’erreur. N’oubliez pas que le slot de tâche implicite ne doit pas être rendu au jobserver ! Rendre trop peu de slots signifie que ces slots seront perdus pour tout le reste du processus de construction ; en rendre trop signifie que des slots supplémentaires deviendront disponibles. La commande make de plus haut niveau affiche un message d’erreur à la fin de la construction si elle détecte un nombre incorrect de slots disponibles dans le jobserver.

Prenons comme exemple le cas où vous implémentez un éditeur de liens (linker) prenant en charge un fonctionnement multithread. Vous souhaitez enrichir cet éditeur de liens de sorte que, lorsqu’il est invoqué par GNU make, il participe au protocole du jobserver pour contrôler le nombre de threads utilisés durant l’édition de liens. Vous devrez d’abord modifier l’éditeur de liens pour qu’il détermine si la variable d’environnement MAKEFLAGS est définie. Ensuite, vous devrez analyser la valeur de cette variable pour déterminer si le jobserver est disponible et comment y accéder. S’il est disponible, vous pouvez y accéder pour obtenir des slots de tâche contrôlant le degré de parallélisme que votre outil peut utiliser. Une fois le travail terminé, votre outil doit rendre ces slots de tâche au jobserver.

13.1.1 Interaction avec le jobserver sous POSIX

Sur les systèmes POSIX, le jobserver est implémenté de l’une des deux façons suivantes. Sur les systèmes qui le prennent en charge, GNU make crée un tube nommé (named pipe) et l’utilise comme jobserver. Dans ce cas, l’option auth prend la forme --jobserver-auth=fifo:PATH, où « PATH » est le chemin du tube nommé. Pour accéder au jobserver, vous devez ouvrir le chemin de ce tube nommé et y lire/écrire comme décrit ci-dessous.

Si le système ne prend pas en charge les tubes nommés, ou si l’utilisateur a fourni l’option --jobserver-style en spécifiant « pipe », alors le jobserver est implémenté sous la forme d’un simple tube UNIX. Dans ce cas, l’option auth prend la forme --jobserver-auth=R,W, où « R » et « W » sont des entiers non négatifs représentant des descripteurs de fichier : « R » est le descripteur de fichier en lecture et « W » le descripteur de fichier en écriture. Si l’un de ces descripteurs de fichier, ou les deux, est négatif, cela signifie que le jobserver est désactivé pour ce processus.

Lorsqu’un simple tube est utilisé, seules les lignes de commande que make reconnaît comme des invocations récursives de make (voir Fonctionnement de la variable MAKE) ont accès au jobserver. Lorsque vous écrivez des makefiles, vous devez veiller à marquer la commande comme récursive (le plus souvent en préfixant la ligne de commande par l’indicateur + ; voir Utilisation récursive de make). Notez que le côté lecture du tube du jobserver est réglé en mode « bloquant » (blocking). Cela ne doit pas être modifié.

Dans les deux implémentations du jobserver, le tube est préchargé avec un jeton (token) d’un seul caractère pour chaque tâche disponible. Pour obtenir un slot supplémentaire, vous devez lire un seul caractère depuis le jobserver ; pour libérer un slot, vous devez écrire un seul caractère dans le jobserver.

Il est important, lorsque vous libérez le slot de tâche, de réécrire le même caractère que celui que vous avez lu. Ne supposez pas que tous les jetons sont le même caractère ; des caractères différents peuvent avoir des significations différentes pour GNU make. L’ordre n’a pas d’importance, car make n’a de toute façon aucune idée de l’ordre dans lequel les tâches se termineront.

Diverses conditions d’erreur doivent être prises en compte pour garantir la robustesse de votre implémentation :

13.1.2 Interaction avec le jobserver sous Windows

Sur les systèmes Windows, le jobserver est implémenté sous la forme d’un sémaphore nommé (named semaphore). Le sémaphore est configuré avec un compteur initial égal au nombre de slots disponibles ; pour obtenir un slot, vous devez attendre (wait) sur le sémaphore (avec ou sans délai d’expiration). Pour libérer un slot, libérez (release) le sémaphore.

Pour accéder au sémaphore, vous devez analyser la variable MAKEFLAGS et y rechercher la chaîne d’argument --jobserver-auth=NAME, où « NAME » est le nom du sémaphore nommé. Passez ce nom à OpenSemaphore pour créer un descripteur (handle) vers le sémaphore.

Le seul style valable pour --jobserver-style est « sem ».

Diverses conditions d’erreur doivent être prises en compte pour garantir la robustesse de votre implémentation :

13.2 Synchroniser la sortie sur le terminal

Normalement, GNU make invoque toutes les commandes en leur donnant accès aux mêmes sorties standard et d’erreur que celles avec lesquelles make lui-même a été démarré. De nombreux outils détectent si la sortie est un terminal ou non, et utilisent cette information pour modifier leur style de sortie. Par exemple, si la sortie va vers un terminal, l’outil peut ajouter des caractères de contrôle qui définissent une couleur, voire modifier la position du curseur. Si la sortie ne va pas vers un terminal, ces caractères de contrôle spéciaux ne sont pas émis, afin qu’ils ne corrompent pas les fichiers journaux, etc.

L’option --output-sync (voir Sortie pendant l’exécution parallèle) désactive cette détection du terminal. Lorsque la synchronisation de la sortie est activée, GNU make fait en sorte que toute la sortie des commandes soit d’abord écrite dans un fichier, afin que cette sortie puisse être écrite d’un seul bloc sans être perturbée par celle d’autres commandes. Cela signifie que tous les outils invoqués par make croiront que leur sortie ne sera pas affichée sur un terminal, même lorsqu’elle le sera (parce que make l’y affichera une fois la commande terminée).

Afin d’aider les outils qui souhaitent déterminer si leur sortie sera ou non affichée sur un terminal, GNU make définit les variables d’environnement MAKE_TERMOUT et MAKE_TERMERR avant d’invoquer la moindre commande. Les outils qui souhaitent déterminer si la sortie standard (ou la sortie d’erreur, respectivement) sera affichée sur un terminal peuvent vérifier si ces variables d’environnement existent et contiennent une valeur non vide. Si c’est le cas, l’outil peut supposer que la sortie sera (à terme) affichée sur un terminal. Si ces variables ne sont pas définies ou ont une valeur vide, l’outil doit alors se rabattre sur ses méthodes habituelles pour détecter si la sortie va vers un terminal ou non.

Le contenu de ces variables peut être analysé pour déterminer le type de terminal qui sera utilisé pour afficher la sortie.

De même, les environnements qui invoquent make et souhaitent en capturer la sortie pour finalement l’afficher sur un terminal (ou sur un dispositif d’affichage capable d’interpréter les caractères de contrôle de terminal) peuvent définir ces variables avant d’invoquer make. GNU make ne modifie pas ces variables d’environnement si elles existent déjà à son démarrage.


Précédent | Suivant | Sommaire | Version originale anglaise (gnu.org)