Làm cách nào để thêm dir vào $ PATH trong Makefile?


87

Tôi muốn viết một Makefile để chạy thử nghiệm. Kiểm tra nằm trong thư mục './tests' và các tệp thực thi được kiểm tra nằm trong thư mục './bin'.

Khi tôi chạy các bài kiểm tra, họ không thấy các tệp thực thi, vì thư mục ./bin không nằm trong $ PATH.

Khi tôi làm điều gì đó như thế này:

EXPORT PATH=bin:$PATH
make test

làm tất cả mọi việc. Tuy nhiên, tôi cần thay đổi $ PATH trong Makefile.

Nội dung Makefile đơn giản:

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

Nó in đường dẫn một cách chính xác, tuy nhiên nó không tìm thấy tệp x.

Khi tôi làm điều này theo cách thủ công:

$ export PATH=bin:$PATH
$ x

mọi thứ đều ổn sau đó.

Làm cách nào để thay đổi $ PATH trong Makefile?


Bạn có thể không chỉ gọi các bài kiểm tra từ thư mục thực thi như thế ../test/test_to_runnào? Xin lỗi nếu tôi đã hiểu sai câu hỏi.
Chris

Tôi muốn tệp này hiển thị bình thường trong các bài kiểm tra. Tôi không muốn chơi với các thư mục, vì tôi cấu trúc lại nó sẽ là một nighmare.
Szymon Lipinski

Cách duy nhất bạn có thể đạt được điều này là yêu cầu makefile viết ra một tập lệnh shell chứa các decls biến và sau đó có mã nguồn shell cha mà tập lệnh đó .. Tuy nhiên, điều này có lẽ là không thực tế.
Michael Smith

Tôi tin rằng unix.stackexchange.com/questions/11530/… là một câu hỏi rất khác (ngu ngốc), không giống như câu hỏi của bạn.
imz - Ivan Zakharyaschev

Câu trả lời:


106

Bạn đã thử exportchỉ thị của Make chính nó (giả sử rằng bạn sử dụng GNU Make)?

export PATH := bin:$(PATH)

test all:
    x

Ngoài ra, có một lỗi trong ví dụ của bạn:

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

Đầu tiên, giá trị được chỉnh sửa echolà sự mở rộng của PATHbiến được thực hiện bởi Make, không phải là shell. Nếu nó in ra giá trị mong đợi thì tôi đoán là bạn đã đặt PATHbiến ở đâu đó trước đó trong Makefile của mình hoặc trong một trình bao gọi Make. Để ngăn chặn hành vi như vậy, bạn nên thoát khỏi đô la:

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

Thứ hai, trong mọi trường hợp, điều này sẽ không hoạt động vì Make thực thi từng dòng của công thức trong một trình bao riêng biệt . Điều này có thể được thay đổi bằng cách viết công thức trong một dòng:

test all:
    export PATH=bin:$$PATH; echo $$PATH; x

7
$(PATH)sẽ được đặt thành giá trị PATHcủa lệnh gọi shell. Theo sách hướng dẫn , "Mọi biến môi trường make thấy khi nó khởi động đều được chuyển đổi thành biến make có cùng tên và giá trị."
Emil Sit

Chỉ thị xuất đã làm việc cho tôi (cảm ơn!), Nhưng chỉ sau khi tôi cài đặt GNU Make 4.3. Trong phiên bản 3,81 (mặc định trên hệ điều hành MacOS Catalina), được cập nhật PATHđược phản ánh một cách chính xác trong các biến ( echo $(PATH)) và trong môi trường lệnh ( env, which python, bash -c python), nhưng dường như không được sử dụng khi định vị các thực thi cho các lệnh: lệnh pythonvẫn chạy Python thực thi trên bản gốc PATH.
doctaphred

27

Bằng cách thiết kế maketrình phân tích cú pháp thực thi các dòng trong một lệnh gọi shell riêng biệt, đó là lý do tại sao thay đổi biến (ví dụ PATH) trong một dòng, thay đổi có thể không được áp dụng cho các dòng tiếp theo (xem bài đăng này ).

Một cách để giải quyết vấn đề này là chuyển đổi nhiều lệnh thành một dòng duy nhất (cách nhau bằng ;), hoặc sử dụng mục tiêu đặc biệt One Shell ( .ONESHELLkể từ GNU Make 3.82).

Ngoài ra, bạn có thể cung cấp PATHbiến tại thời điểm trình bao được gọi. Ví dụ:

PATH  := $(PATH):$(PWD)/bin:/my/other/path
SHELL := env PATH=$(PATH) /bin/bash

2
Tôi thích cách tiếp cận!
Alan Franzoni

2
Điều này là tốt nhất, bởi vì nó hoạt động ngay cả với $(shell)lời gọi! : D Ví dụ: pastebin.com/Pii8pmkD
PsychoX 28/10/17

Trên dev.azure, tôi nhận được: env: 'env': Không có tệp hoặc thư mục nào như vậy; Hoạt động tại địa phương; /
Kamil Dziedzic

Không hoạt động trên Debian 10 với make 4.2: make: env PATH = <path> / bin / sh: Không tìm thấy lệnh. Sử dụng các công trình xuất khẩu. Đảm bảo sử dụng $ (HOME) chứ không phải ~ cho đường dẫn trong nhà.
MKesper

25

Các thay đổi về đường dẫn dường như liên tục nếu bạn đặt biến SHELL trong makefile của mình trước:

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

test all:
    x

Tôi không biết liệu đây có phải là hành vi mong muốn hay không.


Điều này đã khắc phục sự cố tôi đang gặp phải (tôi đang chạy zsh). Cảm ơn!
Jezen Thomas

Vâng, điều này thực sự làm những gì OP muốn ... nhưng nó là một tính năng hay một lỗi? Ngay cả sau khi đọc phần VỎ của sổ tay hướng dẫn sử dụng, tôi không chắc.
pje

5
Điều này cũng không hiệu quả với tôi. whichenvbây giờ chọn PATH mới, nhưng thực thi trực tiếp một nhị phân vẫn không được tìm thấy trong PATH đã sửa đổi, chỉ có trong PATH ban đầu.
Konrad Rudolph

3

Những gì tôi thường làm là cung cấp đường dẫn đến tệp thực thi một cách rõ ràng:

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

Tôi cũng sử dụng kỹ thuật này để chạy các tệp nhị phân không phải gốc trong một trình giả lập như QEMU nếu tôi đang biên dịch chéo:

EXE = qemu-mips ./bin/

Nếu make đang sử dụng vỏ sh, điều này sẽ hoạt động:

test all:
    PATH=bin:$PATH x

Đúng vậy, thật tuyệt, tuy nhiên tôi đã có các bài kiểm tra của mình được viết bằng perl và tôi cần gọi exe từ tập lệnh perl, không phải trực tiếp từ makefile. Tôi phải suy nghĩ lại toàn bộ thử nghiệm của công cụ này :)
Szymon Lipinski

Gotcha. Làm thế nào về việc thiết lập PATH trên chính dòng lệnh? Xem chỉnh sửa ở trên.
Richard Pennington

-2

Để đặt PATHbiến, chỉ trong Makefile, hãy sử dụng một cái gì đó như:

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

test:
@echo my new PATH = $(PATH)

Nó không hoạt động theo cách tôi muốn. Tôi đã cập nhật câu hỏi với các ví dụ về những gì tôi muốn đạt được.
Szymon Lipinski
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.