Truyền các biến bổ sung từ dòng lệnh để thực hiện


614

Tôi có thể chuyển các biến cho GNU Makefile làm đối số dòng lệnh không? Nói cách khác, tôi muốn chuyển một số đối số mà cuối cùng sẽ trở thành các biến trong Makefile.

Câu trả lời:


754

Bạn có một số tùy chọn để thiết lập các biến từ bên ngoài tệp thực hiện của mình:

  • Từ môi trường - mỗi biến môi trường được chuyển thành biến makefile có cùng tên và giá trị.

    Bạn cũng có thể muốn thiết lập -etùy chọn (aka --environments-override) trên, và các biến môi trường của bạn sẽ ghi đè lên tập làm thành makefile (trừ những bài tập mình sử dụng overridechỉ thị . Tuy nhiên, nó không được khuyến khích, và nó tốt hơn nhiều và linh hoạt để sử dụng ?=chuyển nhượng (biến có điều kiện toán tử gán, nó chỉ có hiệu lực nếu biến chưa được xác định):

    FOO?=default_value_if_not_set_in_environment
    

    Lưu ý rằng các biến nhất định không được kế thừa từ môi trường:

    • MAKE được lấy từ tên của kịch bản
    • SHELLđược đặt trong tệp tạo tệp hoặc mặc định là /bin/sh(lý do: các lệnh được chỉ định trong tệp tạo tệp và chúng là đặc trưng cho vỏ).
  • Từ dòng lệnh - makecó thể thực hiện các nhiệm vụ thay đổi như một phần của dòng lệnh của mình, trộn lẫn với các mục tiêu:

    make target FOO=bar
    

    Nhưng sau đó tất cả các bài tập để FOObiến trong makefile sẽ bị bỏ qua trừ khi bạn sử dụng các overridechỉ thị trong chuyển nhượng. (Hiệu ứng này giống như với -etùy chọn cho các biến môi trường).

  • Xuất từ ​​cha mẹ Make - nếu bạn gọi Make từ Makefile, bạn thường không nên viết rõ ràng các bài tập biến như thế này:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    Thay vào đó, giải pháp tốt hơn có thể là xuất các biến này. Việc xuất một biến làm cho nó vào môi trường của mọi lệnh gọi shell và Thực hiện các cuộc gọi từ các lệnh này chọn các biến môi trường này như được chỉ định ở trên.

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    

    Bạn cũng có thể xuất tất cả các biến bằng cách sử dụng exportmà không cần đối số.


11
để vượt qua khỏi dòng lệnh một cái gì đó với không gian làmmake A='"as df"'
Ciro Santilli 冠状 病 六四 事件

4
Có vẻ như bạn đang yêu cầu rắc rối nếu bạn quan tâm đến các biến môi trường. Đối với một điều, đó là một cơn ác mộng gỡ lỗi nếu nó hoạt động ở vị trí A và không ở vị trí B, chỉ vì chúng có môi trường khác nhau.
James Moore

12
Chỉ dựa trên kinh nghiệm, xuất khẩu những thứ như CFLAGS là một công thức cho cơn ác mộng cho các dự án lớn. Các dự án lớn thường có thư viện bên thứ 3 chỉ biên dịch với một bộ cờ nhất định (không ai sửa cả). Nếu bạn xuất CFLAGS, CFLAGS của dự án của bạn sẽ ghi đè lên thư viện của bên thứ 3 và gây ra lỗi biên dịch. Một cách khác có thể là xác định export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)và chuyển nó theo make -C folder $(PROJECT_MAKE_FLAGS). Nếu có một cách để nói với thư viện của bạn bỏ qua môi trường, thì đó là lý tưởng (ngược lại với -e).
RD

24
CẢNH BÁO: Trong phần "Xuất từ ​​cha mẹ Make" ở trên, "Đừng làm điều này!" là phê phán sai lầm . Truyền các biến trên dòng lệnh sẽ ghi đè các phép gán trong tệp tạo tệp phụ nhưng các biến được xuất không ghi đè các phép gán trong tệp tạo tệp phụ. Hai phương thức này để truyền biến cho một tệp con thực hiện không tương đương và không nên nhầm lẫn.
Jonathan Ben-Avraham

4
Bất kỳ sự khác biệt ? make target FOO=bar make FOO=bar target?
gfan

213

