Dalam Makefile, deploy
resep membutuhkan variabel lingkungan ENV
untuk diatur agar dapat dieksekusi dengan benar, sedangkan yang lain tidak peduli, misalnya:
ENV =
.PHONY: deploy hello
deploy:
rsync . $(ENV).example.com:/var/www/myapp/
hello:
echo "I don't care about ENV, just saying hello!"
Bagaimana saya bisa memastikan variabel ini diatur, misalnya: apakah ada cara untuk mendeklarasikan variabel makefile ini sebagai prasyarat dari resep deploy, seperti:
deploy: make-sure-ENV-variable-is-set
?
Terima kasih.
make
mengaturnya, atau memberikan peringatan, atau menghasilkan kesalahan fatal?make ENV=dev
tetapi jika ia lupaENV=dev
,deploy
resepnya akan gagal ...Jawaban:
Ini akan menyebabkan kesalahan fatal jika
ENV
tidak terdefinisi dan sesuatu membutuhkannya (dalam GNUM, bagaimanapun juga).(Perhatikan bahwa jikandef dan endif tidak diindentasi - mereka mengontrol apa yang membuat "melihat" , mulai berlaku sebelum Makefile dijalankan. "$ (Kesalahan" diindentasi dengan tab sehingga hanya berjalan dalam konteks aturan.)
sumber
ENV is undefined
ketika menjalankan tugas yang tidak memiliki check-env sebagai prasyarat.check-env
aturan; Make tidak akan memperluasnya kecuali / sampai menjalankan aturan. Jika itu tidak dimulai dengan TAB (seperti dalam contoh @ rane), Jadikan itu sebagai tidak dalam aturan, dan evaluasi sebelum menjalankan aturan apa pun, apa pun targetnya.Anda dapat membuat target pelindung tersirat, yang memeriksa bahwa variabel di batang didefinisikan, seperti ini:
Anda kemudian menambahkan
guard-ENVVAR
target di mana saja Anda ingin menegaskan bahwa suatu variabel didefinisikan, seperti ini:Jika Anda menelepon
make change-hostname
, tanpa menambahkanHOSTNAME=somehostname
panggilan, maka Anda akan mendapatkan kesalahan, dan build akan gagal.sumber
if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi
DVarian sebaris
Di makefile saya, saya biasanya menggunakan ekspresi seperti:
Alasan:
Jangan lupa komentar yang penting untuk debugging:
... memaksa Anda untuk mencari Makefile sementara ...
... menjelaskan secara langsung apa yang salah
Varian global (untuk kelengkapan, tetapi tidak ditanyakan)
Di atas Makefile Anda, Anda juga bisa menulis:
Peringatan:
clean
target akan gagal jika ENV tidak diatur. Kalau tidak, lihat jawaban Hudon yang lebih komplekssumber
@
. -> gnu.org/software/make/manual/make.html#Echoing@test -n "$(name)" || (echo 'A name must be defined for the backup. Ex: make backup name=xyz' && exit 1)
Satu kemungkinan masalah dengan jawaban yang diberikan sejauh ini adalah bahwa urutan ketergantungan pada make tidak didefinisikan. Misalnya, menjalankan:
ketika
target
memiliki beberapa dependensi tidak menjamin bahwa ini akan berjalan dalam urutan tertentu.Solusi untuk ini (untuk memastikan bahwa ENV akan diperiksa sebelum resep dipilih) adalah dengan memeriksa ENV selama pass pertama make, di luar resep apa pun:
Anda dapat membaca tentang berbagai fungsi / variabel yang digunakan di sini dan
$()
hanya cara untuk secara eksplisit menyatakan bahwa kami membandingkan dengan "tidak ada".sumber
Saya menemukan bahwa jawaban terbaik tidak dapat digunakan sebagai persyaratan, kecuali untuk target PHONY lainnya. Jika digunakan sebagai ketergantungan untuk target yang merupakan file aktual, gunakan
check-env
akan memaksa target file untuk dibangun kembali.Jawaban lain bersifat global (mis. Variabel diperlukan untuk semua target di Makefile) atau menggunakan shell, mis. Jika ENV tidak ada, make akan berakhir tanpa mempedulikan target.
Solusi yang saya temukan untuk kedua masalah tersebut adalah
Outputnya seperti
value
memiliki beberapa peringatan menakutkan, tetapi untuk penggunaan sederhana ini saya percaya itu adalah pilihan terbaik.sumber
Seperti yang saya lihat, perintah itu sendiri membutuhkan variabel ENV sehingga Anda dapat memeriksanya dalam perintah itu sendiri:
sumber
deploy
ini bukan satu-satunya resep yang membutuhkan variabel ini. Dengan solusi ini, saya harus menguji keadaanENV
untuk masing-masing ... sementara saya ingin menghadapinya sebagai prasyarat tunggal (semacam).Saya tahu ini sudah tua, tapi saya pikir saya akan berpadu dengan pengalaman saya sendiri untuk pengunjung masa depan, karena itu IMHO sedikit lebih rapi.
Biasanya,
make
akan digunakansh
sebagai shell default ( ditetapkan melaluiSHELL
variabel khusus ). Dish
dan turunannya, sepele untuk keluar dengan pesan kesalahan saat mengambil variabel lingkungan jika tidak disetel atau dibatalkan dengan melakukan:${VAR?Variable VAR was not set or null}
.Memperluas ini, kita dapat menulis target make yang dapat digunakan kembali yang dapat digunakan untuk gagal target lain jika variabel lingkungan tidak ditetapkan:
Hal-hal yang perlu diperhatikan:
$$
) diperlukan untuk menunda ekspansi ke shell alih-alih di dalammake
test
ini hanya untuk mencegah shell dari mencoba mengeksekusi kontenVAR
(tidak ada tujuan signifikan lainnya).check-env-vars
dapat dengan mudah diperluas untuk memeriksa lebih banyak variabel lingkungan, yang masing-masing hanya menambahkan satu baris (misalnya@test $${NEWENV?Please set environment variable NEWENV}
)sumber
ENV
berisi spasi, ini tampaknya gagal (setidaknya untuk saya)Anda dapat menggunakan
ifdef
bukannya target yang berbeda.sumber
deploy
bukan satu-satunya resep yang harus memeriksaENV
variabel keadaan..PHONY: deploy
dandeploy:
sebelum blok ifdef dan hapus duplikasi. (btw saya sudah mengedit jawaban untuk mencerminkan metode yang benar)