Comment puis-je ajouter dir à $ PATH dans Makefile?

87

Je veux écrire un Makefile qui exécuterait des tests. Les tests sont dans un répertoire './tests' et les fichiers exécutables à tester sont dans le répertoire './bin'.

Lorsque j'exécute les tests, ils ne voient pas les fichiers exécutables, car le répertoire ./bin n'est pas dans le $ PATH.

Quand je fais quelque chose comme ça:

EXPORT PATH=bin:$PATH
make test

tout fonctionne. Cependant, je dois changer le $ PATH dans le Makefile.

Contenu Makefile simple:

test all:
    PATH=bin:${PATH}
    @echo $(PATH)
    x

Il imprime correctement le chemin, mais ne trouve pas le fichier x.

Lorsque je fais cela manuellement:

$ export PATH=bin:$PATH
$ x

tout va bien alors.

Comment pourrais-je changer le $ PATH dans le Makefile?

Szymon Lipiński
la source
Ne pouvez-vous pas simplement appeler les tests à partir du répertoire exécutable comme ../test/test_to_run? Désolé si j'ai mal compris la question.
Chris
Je veux que ce fichier soit normalement visible pour les tests. Je ne veux pas jouer avec les répertoires, car je refactoriserais ce serait un nighmare.
Szymon Lipiński
La seule façon de s'en approcher est de demander au makefile d'écrire un script shell contenant la variable decls, puis d'avoir le shell parent source avec ce script .. Ceci n'est probablement pas pratique cependant.
Michael Smith
Je crois que unix.stackexchange.com/questions/11530/… est une question très différente (stupide), contrairement à la vôtre.
imz - Ivan Zakharyaschev

Réponses:

106

Avez-vous essayé la exportdirective de Make lui-même (en supposant que vous utilisez GNU Make)?

export PATH := bin:$(PATH)

test all:
    x

En outre, il y a un bogue dans votre exemple:

test all:
    PATH=bin:${PATH}
    @echo $(PATH)
    x

Premièrement, la valeur en cours d' echoédition est une expansion de PATHvariable effectuée par Make, pas par le shell. S'il imprime la valeur attendue, je suppose que vous avez défini la PATHvariable quelque part plus tôt dans votre Makefile, ou dans un shell qui a appelé Make. Pour éviter un tel comportement, vous devez échapper aux dollars:

test all:
    PATH=bin:$$PATH
    @echo $$PATH
    x

Deuxièmement, dans tous les cas, cela ne fonctionnera pas car Make exécute chaque ligne de la recette dans un shell séparé . Cela peut être changé en écrivant la recette sur une seule ligne:

test all:
    export PATH=bin:$$PATH; echo $$PATH; x
Eldar Abusalimov
la source
7
$(PATH)obtiendra la valeur de PATHdu shell invoquant make. Selon le manuel , "Chaque variable d'environnement qui fait voit quand il démarre est transformée en une variable make avec le même nom et la même valeur."
Emil Sit
La directive d'exportation a fonctionné pour moi (merci!), Mais seulement après avoir installé GNU Make 4.3. Dans la version 3.81 (la valeur par défaut sur macOS Catalina), la version actualisée PATHest correctement reflétée dans les variables ( echo $(PATH)) et dans les environnements de commandes ( env, which python, bash -c python), mais ne semble pas être utilisé lors de la localisation de l'exécutable pour la commande: la commande pythongere encore Exécutable Python sur l'original PATH.
doctaphred le
27

Par conception, l' makeanalyseur exécute les lignes dans des invocations de shell séparées, c'est pourquoi en changeant la variable (par exemple PATH) sur une ligne, le changement peut ne pas être appliqué pour les lignes suivantes (voir cet article ).

Une façon de contourner ce problème est de convertir plusieurs commandes en une seule ligne (séparées par ;), ou d'utiliser une cible spéciale One Shell ( .ONESHELL, à partir de GNU Make 3.82).

Vous pouvez également fournir une PATHvariable au moment où le shell est appelé. Par exemple:

PATH  := $(PATH):$(PWD)/bin:/my/other/path
SHELL := env PATH=$(PATH) /bin/bash
Kenorb
la source
2
J'aime l'approche!
Alan Franzoni
2
C'est le meilleur, car cela fonctionne même avec des $(shell)invocations! : D Exemple: pastebin.com/Pii8pmkD
PsychoX
Sur dev.azure, j'obtiens: env: 'env': aucun fichier ou répertoire de ce type; Fonctionne localement; /
Kamil Dziedzic
Ne fonctionne pas sur Debian 10 avec make 4.2: make: env PATH = <chemin> / bin / sh: Commande introuvable. Utilisation des travaux d'exportation. Assurez-vous d'utiliser $ (HOME) et non ~ pour un chemin dans le répertoire home.
MKesper le
25

Les changements de chemin semblent persistants si vous définissez d'abord la variable SHELL dans votre makefile:

SHELL := /bin/bash
PATH := bin:$(PATH)

test all:
    x

Je ne sais pas si c'est un comportement souhaité ou non.

sous-spécifié
la source
Cela a résolu le problème que j'avais (j'utilise zsh). Merci!
Jezen Thomas
Oui, cela fait en effet ce que l'OP voulait ... mais est-ce une fonctionnalité ou un bug? Même après avoir lu la section SHELL du manuel de fabrication, je ne suis pas sûr.
pje le
5
Cela ne fonctionne pas non plus pour moi. whichet envmaintenant prenez le nouveau PATH, mais l'exécution directe d'un binaire n'est toujours pas trouvée dans le PATH modifié, seulement dans l'original.
Konrad Rudolph
3

Ce que je fais généralement est de fournir explicitement le chemin d'accès à l'exécutable:

EXE=./bin/
...
test all:
    $(EXE)x

J'utilise également cette technique pour exécuter des binaires non natifs sous un émulateur comme QEMU si je suis en compilation croisée:

EXE = qemu-mips ./bin/

Si make utilise le shell sh, cela devrait fonctionner:

test all:
    PATH=bin:$PATH x
Richard Pennington
la source
Oui, cool soulution, mais j'ai mes tests écrits en perl et je dois appeler l'exe depuis le script perl, pas directement depuis makefile. Je dois repenser l'ensemble des tests de ce truc :)
Szymon Lipiński
Je t'ai eu. Que diriez-vous de définir PATH sur la ligne de commande elle-même? Voir la modification ci-dessus.
Richard Pennington
-2

Pour définir la PATHvariable, dans le Makefile uniquement, utilisez quelque chose comme:

PATH := $(PATH):/my/dir

test:
@echo my new PATH = $(PATH)
Karnhick
la source
Cela ne fonctionne pas comme je le souhaite. J'ai mis à jour la question avec des exemples de ce que je veux réaliser.
Szymon Lipiński