Làm thế nào để in ra một biến trong makefile


246

Trong tệp tạo tệp của tôi, tôi có một biến 'NDK_PRO DỰ ÁN', câu hỏi của tôi là làm thế nào tôi có thể in nó ra khi biên dịch?

Tôi đọc Tạo tiếng vang tập tin hiển thị chuỗi "$ PATH" và tôi đã thử:

@echo $(NDK_PROJECT_PATH)
@echo $(value NDK_PROJECT_PATH)

Cả hai cho tôi

"build-local.mk:102: *** missing separator.  Stop."

Có ai biết tại sao nó không làm việc cho tôi không?

Câu trả lời:


221

Bạn có thể in ra các biến khi makefile được đọc (giả sử GNU thực hiện như bạn đã gắn thẻ câu hỏi này một cách thích hợp) bằng phương thức này (với một biến có tên "var"):

$(info $$var is [${var}])

Bạn có thể thêm cấu trúc này vào bất kỳ công thức nào để xem những gì tạo ra sẽ chuyển sang trình bao:

.PHONY: all
all: ; $(info $$var is [${var}])echo Hello world

Bây giờ, những gì xảy ra ở đây là làm cho các cửa hàng lưu trữ toàn bộ công thức ( $(info $$var is [${var}])echo Hello world) dưới dạng một biến đệ quy được mở rộng. Khi make quyết định chạy công thức (ví dụ khi bạn bảo nó xây dựng all), nó sẽ mở rộng biến và sau đó chuyển từng dòng kết quả riêng biệt vào shell.

Vì vậy, trong chi tiết đau đớn:

  • Nó mở rộng $(info $$var is [${var}])echo Hello world
  • Để làm điều này, đầu tiên nó mở rộng $(info $$var is [${var}])
    • $$ trở thành nghĩa đen $
    • ${var}trở thành :-)(nói)
    • Các tác dụng phụ là $var is [:-)]xuất hiện trên tiêu chuẩn ra
    • Việc mở rộng $(info...)mặc dù trống rỗng
  • Làm cho còn lại với echo Hello world
    • Tạo bản in echo Hello worldtrên thiết bị xuất chuẩn trước để cho bạn biết những gì nó sẽ yêu cầu trình bao làm
  • Vỏ in Hello worldtrên thiết bị xuất chuẩn.

2
nó có nên (chấm) .PHONY thay vì PHONY không?
võng

172

Theo hướng dẫn sử dụng GNU Make và cũng được chỉ ra bởi 'bobbogo' trong câu trả lời dưới đây, bạn có thể sử dụng thông tin / cảnh báo / lỗi để hiển thị văn bản.

$(error   text…)
$(warning text…)
$(info    text…)

Để in các biến,

$(error   VAR is $(VAR))
$(warning VAR is $(VAR))
$(info    VAR is $(VAR))

'lỗi' sẽ dừng thực hiện, sau khi hiển thị chuỗi lỗi


Ồ, không biết điều này. Cách tốt hơn tiếng vang, sao chép lệnh trong nhật ký.
đào sâu


44

Nếu bạn chỉ đơn giản muốn một số đầu ra, bạn muốn sử dụng $(info)chính nó. Bạn có thể làm điều đó ở bất cứ đâu trong Makefile và nó sẽ hiển thị khi dòng đó được đánh giá:

$(info VAR="$(VAR)")

Sẽ xuất VAR="<value of VAR>"bất cứ khi nào thực hiện quá trình dòng đó. Hành vi này phụ thuộc rất nhiều vào vị trí, vì vậy bạn phải đảm bảo rằng việc $(info)mở rộng xảy ra SAU mọi thứ có thể sửa đổi $(VAR)đã xảy ra!

