Cara mencetak variabel di makefile

246

Dalam makefile saya, saya memiliki variabel 'NDK_PROJECT_PATH', pertanyaan saya adalah bagaimana saya bisa mencetaknya saat dikompilasi?

Saya membaca Make file echo yang menampilkan string "$ PATH" dan saya mencoba:

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

Keduanya memberi saya

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

Adakah yang tahu mengapa itu tidak berhasil untuk saya?

michael
sumber

Jawaban:

222

Anda dapat mencetak variabel saat makefile dibaca (dengan asumsi GNU make seperti Anda menandai pertanyaan ini dengan tepat) menggunakan metode ini (dengan variabel bernama "var"):

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

Anda bisa menambahkan konstruksi ini ke resep apa saja untuk melihat apa yang akan lolos ke shell:

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

Sekarang, apa yang terjadi di sini adalah membuat menyimpan seluruh resep ( $(info $$var is [${var}])echo Hello world) sebagai variabel tunggal yang diperluas secara rekursif. Ketika make memutuskan untuk menjalankan resep (misalnya ketika Anda memintanya untuk membangun all), itu memperluas variabel, dan kemudian melewati setiap baris yang dihasilkan secara terpisah ke shell.

Jadi, dalam detail yang menyakitkan:

  • Itu mengembang $(info $$var is [${var}])echo Hello world
  • Untuk melakukan ini pertama-tama mengembang $(info $$var is [${var}])
    • $$ menjadi literal $
    • ${var}menjadi :-)(katakanlah)
    • Efek sampingnya adalah yang $var is [:-)]muncul pada standar out
    • Perluasan $(info...)meskipun kosong
  • Buat dibiarkan echo Hello world
    • Buat cetakan echo Hello worldpada stdout terlebih dahulu untuk memberi tahu Anda apa yang harus dilakukan shell
  • Shell mencetak Hello worldpada stdout.
bobbogo
sumber
2
haruskah itu (dot) .PHONY bukannya PHONY?
hammadian
172

Sesuai manual GNU Make dan juga ditunjukkan oleh 'bobbogo' pada jawaban di bawah ini, Anda dapat menggunakan info / peringatan / kesalahan untuk menampilkan teks.

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

Untuk mencetak variabel,

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

'error' akan menghentikan eksekusi make , setelah menunjukkan string kesalahan

kesembuhan
sumber
Wow, tidak tahu ini. Jauh lebih baik daripada gema, yang menduplikasi perintah dalam log.
deepelement
148

dari "Mr. Make post" https://www.cmcrossroads.com/article/printing-value-makefile-variable

Tambahkan aturan berikut ke Makefile Anda:

print-%  : ; @echo $* = $($*)

Kemudian, jika Anda ingin mengetahui nilai variabel makefile, cukup:

make print-VARIABLE

dan itu akan kembali:

VARIABLE = the_value_of_the_variable
Anthony Earl Wong
sumber
Anda menjelaskannya lebih baik daripada penulis. Jempolan!
f0nzie
44

Jika Anda hanya ingin beberapa keluaran, Anda ingin menggunakannya $(info)dengan sendirinya. Anda dapat melakukannya di mana saja di Makefile, dan itu akan ditampilkan ketika garis itu dievaluasi:

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

Akan ditampilkan VAR="<value of VAR>"setiap kali membuat proses garis itu. Perilaku ini sangat bergantung pada posisi, jadi Anda harus memastikan bahwa $(info)ekspansi terjadi SETELAH semua yang dapat memodifikasi $(VAR)telah terjadi!

