Jak mogę dodać katalog do $ PATH w Makefile?

87

Chcę napisać plik Makefile, który uruchamia testy. Testy znajdują się w katalogu „./tests”, a pliki wykonywalne do przetestowania w katalogu „./bin”.

Kiedy uruchamiam testy, nie widzą plików exec, ponieważ katalogu ./bin nie ma w $ PATH.

Kiedy robię coś takiego:

EXPORT PATH=bin:$PATH
make test

wszystko działa poprawnie. Jednak muszę zmienić $ PATH w Makefile.

Zawartość Simple Makefile:

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

Wyświetla ścieżkę poprawnie, jednak nie znajduje pliku x.

Kiedy robię to ręcznie:

$ export PATH=bin:$PATH
$ x

wszystko jest w porządku.

Jak mogłem zmienić $ PATH w Makefile?

Szymon Lipiński
źródło
Czy nie możesz po prostu wywołać testów z katalogu wykonywalnego ../test/test_to_run? Przepraszam, jeśli źle zrozumiałem pytanie.
Chris,
Chcę, aby ten plik był normalnie widoczny dla testów. Nie chcę bawić się katalogami, ponieważ refaktoryzacja byłaby koszmarem.
Szymon Lipiński
Jedynym sposobem, aby się do tego zbliżyć, jest wypisanie przez plik makefile skryptu powłoki zawierającego zmienną decls, a następnie posiadanie nadrzędnego źródła powłoki, z którym skrypt jest powiązany .. Jest to jednak prawdopodobnie niepraktyczne.
Michael Smith
Uważam, że unix.stackexchange.com/questions/11530/… to zupełnie inne (głupie) pytanie, w przeciwieństwie do twojego.
imz - Ivan Zakharyaschev

Odpowiedzi:

106

Czy próbowałeś exportdyrektywy Make samego (zakładając, że używasz GNU Make)?

export PATH := bin:$(PATH)

test all:
    x

W twoim przykładzie jest również błąd:

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

Po pierwsze, edytowana wartość echojest rozwinięciem PATHzmiennej wykonywanym przez Make, a nie powłokę. Jeśli wypisze oczekiwaną wartość, to myślę, że ustawiłeś PATHzmienną gdzieś wcześniej w swoim Makefile lub w powłoce, która wywołała Make. Aby temu zapobiec, powinieneś uciec od dolarów:

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

Po drugie, w żadnym wypadku to nie zadziała, ponieważ Make wykonuje każdy wiersz przepisu w oddzielnej powłoce . Można to zmienić, wpisując przepis w jednej linii:

test all:
    export PATH=bin:$$PATH; echo $$PATH; x
Eldar Abusalimov
źródło
7
$(PATH)zostanie ustawiona na wartość PATHpowłoki wywołującej make. Zgodnie z instrukcją „Każda zmienna środowiskowa, która sprawia, że ​​widzi się po uruchomieniu, jest przekształcana w zmienną make o tej samej nazwie i wartości”.
Emil Sit
Dyrektywa eksportowa zadziałała dla mnie (dzięki!), Ale dopiero po zainstalowaniu GNU Make 4.3. W wersji 3.81 (domyślnie na MacOS Catalina), zaktualizowany PATHzostał prawidłowo odzwierciedlone w zmiennych ( echo $(PATH)) oraz w środowiskach Polecenia ( env, which python, bash -c python), ale nie wydaje się być stosowany podczas lokalizowania wykonywalny dla polecenia: komenda pythonciągle uruchamia Plik wykonywalny Pythona na oryginale PATH.
udokumentowano
27

Zgodnie z projektem makeparser wykonuje wiersze w oddzielnych wywołaniach powłoki, dlatego zmiana zmiennej (np. PATH) W jednej linii, zmiana może nie zostać zastosowana w kolejnych wierszach (zobacz ten post ).

Jednym ze sposobów obejścia tego problemu jest przekształcenie wielu poleceń w jeden wiersz (oddzielony znakiem ;) lub użycie specjalnego celu One Shell ( .ONESHELLod wersji GNU Make 3.82).

Alternatywnie możesz podać PATHzmienną w momencie wywołania powłoki. Na przykład:

PATH  := $(PATH):$(PWD)/bin:/my/other/path
SHELL := env PATH=$(PATH) /bin/bash
kenorb
źródło
2
Podoba mi się to podejście!
Alan Franzoni
2
To jest najlepsze, ponieważ działa nawet z $(shell)inwokacjami! : D Przykład: pastebin.com/Pii8pmkD
PsychoX
Na dev.azure otrzymuję: env: 'env': Nie ma takiego pliku lub katalogu; Działa lokalnie; /
Kamil Dziedzic
Nie działa na Debianie 10 z make 4.2: make: env PATH = <ścieżka> / bin / sh: nie znaleziono polecenia. Korzystanie z eksportu. Upewnij się, że używasz $ (HOME) a ​​nie ~ jako ścieżki w katalogu domowym.
MKesper
25

Zmiany ścieżki wydają się być trwałe, jeśli najpierw ustawisz zmienną SHELL w pliku makefile:

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

test all:
    x

Nie wiem, czy jest to pożądane zachowanie, czy nie.

nieokreślony
źródło
To rozwiązało problem, który miałem (używam zsh). Dzięki!
Jezen Thomas,
Tak, to rzeczywiście robi to, czego chciał OP ... ale czy jest to funkcja czy błąd? Nawet po przeczytaniu działu SHELL w instrukcji make nie jestem pewien.
pje
5
Dla mnie to też nie działa. whicha envteraz wybierz nową PATH, ale bezpośrednie wykonanie pliku binarnego nadal nie występuje w zmodyfikowanej PATH, tylko w oryginalnej.
Konrad Rudolph
3

Zwykle jawnie podaję ścieżkę do pliku wykonywalnego:

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

Używam również tej techniki do uruchamiania nienatywnych plików binarnych w emulatorze, takim jak QEMU, jeśli kompiluję krzyżowo:

EXE = qemu-mips ./bin/

Jeśli make używa powłoki sh, to powinno działać:

test all:
    PATH=bin:$PATH x
Richarda Penningtona
źródło
Tak, fajne soulution, jednak mam testy napisane w perlu i muszę wywołać exe ze skryptu perla, a nie bezpośrednio z pliku makefile. Muszę przemyśleć cały test tego materiału :)
Szymon Lipiński
Mam cię. A co powiesz na ustawienie PATH w samym wierszu poleceń? Zobacz edycję powyżej.
Richard Pennington,
-2

Aby ustawić PATHzmienną, tylko w Makefile, użyj czegoś takiego:

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

test:
@echo my new PATH = $(PATH)
karnhick
źródło
To nie działa tak, jak chcę. Zaktualizowałem pytanie o przykłady tego, co chcę osiągnąć.
Szymon Lipiński