Một tùy chọn chung hơn là tạo một quy tắc đặc biệt để in giá trị của biến. Nói chung, các quy tắc được thực thi sau khi các biến được gán, vì vậy điều này sẽ cho bạn thấy giá trị thực sự đang được sử dụng. (Mặc dù, quy tắc có thể thay đổi một biến .) Định dạng tốt sẽ giúp làm rõ biến được đặt là gì và $(flavor)hàm sẽ cho bạn biết loại biến đó là gì. Vì vậy, trong quy tắc này:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*mở rộng đến gốc mà % mô hình khớp với quy tắc.
  • $($*)mở rộng đến giá trị của biến có tên được cho bởi $*.
  • Các []rõ ràng phân định việc mở rộng biến. Bạn cũng có thể sử dụng ""tương tự.
  • $(flavor $*)cho bạn biết nó là loại biến gì LƯU Ý: $(flavor) lấy tên biến và không mở rộng. Vì vậy, nếu bạn nói make print-LDFLAGS, bạn nhận được $(flavor LDFLAGS), đó là những gì bạn muốn.
  • $(info text)cung cấp đầu ra. Tạo các bản in texttrên thiết bị xuất chuẩn của nó như là một hiệu ứng phụ của việc mở rộng. Việc mở rộng $(info)mặc dù là trống rỗng. Bạn có thể nghĩ về nó như thế nào @echo, nhưng quan trọng là nó không sử dụng shell, vì vậy bạn không phải lo lắng về quy tắc trích dẫn shell.
  • @truechỉ có để cung cấp một lệnh cho quy tắc. Không có điều đó, làm cũng sẽ đầu ra print-blah is up to date. Tôi cảm thấy @truerõ ràng hơn rằng nó có nghĩa là không có.

Chạy nó, bạn nhận được

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]

Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ - bạn luôn có thể nhận xét về bài đăng của riêng bạn và khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào . - Từ đánh giá
Năng lượng rồng

Cảm ơn đã xem xét. Tôi hiểu rằng tôi có thể nhận xét một khi tôi có đủ danh tiếng, nhưng tôi nên làm gì trong lúc này? Tôi tin rằng câu trả lời của tôi cung cấp giá trị bổ sung, vì vậy tôi không nên thêm nó?
Jim Nasby

1
Tôi khuyên bạn nên viết lại đây là một câu trả lời độc lập cạnh tranh với câu trả lời mà bạn đang bình luận, thay vì đặt nó như một nhận xét không đúng chỗ cho câu trả lời đó.
Charles Duffy

@JimNasby Vâng, những gì Charles đề nghị. Trên thực tế, nó có thể giúp bắt đầu chỉ đơn giản là loại bỏ phần "xin lỗi không đủ đại diện để bình luận", vì nó là một loại cờ đỏ. Nếu bạn biến nó thành một câu trả lời hoàn chỉnh (có thể chỉnh sửa tất cả những gì bạn thích), thì nó sẽ làm khá tốt. Chúc mừng.
Năng lượng rồng

Tuyệt vời - đây là một câu trả lời tốt hơn nhiều bây giờ. :)
Charles Duffy

6

@echo $ (NDK_PRO DỰ ÁN) là cách tốt để làm điều đó. Tôi không nghĩ rằng lỗi đến từ đó. Nói chung, lỗi này xuất hiện khi bạn nhập sai ý định: Tôi nghĩ rằng bạn có không gian nơi bạn nên có một tab.


2
Tôi đã thử '@echo $ (NDK_PRO DỰ ÁN)', tôi vẫn gặp lỗi "build-local.mk:102: *** thiếu dấu phân cách. Dừng lại." Tôi chỉ có 1 khoảng trắng sau 'echo', không có khoảng trắng hoặc tab nào trước '@echo'.
michael

Bạn có chắc chắn lỗi đến từ dòng này? Là dòng này trong một quy tắc? Cô ấy có lẽ phải được thụt lề ...

6

Tất cả các phiên bản makeyêu cầu các dòng lệnh được thụt lề bằng TAB (không phải khoảng trắng) là ký tự đầu tiên trong dòng. Nếu bạn chỉ cho chúng tôi toàn bộ quy tắc thay vì chỉ hai dòng trong câu hỏi, chúng tôi có thể đưa ra câu trả lời rõ ràng hơn, nhưng nó phải là một cái gì đó như:

myTarget: myDependencies
        @echo hi

trong đó ký tự đầu tiên trong dòng thứ hai phải là TAB.


4

Chạy make -n; nó cho bạn thấy giá trị của biến ..

Làm cho ...

all:
        @echo $(NDK_PROJECT_PATH)

Chỉ huy:

export NDK_PROJECT_PATH=/opt/ndk/project
make -n 

Đầu ra:

echo /opt/ndk/project

Điều này khá hữu ích và tôi sử dụng --just-printtương tự trong Thay vì thực thi
Fredrick Gauss

3

Điều này makefile sẽ tạo ra thông báo lỗi 'thiếu dấu phân cách':

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