Opsi yang lebih umum adalah membuat aturan khusus untuk mencetak nilai variabel. Secara umum, aturan dijalankan setelah variabel ditugaskan, jadi ini akan menunjukkan kepada Anda nilai yang sebenarnya sedang digunakan. (Meskipun, ada kemungkinan aturan mengubah variabel .) Pemformatan yang baik akan membantu memperjelas variabel apa yang diatur, dan $(flavor)fungsi akan memberi tahu Anda seperti apa variabel itu. Jadi dalam aturan ini:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*memperluas ke batang yang cocok dengan % pola dalam aturan.
  • $($*)memperluas ke nilai variabel yang namanya diberikan oleh $*.
  • The [dan ]secara jelas menggambarkan ekspansi variabel. Anda juga bisa menggunakan "dan "atau serupa.
  • $(flavor $*)memberi tahu Anda apa jenis variabelnya. CATATAN: $(flavor) mengambil nama variabel , dan bukan ekspansi. Jadi jika Anda berkata make print-LDFLAGS, Anda dapatkan $(flavor LDFLAGS), itulah yang Anda inginkan.
  • $(info text)memberikan output. Jadikan cetakan textpada stdout sebagai efek samping dari ekspansi. Perluasan $(info)meskipun kosong. Anda bisa memikirkannya seperti itu @echo, tetapi yang penting itu tidak menggunakan shell, jadi Anda tidak perlu khawatir tentang aturan mengutip shell.
  • @trueapakah ada hanya untuk memberikan perintah untuk aturan. Tanpa itu, make juga akan di-output print-blah is up to date. Saya merasa @truemembuatnya lebih jelas bahwa itu dimaksudkan sebagai larangan.

Menjalankannya, Anda dapatkan

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]
Jim Nasby
sumber
Ini tidak memberikan jawaban untuk pertanyaan itu. Untuk mengkritik atau meminta klarifikasi dari penulis, tinggalkan komentar di bawah posting mereka - Anda selalu dapat mengomentari posting Anda sendiri, dan setelah Anda memiliki reputasi yang cukup, Anda akan dapat mengomentari posting apa pun . - Dari Ulasan
Dragon Energy
Terima kasih atas ulasannya. Saya mengerti bahwa saya dapat berkomentar setelah saya memiliki reputasi yang cukup, tetapi apa yang harus saya lakukan sementara itu? Saya yakin jawaban saya memberikan nilai tambahan, jadi tidakkah saya harus menambahkannya?
Jim Nasby
1
Saya sarankan menulis ulang ini menjadi jawaban mandiri yang bersaing dengan jawaban yang Anda komentari, daripada mengutarakannya sebagai komentar yang tidak pada tempatnya untuk jawaban itu.
Charles Duffy
@ JimNasby Ya, apa yang disarankan Charles. Sebenarnya itu mungkin membantu sebagai permulaan untuk hanya menghapus bagian "maaf tidak cukup untuk berkomentar", karena itu semacam bendera merah. Jika Anda mengubahnya menjadi jawaban yang lengkap (dapat mengeditnya sesuka Anda), itu harus dilakukan dengan cukup baik. Bersulang.
Dragon Energy
Luar biasa - ini adalah jawaban yang jauh lebih baik sekarang. :)
Charles Duffy
6

@echo $ (NDK_PROJECT_PATH) adalah cara yang baik untuk melakukannya. Saya tidak berpikir kesalahan itu berasal dari sana. Secara umum kesalahan ini muncul ketika Anda salah mengetik niat: Saya pikir Anda memiliki spasi di mana Anda harus memiliki tab.


sumber
2
Saya mencoba '@echo $ (NDK_PROJECT_PATH)', saya masih mendapatkan kesalahan "build-local.mk:102: pemisah yang hilang. Hentikan.". Saya hanya punya 1 spasi setelah 'echo', tidak ada spasi atau tab sebelum '@echo'.
michael
Apakah Anda yakin kesalahan berasal dari baris ini? Apakah garis ini sesuai aturan? Dia mungkin harus diindentasi ...
6

Semua versi makemengharuskan baris perintah diindentasi dengan TAB (bukan spasi) sebagai karakter pertama dalam baris. Jika Anda menunjukkan kepada kami seluruh aturan alih-alih hanya dua baris yang dipermasalahkan, kami dapat memberikan jawaban yang lebih jelas, tetapi harus berupa:

myTarget: myDependencies
        @echo hi

di mana karakter pertama di baris kedua harus TAB.

Ilmuwan gila
sumber
4