Cách đơn giản nhất là:

make foo=bar target

Sau đó, trong makefile của bạn, bạn có thể tham khảo $(foo). Lưu ý rằng điều này sẽ không lan truyền đến các phụ bản tự động.

Nếu bạn đang sử dụng các sản phẩm phụ, hãy xem bài viết này: Truyền đạt các biến đến một sản phẩm phụ


2
bởi phụ làm cho bạn có nghĩa là các makefile includedtrong makefile chính?
Pablo

2
@Michael: Có nghĩa là gọi lại từ bên trong makefile. Tôi đã cập nhật câu trả lời của tôi vì bạn có vẻ quan tâm đến chi tiết này.
Mark Byers

2
"Lưu ý rằng điều này sẽ không lan truyền đến các phụ bản tự động." Không đúng sự thật! "Theo mặc định, chỉ các biến xuất phát từ môi trường hoặc dòng lệnh được truyền cho các lệnh đệ quy. Bạn có thể sử dụng lệnh xuất để truyền các biến khác." gnu.org/software/make/manual/html_node/...
ThomasMcLeod

82

Giả sử bạn có một tệp thực hiện như thế này:

action:
    echo argument is $(argument)

Sau đó bạn sẽ gọi nó make action argument=something


5
vậy mục tiêu và đối số có thể thay thế cho nhau về vị trí?
Pablo

4
@Michael: Có (xem câu trả lời của Mark Byers)
nc3b

25

Từ hướng dẫn :

Các biến trong make có thể đến từ môi trường mà make được chạy. Mỗi biến môi trường tạo ra khi nhìn thấy nó khởi động được chuyển thành biến tạo có cùng tên và giá trị. Tuy nhiên, một gán rõ ràng trong tệp thực hiện hoặc với một đối số lệnh, sẽ ghi đè môi trường.

Vì vậy, bạn có thể làm (từ bash):

FOOBAR=1 make

dẫn đến một biến FOOBARtrong Makefile của bạn.


2
Cách khác thực sự tốt hơn trong hầu hết các trường hợp. Tôi sẽ để nó ở đây cho đầy đủ.
Thomas

Đây là câu trả lời duy nhất cho thấy việc gán biến trước lệnh make trên cùng một dòng - đáng để biết đây không phải là lỗi cú pháp.
M_M

7

Có một tùy chọn khác không được trích dẫn ở đây, được bao gồm trong cuốn sách GNU Make của Stallman và McGrath (xem http://www.oolie.fu-berlin.de/oolnet/use/info/make/make_7.html ). Nó cung cấp ví dụ:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

Nó liên quan đến việc xác minh nếu một tham số nhất định xuất hiện trong MAKEFLAGS. Ví dụ: giả sử bạn đang nghiên cứu về các chủ đề trong c ++ 11 và bạn đã chia nghiên cứu của mình qua nhiều tệp ( class01, ..., classNM) và bạn muốn: biên dịch tất cả và chạy riêng lẻ hoặc biên dịch từng tệp tại một thời gian và chạy nó nếu một cờ được chỉ định ( -rví dụ). Vì vậy, bạn có thể đưa ra những điều sau đây Makefile:

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o $@.out $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./$@.out
endif

all: $(SOURCES)

.PHONY: clean

clean:
    find . -name "*.out" -delete

Có điều đó, bạn:

  • xây dựng và chạy một tập tin w / make -r class02;
  • xây dựng tất cả w / makehoặc make all;
  • xây dựng và chạy tất cả w / make -r(giả sử rằng tất cả chúng đều chứa một số loại xác nhận nhất định và bạn chỉ muốn kiểm tra tất cả)

6

dường như

lệnh args ghi đè biến môi trường

Makefile

send:
    echo $(MESSAGE1) $(MESSAGE2)

Chạy ví dụ

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK

5

Nếu bạn tạo một tệp có tên Makefile và thêm một biến như $ này (không đáng tin nhất) thì bạn sẽ có thể sử dụng biến này bên trong Makefile ngay cả với các ký tự đại diện

thí dụ :

make unittest=*

Tôi sử dụng BOOST_TEST và bằng cách đưa ký tự đại diện cho tham số --run_test = $ (unittest), sau đó tôi sẽ có thể sử dụng biểu thức chính quy để lọc thử nghiệm mà tôi muốn Makefile của mình chạy


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.