Xác định biến Makefile bằng biến ENV hoặc giá trị mặc định


78

Tôi đang cố gắng làm một điều đơn giản:

TMPDIR ?= /tmp

test:
    @echo $(TMPDIR)

Điều này hoạt động nếu tôi chạy:

$ make test
/tmp

Nó cũng hoạt động nếu tôi chạy:

$ make test -e TMPDIR=~/tmp
/home/user/tmp

Tôi có thể làm gì để nó cũng hoạt động cho:

$ TMPDIR=~/tmp make test
/home/user/tmp

4
Erhm ... những gì bạn có DOES hoạt động (nếu bạn sử dụng ?=và bạn có một bộ biến môi trường, thì giá trị của biến môi trường sẽ được sử dụng thay thế). Vấn đề chính xác là gì (tại sao bạn nghĩ rằng nó không hoạt động)?
Bác Học Điên

1
Cũng chỉ FYI, thêm dấu ngoặc kép vào các giá trị biến bên trong một tệp trang điểm thường không phải là một ý kiến ​​hay.
Bác Học Điên

Có, tôi đã kiểm tra kỹ và tôi đã làm việc với TMPDIR ?= "/tmp"echo $(TMPDIR)điều duy nhất là không quên dấu ngoặc quanh tên biến.
Natim

1
Bạn có cách sử dụng -engược của bạn . -enói để cho phép env vars ghi đè các biến được xác định trong makefile, chúng không ảnh hưởng đến việc gán biến đến từ các đối số dòng lệnh.
Etan Reisner

1
Xin lỗi Natim, nhưng ?= hiệu quả. Nếu nó không làm những gì bạn muốn thì giải thích của bạn ở trên là khó hiểu và chúng tôi không hiểu bạn muốn gì hoặc có điều gì đó về môi trường thực của bạn không được phản ánh trong câu hỏi của bạn ở trên.
Bác Học Điên

Câu trả lời:


132

Để theo dõi các nhận xét của tôi ở trên, đây là một ví dụ:

T ?= foo
all:
        : '$(T)'

Bây giờ nếu tôi chạy Makefile theo nhiều cách khác nhau, nó sẽ hoạt động như chúng tôi mong đợi (tôi foochỉ nhận được nếu tôi không đặt Ttrên dòng lệnh hoặc môi trường):

$ make
: 'foo'

$ make T=bar
: 'bar'

$ T=bar make
: 'bar'

Đây là all:;:gì:?
Xiphias

3
all:tạo quy tắc cho một mục tiêu tất cả . Dấu chấm phẩy kết thúc danh sách các điều kiện tiên quyết và bắt đầu dòng công thức đầu tiên. Cuối cùng :là công thức; dấu hai chấm là một toán tử shell POSIX đặc biệt có nghĩa là về cơ bản, "không làm gì cả". Vì vậy, điều này xác định một quy tắc đầy đủ cho allmục tiêu có một công thức không làm bất cứ điều gì.
MadScientist,

Tôi thực sự thích định dạng gốc hơn vì nó hoạt động mà không cần phải chuyển đổi khoảng trắng thành tab (thật khó để đặt một TAB cứng thành một ví dụ trong SO). Nhưng tôi đoán những người khác thông qua chỉnh sửa như vậy ...
Bác Học Điên

37

Các biến được chỉ định trên dòng lệnh make ghi đè các giá trị được chỉ định trong makefile :

TMPDIR := "/tmp"
test:
    @echo $(TMPDIR)

Và sau đó:

make TMPDIR=whatever
whatever

Nói chung, thực tiễn xấu là các tệp makefiles phụ thuộc vào các biến môi trường, đây là lý do tại sao việc chuyển các biến trong dòng lệnh make được ưu tiên hơn.


Một cách khác là sử dụng orhàm make :

X := $(or ${X},${X},abc)

all :
    @echo ${X}

make
abc

X=def make 
def

Trên thực tế, bạn chỉ nên sử dụng ?=nhiệm vụ.


1
Ok, điều đó là tốt để biết nhưng làm thế nào tôi có thể sử dụng biến môi trường làm giá trị mặc định nếu được đặt?
Natim

Trong trường hợp cụ thể đó, TMPDIR là một biến có thể tồn tại và tôi muốn sử dụng nếu có.
Natim

Tôi đã thử TMPDIR := $(or $$TMPDIR,$$TMPDIR,"/tmp")nhưng dường như không hiệu quả.
Natim

@Natim Tại sao bạn đặt thêm các ký hiệu đô la?
Maxim Egorushkin

1
Có vẻ như những $(orlời kêu gọi này là nhiều hơn mức cần thiết. Điều này không hoạt động? $(or $X,abc) ?
Ned Batchelder

4

Đây là một giải pháp đơn giản:

SHELL  := env TMPDIR=$(TMPDIR) $(SHELL)
TMPDIR ?= "/tmp"

all:
  @echo $(TMPDIR)

hoạt động cho cả hai trường hợp: TMPDIR=new/path makemake TMPDIR=new/path.


0

Một trong những điều bạn có thể làm là:

TMPDIR := "/tmp"

ifdef $$TMPDIR
TMPDIR := $$TMPDIR
endif

test:
    echo $(TMPDIR)

Nó không hoạt động như TMPDIR=~/tmp make, chỉ khi chạy như make TMPDIR=~/tmp , nhưng câu hỏi là làm cho nó hoạt động cho cả hai.
kenorb
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.