Có một tab trước @echo "All done" (mặc dù done:quy tắc và hành động phần lớn là thừa), nhưng không phải trước @echo PATH=$(PATH).

Vấn đề là dòng bắt đầu all phải có dấu hai chấm :hoặc dấu bằng =để chỉ ra rằng đó là dòng đích hoặc dòng macro và không có, vì vậy dấu phân cách bị thiếu.

Hành động lặp lại giá trị của biến phải được liên kết với mục tiêu, có thể là mục tiêu giả hoặc PHONEY. Và dòng đích đó phải có dấu hai chấm trên đó. Nếu bạn thêm một: sau alltrong ví dụ makefilevà thay thế các khoảng trống hàng đầu trên dòng tiếp theo bằng một tab, nó sẽ hoạt động hoàn toàn.

Bạn có thể có một vấn đề tương tự gần dòng 102 trong bản gốc makefile. Nếu bạn đã hiển thị 5 dòng không trống, không bình luận trước các hoạt động tiếng vang không thành công, có thể có thể kết thúc chẩn đoán. Tuy nhiên, vì câu hỏi đã được hỏi vào tháng 5 năm 2013, không chắc makefilelà hiện tại vẫn chưa có sẵn (tháng 8 năm 2014), vì vậy câu trả lời này không thể được xác nhận chính thức. Nó chỉ có thể được sử dụng để minh họa một cách hợp lý trong đó vấn đề xảy ra.


3

Không cần phải sửa đổi Makefile.

$ cat printvars.mak
print-%:
        @echo '$*=$($*)'

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE

2

Vấn đề là echo chỉ hoạt động dưới một khối thực thi. tức là bất cứ điều gì sau "xx:"

Vì vậy, bất cứ điều gì ở trên khối thực thi đầu tiên chỉ là khởi tạo để không có lệnh thực thi nào có thể được sử dụng.

Vì vậy, tạo ra một khối thực thi


1

Điều này có thể được thực hiện theo cách chung chung và có thể rất hữu ích khi gỡ lỗi một tệp thực hiện phức tạp. Theo kỹ thuật tương tự như được mô tả trong câu trả lời khác , bạn có thể chèn đoạn sau vào bất kỳ tệp thực hiện nào:

# if the first command line argument is "print"
ifeq ($(firstword $(MAKECMDGOALS)),print)

  # take the rest of the arguments as variable names
  VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))

  # turn them into do-nothing targets
  $(eval $(VAR_NAMES):;@:))

  # then print them
  .PHONY: print
  print:
          @$(foreach var,$(VAR_NAMES),\
            echo '$(var) = $($(var))';)
endif

Sau đó, bạn chỉ có thể thực hiện "tạo bản in" để kết xuất giá trị của bất kỳ biến nào:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall


0

Nếu bạn không muốn tự sửa đổi Makefile, bạn có thể sử dụng --evalđể thêm mục tiêu mới và sau đó thực hiện mục tiêu mới, ví dụ:

make --eval='print-tests: @echo TESTS $(TESTS) ' print-tests

Bạn có thể chèn ký tự TAB cần thiết vào dòng lệnh bằng cách sử dụng CTRL-V, TAB

ví dụ Makefile từ phía trên:

all: do-something

TESTS=
TESTS+='a'
TESTS+='b'
TESTS+='c'

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1

Tôi đang cố chạy tập lệnh của bạn nhưng tôi gặp lỗimake: *** missing separator. Stop.
Rinaldi Segecin

À, xin lỗi, đã sửa. Thiếu dấu hai chấm ở cuối mục tiêu "kiểm tra in".
lội

Trên thực tế, bạn không cần dòng mới và tab, dấu chấm phẩy sẽ đủ:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo

0

Nếu bạn sử dụng android make (mka) @echo $(NDK_PROJECT_PATH)sẽ không hoạt động và gây ra lỗi cho bạn, hãy *** missing separator. Stop." sử dụng câu trả lời này nếu bạn đang cố in các biến trong android make

NDK_PROJECT_PATH := some_value
$(warning $(NDK_PROJECT_PATH))

điều đó làm việc cho tôi


0

Tôi thường lặp lại với một lỗi nếu tôi muốn xem giá trị biến. (Chỉ khi bạn muốn xem giá trị. Nó sẽ dừng thực thi.)

@echo $ (lỗi NDK_PRO DỰ ÁN = $ (NDK_PRO DỰ ÁN))

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.