Как я могу добавить каталог в $ PATH в Makefile?

87

Я хочу написать Makefile, который будет запускать тесты. Тесты находятся в каталоге ./tests, а исполняемые файлы, которые нужно протестировать, находятся в каталоге ./bin.

Когда я запускаю тесты, они не видят файлы exec, так как каталога ./bin нет в $ PATH.

Когда я делаю что-то вроде этого:

EXPORT PATH=bin:$PATH
make test

все работает. Однако мне нужно изменить $ PATH в Makefile.

Простое содержимое Makefile:

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

Он правильно печатает путь, но не находит файл x.

Когда я делаю это вручную:

$ export PATH=bin:$PATH
$ x

тогда все ок.

Как я могу изменить $ PATH в Makefile?

Шимон Липиньски
источник
А нельзя просто тесты из исполняемого каталога вроде ../test/test_to_run? Извините, если я неправильно понял вопрос.
Крис
Я хочу, чтобы этот файл был нормально виден тестам. Я не хочу играть с каталогами, так как рефакторинг для меня был бы кошмаром.
Szymon Lipiński
Единственный способ приблизиться к этому - заставить make-файл записать сценарий оболочки, содержащий переменную decls, а затем получить родительский источник оболочки, с которым этот сценарий .. Однако это, вероятно, непрактично.
Майкл Смит
Я считаю, что unix.stackexchange.com/questions/11530/… - это совсем другой (глупый) вопрос, в отличие от вашего.
imz - Иван Захарящев

Ответы:

106

Вы пробовали использовать exportдирективу Make (при условии, что вы используете GNU Make)?

export PATH := bin:$(PATH)

test all:
    x

Кроме того, в вашем примере есть ошибка:

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

Во-первых, редактируемое значение echo- это расширение PATHпеременной, выполняемое Make, а не оболочкой. Если он печатает ожидаемое значение, то, я полагаю, вы установили PATHпеременную где-то раньше в вашем Makefile или в оболочке, которая вызвала Make. Чтобы предотвратить такое поведение, вам следует избегать долларов:

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

Во-вторых, в любом случае это не сработает, потому что Make выполняет каждую строку рецепта в отдельной оболочке . Это можно изменить, записав рецепт в одну строку:

test all:
    export PATH=bin:$$PATH; echo $$PATH; x
Эльдар Абусалимов
источник
7
$(PATH)будет установлено значение PATHоболочки, вызывающей make. Согласно руководству : «Каждая переменная среды, которую видит программа make при запуске, преобразуется в переменную make с тем же именем и значением».
Emil Sit
Директива экспорта у меня сработала (спасибо!), Но только после того, как я установил GNU Make 4.3. В версии 3.81 (по умолчанию на MacOS Catalina), обновленный PATHправильно отражено в переменных ( echo $(PATH)) и в среде команд ( env, which python, bash -c python), но , кажется, не будет использоваться при поиске исполняемого файла для команды: команда pythonвсе еще бежит Исполняемый файл Python на оригинале PATH.
doctaphred
27

По задумке makeпарсер выполняет строки в отдельных вызовах оболочки, поэтому при изменении переменной (например PATH) в одной строке изменение может не применяться для следующих строк (см. Этот пост ).

Один из способов решения этой проблемы - преобразовать несколько команд в одну строку (разделенных символом ;) или использовать специальную цель One Shell ( .ONESHELLкак в GNU Make 3.82).

В качестве альтернативы вы можете указать PATHпеременную во время вызова оболочки. Например:

PATH  := $(PATH):$(PWD)/bin:/my/other/path
SHELL := env PATH=$(PATH) /bin/bash
Kenorb
источник
2
Мне нравится подход!
Алан Франзони
2
Это лучший вариант, потому что работает даже с $(shell)вызовами! : D Пример: pastebin.com/Pii8pmkD
PsychoX
На dev.azure я получаю: env: 'env': такого файла или каталога нет; Работает локально; /
Камил Дзедзич
Не работает в Debian 10 с make 4.2: make: env PATH = <path> / bin / sh: Команда не найдена. Использование экспорта работает. Обязательно используйте $ (HOME), а не ~ для пути в домашнем каталоге.
MKesper,
25

Изменения пути кажутся постоянными, если вы сначала установите переменную SHELL в вашем make-файле:

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

test all:
    x

Я не знаю, желаемое ли это поведение или нет.

недооцененный
источник
Это устранило мою проблему (я использую zsh). Благодарность!
Jezen Thomas
Да, это действительно то, что хотел OP ... но это функция или ошибка? Даже после прочтения раздела SHELL в руководстве make я не уверен.
pje
5
У меня это тоже не работает. whichи envтеперь выберите новый PATH, но прямое выполнение двоичного файла все еще не найдено в измененном PATH, а только в исходном.
Конрад Рудольф
3

Обычно я указываю путь к исполняемому файлу явно:

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

Я также использую этот метод для запуска неродных двоичных файлов под эмулятором, например QEMU, если я выполняю кросс-компиляцию:

EXE = qemu-mips ./bin/

Если make использует оболочку sh, это должно сработать:

test all:
    PATH=bin:$PATH x
Ричард Пеннингтон
источник
Да, круто, но у меня есть тесты, написанные на Perl, и мне нужно вызывать exe из скрипта perl, а не напрямую из make-файла. Я должен переосмыслить все тестирование этого материала :)
Szymon Lipiński
Попался. Как насчет установки PATH в самой командной строке? См. Правку выше.
Ричард Пеннингтон,
-2

Чтобы установить PATHпеременную только в Makefile, используйте что-то вроде:

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

test:
@echo my new PATH = $(PATH)
Карнхик
источник
Это не работает так, как я хочу. Я обновил вопрос примерами того, чего я хочу достичь.
Szymon Lipiński