Как я могу добавить каталог в $ 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

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.