TL; DR đừng cố làm điều này
$ make run arg
thay vì tạo tập lệnh:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
và làm điều này:
$ ./buildandrunprog.sh arg
trả lời cho câu hỏi đã nêu:
bạn có thể sử dụng một biến trong công thức
run: prog
./prog $(var)
sau đó chuyển một phép gán biến làm đối số để thực hiện
$ make run var=arg
Điều này sẽ thực thi ./prog arg
.
nhưng hãy cẩn thận với những cạm bẫy. tôi sẽ giải thích chi tiết về những cạm bẫy của phương pháp này và các phương pháp khác.
trả lời cho ý định giả định đằng sau câu hỏi:
giả định: bạn muốn chạy prog
với một số đối số nhưng phải xây dựng lại trước khi chạy nếu cần thiết.
Câu trả lời: tạo một kịch bản xây dựng lại nếu cần thiết sau đó chạy prog với args
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
kịch bản này làm cho ý định rất rõ ràng. nó sử dụng make để làm những gì nó tốt cho: xây dựng. nó sử dụng tập lệnh shell để làm những gì tốt cho: xử lý hàng loạt.
cộng với bạn có thể làm bất cứ điều gì khác mà bạn có thể cần với sự linh hoạt và biểu cảm hoàn toàn của một tập lệnh shell mà không cần tất cả sự cẩn thận của một tập tin.
Ngoài ra cú pháp gọi bây giờ giống hệt như thực tế:
$ ./buildandrunprog.sh foo "bar baz"
so với:
$ ./prog foo "bar baz"
tương phản với
$ make run var="foo bar\ baz"
lý lịch:
make không được thiết kế để truyền đối số cho mục tiêu. tất cả các đối số trên dòng lệnh được hiểu là mục tiêu (còn gọi là mục tiêu), dưới dạng tùy chọn hoặc dưới dạng gán.
Vì vậy, nếu bạn chạy này:
$ make run foo --wat var=arg
thực hiện sẽ giải thích run
và foo
như là mục tiêu (mục tiêu) để cập nhật theo công thức nấu ăn của họ. --wat
như là một lựa chọn để thực hiện. và var=arg
như một sự phân công biến.
để biết thêm chi tiết, xem: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
để biết thuật ngữ, hãy xem: https://www.gnu.org/software/make/manual/html_node/Rule-Intributiontion.html#Rule-Int sinhtion
về phương pháp gán biến và tại sao tôi khuyên bạn nên chống lại nó
$ make run var=arg
và biến trong công thức
run: prog
./prog $(var)
đây là cách "chính xác" và đơn giản nhất để truyền các đối số vào một công thức. nhưng trong khi nó có thể được sử dụng để chạy một chương trình với các đối số thì chắc chắn nó không được thiết kế để sử dụng theo cách đó. xem https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
theo tôi điều này có một nhược điểm lớn: những gì bạn muốn làm là chạy prog
theo lập luận arg
. nhưng thay vì viết:
$ ./prog arg
bạn đang viết:
$ make run var=arg
điều này càng trở nên khó xử hơn khi cố gắng vượt qua nhiều đối số hoặc đối số có chứa khoảng trắng:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
so với:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
Đối với hồ sơ, đây là những gì tôi prog
trông giống như:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
cũng lưu ý rằng bạn không nên đặt $(var)
dấu ngoặc kép trong tệp thực hiện:
run: prog
./prog "$(var)"
bởi vì sau đó prog
sẽ luôn chỉ nhận được một đối số:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
tất cả điều này là lý do tại sao tôi đề nghị chống lại tuyến đường này.
để hoàn thiện, đây là một số phương pháp khác để "truyền đối số để chạy".
phương pháp 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
giải thích siêu ngắn: lọc ra mục tiêu hiện tại từ danh sách các mục tiêu. tạo bắt tất cả mục tiêu ( %
) mà không có gì để âm thầm bỏ qua các mục tiêu khác.
phương pháp 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
giải thích siêu ngắn: nếu mục tiêu là run
sau đó loại bỏ mục tiêu đầu tiên và tạo ra mục tiêu không làm gì cho các mục tiêu còn lại sử dụng eval
.
cả hai sẽ cho phép bạn viết một cái gì đó như thế này
$ make run arg1 arg2
để giải thích sâu hơn, hãy nghiên cứu hướng dẫn sử dụng: https://www.gnu.org/software/make/manual/html_node/index.html
vấn đề của phương pháp 1:
các đối số bắt đầu bằng dấu gạch ngang sẽ được diễn giải bằng cách thực hiện và không được thông qua dưới dạng mục tiêu.
$ make run --foo --bar
cách giải quyết
$ make run -- --foo --bar
các đối số có dấu bằng sẽ được giải thích bằng cách thực hiện và không được thông qua
$ make run foo=bar
không có cách giải quyết
tranh luận với không gian là khó xử
$ make run foo "bar\ baz"
không có cách giải quyết
nếu một đối số xảy ra là run
(bằng với mục tiêu) thì nó cũng sẽ bị xóa
$ make run foo bar run
sẽ chạy ./prog foo bar
thay vì./prog foo bar run
giải pháp có thể với phương pháp 2
nếu một đối số là mục tiêu hợp pháp thì nó cũng sẽ được chạy.
$ make run foo bar clean
sẽ chạy ./prog foo bar clean
nhưng cũng là công thức cho mục tiêu clean
(giả sử nó tồn tại).
giải pháp có thể với phương pháp 2
Khi bạn gõ nhầm một mục tiêu hợp pháp, nó sẽ bị bỏ qua một cách âm thầm vì bắt tất cả mục tiêu.
$ make celan
Sẽ chỉ âm thầm làm ngơ celan
.
cách giải quyết là làm cho mọi thứ dài dòng. để bạn thấy những gì xảy ra nhưng điều đó tạo ra rất nhiều tiếng ồn cho đầu ra hợp pháp.
vấn đề của phương pháp 2:
nếu một đối số có cùng tên với một mục tiêu hiện có thì thực hiện sẽ in một cảnh báo rằng nó đang bị ghi đè.
không có cách giải quyết mà tôi biết
các đối số có dấu bằng sẽ vẫn được giải thích bằng cách thực hiện và không được thông qua
không có cách giải quyết
tranh luận với không gian vẫn còn lúng túng
không có cách giải quyết
đối số với phá vỡ không gian eval
cố gắng tạo ra không làm gì mục tiêu.
cách giải quyết: tạo ra toàn cầu bắt tất cả các mục tiêu không làm gì như trên. với vấn đề như trên, nó sẽ lại âm thầm bỏ qua các mục tiêu hợp pháp bị đánh lừa.
nó sử dụng eval
để sửa đổi tệp thực hiện trong thời gian chạy. bạn có thể tệ hơn bao nhiêu về khả năng đọc và gỡ lỗi và Nguyên tắc ít ngạc nhiên nhất .
cách giải quyết: không làm điều này !! 1 thay vào đó hãy viết một tập lệnh shell chạy và sau đó chạy prog
.
tôi chỉ thử nghiệm bằng cách sử dụng gnu. làm cho khác có thể có hành vi khác nhau.
TL; DR đừng cố làm điều này
$ make run arg
thay vì tạo tập lệnh:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
và làm điều này:
$ ./buildandrunprog.sh arg