Bagaimana cara memeriksa apakah suatu program dapat dipanggil dari Makefile?
(Artinya, program harus ada di jalur atau bisa dipanggil.)
Ini bisa digunakan untuk memeriksa kompiler mana yang diinstal, misalnya.
Misalnya pertanyaan seperti ini , tetapi tanpa mengasumsikan shell yang mendasarinya kompatibel dengan POSIX.
automake
skrip yang memeriksa berbagai prasyarat dan menulis yang sesuaiMakefile
.Jawaban:
Terkadang Anda memerlukan Makefile agar dapat berjalan di OS target yang berbeda dan Anda ingin build tersebut gagal lebih awal jika executable yang diperlukan tidak ada
PATH
daripada dijalankan dalam waktu yang mungkin lama sebelum gagal.Solusi terbaik yang diberikan oleh engineerchuan membutuhkan pembuatan target . Namun, jika Anda memiliki banyak executable untuk diuji dan Makefile Anda memiliki banyak target independen, yang masing-masing memerlukan pengujian, maka setiap target memerlukan target pengujian sebagai dependensi. Itu menghasilkan banyak pengetikan tambahan serta waktu pemrosesan ketika Anda membuat lebih dari satu target pada satu waktu.
Solusi yang disediakan oleh 0xf dapat menguji executable tanpa membuat target. Itu menghemat banyak waktu pengetikan dan eksekusi ketika ada beberapa target yang dapat dibangun secara terpisah atau bersama-sama.
Perbaikan saya untuk solusi yang terakhir adalah dengan menggunakan yang
which
dapat dieksekusi (where
di Windows), daripada mengandalkan adanya--version
opsi di setiap yang dapat dieksekusi, langsung diifeq
direktif GNU Make , daripada untuk menentukan variabel baru, dan untuk menggunakan GNU Makeerror
berfungsi untuk menghentikan build jika executable yang diperlukan tidak ada${PATH}
. Misalnya, untuk menguji yanglzop
dapat dieksekusi:Jika Anda memiliki beberapa executable untuk diperiksa, Anda mungkin ingin menggunakan
foreach
fungsi denganwhich
executable:Perhatikan penggunaan
:=
operator penugasan yang diperlukan untuk memaksa evaluasi langsung dari ekspresi RHS. Jika Makefile Anda mengubahPATH
, maka alih-alih baris terakhir di atas Anda perlu:Ini akan memberi Anda hasil yang mirip dengan:
sumber
where my_exe 2>NUL
sebagai penggantiwhich
.Bash
, tidak perlu melakukan panggilan eksternal kewhich
. Gunakan built-incommand -v
sebagai gantinya. Info lebih lanjut .Saya mencampur solusi dari @kenorb dan @ 0xF dan mendapatkan ini:
Ia bekerja dengan baik karena "perintah -v" tidak mencetak apa pun jika yang dapat dieksekusi tidak tersedia, sehingga variabel DOT tidak pernah didefinisikan dan Anda dapat memeriksanya kapan pun Anda inginkan dalam kode Anda. Dalam contoh ini saya memberikan kesalahan, tetapi Anda dapat melakukan sesuatu yang lebih berguna jika Anda mau.
Jika variabel tersedia, "perintah -v" melakukan operasi pencetakan jalur perintah yang tidak mahal, dengan mendefinisikan variabel DOT.
sumber
$(shell command -v dot)
gagal denganmake: command: Command not found
. Untuk mengatasinya, redirect stderr output ke / dev / null:$(shell command -v dot 2> /dev/null)
. Penjelasancommand
yang dimaksud dengan bash builtin, untuk lebih mudah dibawa, pertimbangkan untuk menggunakanwhich
?command
utilitas diperlukan oleh posix (termasuk-v
opsi) Di sisi lainwhich
tidak memiliki bahasa standar (yang saya tahu) dan kadang-kadang langsung tidak dapat digunakancommand -v
membutuhkan lingkungan shell seperti POSIX. Ini tidak akan berfungsi di Windows tanpa cygwin atau emulasi serupa.command
sering kali tidak berfungsi bukan karena ketidakhadirannya , tetapi karena pengoptimalan khusus yang dilakukan GNU Make: jika sebuah perintah "cukup sederhana" ia akan melewati shell; ini sayangnya berarti built-in terkadang tidak berfungsi kecuali Anda sedikit mengacaukan perintah.apakah ini yang kamu lakukan?
kredit untuk rekan kerja saya.
sumber
Gunakan
shell
fungsi untuk memanggil program Anda sedemikian rupa sehingga mencetak sesuatu ke keluaran standar. Misalnya, lulus--version
.GNU Make mengabaikan status keluar dari perintah yang diteruskan ke
shell
. Untuk menghindari potensi pesan "perintah tidak ditemukan", alihkan kesalahan standar ke/dev/null
.Maka Anda dapat memeriksa hasilnya menggunakan
ifdef
,ifndef
,$(if)
dllSebagai bonus, output (seperti versi program) mungkin berguna di bagian lain Makefile Anda.
sumber
*** missing separator. Stop.
Jika saya menambahkan tab di semua baris setelahall:
saya mendapatkan kesalahanmake: ifdef: Command not found
ifdef
akan dievaluasi benar meskipunyour_program
tidak ada gnu.org/software/make/manual/make.html#Conditional-Syntaxifdef
,else
,endif
garis. Pastikan saja@echo
garisnya dimulai dengan tab.ifdef
memeriksa nilai variabel yang tidak kosong. Jika variabel Anda tidak kosong, apa yang dievaluasi?ifdef
atauifndef
(seperti pada jawaban yang diterima) hanya berfungsi jika variabel yang dievaluasi segera disetel (:=
) alih-alih set malas (=
). Namun, kelemahan dari penggunaan variabel segera ditetapkan adalah bahwa mereka dievaluasi pada waktu deklarasi, sedangkan variabel set malas dievaluasi saat dipanggil. Ini berarti Anda akan menjalankan perintah untuk variabel:=
bahkan ketika Make hanya menjalankan aturan yang tidak pernah menggunakan variabel tersebut! Anda dapat menghindari ini dengan menggunakan=
denganifneq ($(MY_PROG),)
Membersihkan beberapa solusi yang ada di sini ...
The
$(info ...)
Anda dapat mengecualikan jika Anda ingin ini menjadi lebih tenang.Ini akan gagal dengan cepat . Tidak ada target yang dibutuhkan.
sumber
Solusi saya melibatkan skrip pembantu kecil 1 yang menempatkan file bendera jika semua perintah yang diperlukan ada. Ini datang dengan keuntungan bahwa pemeriksaan untuk perintah yang diperlukan hanya dilakukan sekali dan tidak pada setiap
make
pemanggilan.check_cmds.sh
Makefile
1 Lebih lanjut tentang
command -v
teknik dapat ditemukan di sini .sumber
if
pernyataan pertama .Bagi saya semua jawaban di atas didasarkan pada linux dan tidak berfungsi dengan windows. Saya baru dalam membuat jadi pendekatan saya mungkin tidak ideal. Tetapi contoh lengkap yang berfungsi untuk saya di linux dan windows adalah ini:
opsional ketika saya perlu mendeteksi lebih banyak alat yang dapat saya gunakan:
sumber
Anda dapat menggunakan perintah bash built seperti
type foo
ataucommand -v foo
, seperti di bawah ini:Di mana
foo
program / perintah Anda. Alihkan ke> /dev/null
jika Anda ingin senyap.sumber
Asumsikan Anda memiliki target dan pembangun yang berbeda, masing-masing membutuhkan seperangkat alat yang lain. Tetapkan daftar alat tersebut dan anggap mereka sebagai target untuk memaksa memeriksa ketersediaannya
Sebagai contoh:
sumber
Saya secara pribadi mendefinisikan
require
target yang berjalan sebelum yang lainnya. Target ini hanya menjalankan perintah versi dari semua persyaratan satu per satu dan mencetak pesan kesalahan yang sesuai jika perintah tersebut tidak valid.Output dari skrip di bawah ini adalah
sumber
Dipecahkan dengan menyusun program kecil khusus di target makefile lain, yang tujuan utamanya adalah untuk memeriksa hal-hal runtime yang saya cari.
Kemudian, saya memanggil program ini dengan target makefile lainnya.
Itu adalah sesuatu seperti ini jika saya mengingatnya dengan benar:
sumber
Solusi yang memeriksa
STDERR
keluaran--version
tidak berfungsi untuk program yang mencetak versinyaSTDOUT
sebagai penggantiSTDERR
. Alih-alih memeriksa outputnya keSTDERR
atauSTDOUT
, periksa kode pengembalian program. Jika program tidak ada, kode keluarnya akan selalu bukan nol.sumber