Jalankan make -n; ini menunjukkan kepada Anda nilai variabel ..

Makefile ...

all:
        @echo $(NDK_PROJECT_PATH)

Perintah:

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

Keluaran:

echo /opt/ndk/project
ivandcl
sumber
Ini cukup berguna dan saya gunakan --just-printadalah sama di Alih-alih Eksekusi
Fredrick Gauss
3

Ini makefileakan menghasilkan pesan kesalahan 'pemisah yang hilang':

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

Ada tab sebelum @echo "All done"(meskipun done:aturan dan tindakan sebagian besar berlebihan), tetapi tidak sebelum @echo PATH=$(PATH).

Masalahnya adalah bahwa garis awal allharus memiliki titik dua :atau sama dengan =untuk menunjukkan bahwa itu adalah garis target atau garis makro, dan tidak memiliki keduanya, sehingga pemisah tidak ada.

Tindakan yang menggemakan nilai variabel harus dikaitkan dengan target, mungkin target dummy atau PHONEY. Dan garis target itu harus memiliki titik dua di atasnya. Jika Anda menambahkan :setelah alldalam contoh makefiledan mengganti kosong di baris berikutnya dengan tab, itu akan berfungsi dengan baik.

Anda mungkin memiliki masalah analog di dekat baris 102 dalam dokumen asli makefile. Jika Anda menunjukkan 5 baris non-kosong, non-komentar sebelum operasi gema yang gagal, mungkin akan mungkin untuk menyelesaikan diagnosis. Namun, sejak pertanyaan diajukan pada Mei 2013, kecil kemungkinan kerusakan makefilemasih tersedia sekarang (Agustus 2014), jadi jawaban ini tidak dapat divalidasi secara resmi. Ini hanya dapat digunakan untuk menggambarkan cara yang masuk akal di mana masalah terjadi.

Jonathan Leffler
sumber
3

Tidak perlu memodifikasi Makefile.

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

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

Masalahnya adalah bahwa gema hanya berfungsi di bawah blok eksekusi. yaitu apa saja setelah "xx:"

Jadi apapun di atas blok eksekusi pertama hanya inisialisasi sehingga tidak ada perintah eksekusi yang dapat digunakan.

Jadi buat blok eksekusi

Andy
sumber
1

Ini bisa dilakukan dengan cara yang umum dan bisa sangat berguna ketika men-debug makefile yang kompleks. Mengikuti teknik yang sama seperti yang dijelaskan dalam jawaban lain , Anda bisa memasukkan yang berikut ini ke makefile apa pun:

# 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

Kemudian Anda bisa melakukan "cetak" untuk membuang nilai variabel apa pun:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall
Idelic
sumber
0

Jika Anda tidak ingin memodifikasi Makefile itu sendiri, Anda dapat menggunakan --evaluntuk menambahkan target baru, dan kemudian menjalankan target baru, misalnya

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

Anda dapat memasukkan karakter TAB yang diperlukan di baris perintah menggunakan CTRL-V, TAB

contoh Makefile dari atas:

all: do-something

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

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1
Menyeberang
sumber
Saya mencoba menjalankan skrip Anda tetapi saya mendapatkan kesalahanmake: *** missing separator. Stop.
Rinaldi Segecin
Ah, maaf, sudah diperbaiki. Tanda titik dua tidak ada pada akhir target "tes-cetak".
Wade
Sebenarnya Anda tidak perlu baris baru dan tab, tanda titik koma sudah cukup:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo
0

jika Anda menggunakan android make (mka) @echo $(NDK_PROJECT_PATH)tidak akan berfungsi dan memberi Anda kesalahan, *** missing separator. Stop." gunakan jawaban ini jika Anda mencoba mencetak variabel di android make

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

itu berhasil untuk saya

mjalil
sumber
0

Saya biasanya echo dengan kesalahan jika saya ingin melihat nilai variabel. (Hanya jika Anda ingin melihat nilai. Ini akan menghentikan eksekusi.)

@echo $ (kesalahan NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

Abdul Jaleel
sumber