bagaimana makefile mendeteksi apakah suatu perintah tersedia di mesin lokal?

11

Saya mulai menggunakan mode-org untuk merencanakan tugas-tugas saya dalam sistem gaya GTD . Menempatkan setiap file org dalam direktori folder Dropbox , saya menjalankan emacs untuk mengedit / mengelola file-file ini dari tiga mesin lokal yang berbeda: Cygwin, Mac OS X, dan Debian. Karena saya juga menggunakan MobileOrg untuk mengakses file org ini dari iPad saya, checksums.datfile harus tetap terbaru ketika ada perubahan. Ini bisa dilakukan dengan menjalankan md5sum *.org > checksums.dat.

Masalahnya adalah ada tiga perintah untuk perintah yang berbeda md5sum: md5sum.exedi Cygwin, md5di Mac OS X, dan md5sumdi Debian. Situasi paling ideal adalah makefile, disimpan dalam foder Dropbox, mendeteksi perintah mana yang tersedia di mesin saat ini dan menjalankan perintah itu untuk melakukan operasi checksum md5.

Federico Magallanez
sumber
gnuautotools
Kevin
1
@ Kevin Kedengarannya seperti berlebihan. Saya tidak ingin menginstal program dalam tiga sistem yang berbeda. Di setiap sistem, folder Dropbox dapat diakses sebagai direktori lokal. Ketika saya menjalankan make checksumuntuk menghasilkan data checksum di bawah folder Dropbox, saya ingin makefile menggunakan perintah yang sesuai setelah mendeteksi perintah checksum mana yang tersedia di mesin saat ini.
Federico Magallanez
Jika Anda akan melakukan banyak skrip, dan proyek ini kecil, saya sarankan scon.
Faheem Mitha

Jawaban:

7

Perintah yang mungkin untuk menghasilkan checksum

Sayangnya, tidak ada utilitas standar untuk menghasilkan checksum kriptografi. Ada utilitas standar untuk menghasilkan CRC: cksum; ini mungkin cukup untuk tujuan Anda mendeteksi perubahan di lingkungan yang tidak bermusuhan.

Saya akan merekomendasikan menggunakan SHA1 daripada MD5. Tidak banyak sistem yang memiliki utilitas MD5 tetapi tidak ada SHA1, dan jika Anda akan menggunakan checksum kriptografi, Anda mungkin juga menggunakan algoritma tanpa metode yang diketahui untuk menemukan tabrakan (dengan asumsi Anda juga memeriksa ukurannya).

Salah satu alat yang tidak standar tetapi umum dan dapat menghitung pencernaan adalah OpenSSL . Ini tersedia untuk Cygwin, Debian dan OSX, tetapi sayangnya bukan bagian dari instalasi default di OSX.

openssl dgst -sha1

Pada OSX 10.6, ada shasumutilitas, yang juga ada di Debian (itu bagian dari perlpaket) dan saya percaya pada Cygwin juga. Ini adalah skrip Perl. Sebagian besar sistem unix memasang Perl, sehingga Anda dapat menggabungkan skrip tersebut bersama makefile Anda jika Anda khawatir skrip ini tidak tersedia di mana-mana.

Memilih perintah yang tepat untuk sistem Anda

Oke, katakanlah Anda benar-benar tidak dapat menemukan perintah yang berfungsi di mana-mana.

Di dalam shell

Gunakan typebuilt-in untuk melihat apakah perintah tersedia.

sum=
for x in sha1sum sha1 shasum 'openssl dgst -sha1'; do
  if type "${x%% *}" >/dev/null 2>/dev/null; then sum=$x; break; fi
done
if [ -z "$sum" ]; then echo 1>&2 "Unable to find a SHA1 utility"; exit 2; fi
$sum *.org

GNU membuat

Anda dapat menggunakan shellfungsi untuk menjalankan potongan shell ketika makefile dimuat dan menyimpan output dalam suatu variabel.

sum := $(shell { command -v sha1sum || command -v sha1 || command -v shasum; } 2>/dev/null)
%.sum: %
        $(sum) $< >$@

Portable (POSIX) buat

Anda hanya dapat menjalankan perintah shell dalam aturan, sehingga setiap aturan yang menghitung checksum harus berisi kode pencarian. Anda dapat menempatkan potongan dalam variabel. Ingatlah bahwa baris yang terpisah dalam aturan dievaluasi secara independen. Juga ingat bahwa $tanda - tanda yang akan diteruskan ke shell perlu diloloskan $$.

determine_sum = \
        sum=; \
        for x in sha1sum sha1 shasum 'openssl dgst -sha1'; do \
          if type "$${x%% *}" >/dev/null 2>/dev/null; then sum=$$x; break; fi; \
        done; \
        if [ -z "$$sum" ]; then echo 1>&2 "Unable to find a SHA1 utility"; exit 2; fi

checksums.dat: FORCE
    $(determine_sum); \
    $$sum *.org
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya harus menggunakan -Popsi typeperintah untuk mendapatkan metode "GNU make" yang dijelaskan di atas untuk bekerja dengan baik, jadi saya berakhir dengan sum := $(shell { type -P sha1sum || type -P sha1 || type -P shasum; } 2>/dev/null).
Sean
@Sean Terima kasih atas laporan bugnya. type -Phanya berfungsi jika shell Anda adalah bash, bukan jika itu misalnya ksh atau dash (yang merupakan kasus di Ubuntu antara lain). Anda dapat menggunakan command -vuntuk portabilitas.
Gilles 'SO- stop being evil'
Tampaknya Anda telah beralih dari menggunakan typeke menggunakan command. Haruskah metode lain diperbarui juga?
Sean
@Sean Metode lainnya baik-baik saja: typeadalah cara yang benar dan portabel untuk menguji keberadaan perintah, masalahnya adalah bahwa ia menghasilkan keluaran seperti sha1sum is /usr/bin/sha1sumbukan hanya nama program. Ini adalah satu-satunya tempat di mana saya menggunakan output typedaripada hanya nilai pengembaliannya.
Gilles 'SO- stop being evil'
5

Ini semacam retasan, tetapi Anda bisa menguji apakah masing-masing ada dan menjalankannya jika ada:

[ -x "`which md5 2>/dev/null`" ] && md5 newfile >>sums
[ -x "`which md5sum 2>/dev/null`" ] && md5sum newfile >>sums

Saya cukup yakin cygwin mengenali perintah (termasuk md5sum) tanpa .exe, tetapi sertakan jika Anda harus.

Kevin
sumber
4
whichnilai keluar tidak portabel. Gunakan typesebagai gantinya (dan Anda mungkin ingin menggunakannya if; then; elifuntuk menghindari masalah karena ada beberapa file yang dapat dieksekusi). whichdan typehanya mencari executable, jadi pengujian Anda dengan -x tidak ada gunanya.
Chris Down
lebih lanjut tentang menggunakan "type": cmd = $ (untuk cmd di foo md5 md5sum bar; lakukan ketik $ cmd> / dev / null 2> & 1 && echo $ cmd && break; done); $ cmd file1 file2 file3> md5.txt
michael
1

Entah GNU autotools (seperti yang disebutkan dalam komentar), atau juga CMake adalah sebuah pilihan.

Autotool GNU adalah pendekatan yang lebih tradisional, tetapi (dan mungkin hanya berbicara untuk diri saya sendiri) saya tidak berpikir orang-orang benar-benar terlalu bersemangat pada prospek awalnya mengatur proyek menggunakan mereka. Bagaimanapun, ini adalah kurva belajar. CMake adalah anak baru di blok, dan mungkin kurang umum (dan masih memiliki kurva belajar). Ini memiliki sintaks sendiri, dan menghasilkan makefile untuk platform Anda. CMake memang memiliki keuntungan berbeda karena tidak begitu tidak * x-sentris; ini berfungsi dengan baik pada unix, windows dan mac juga (mis., ia dapat menghasilkan proyek-proyek msvc, misalnya, daripada membuat file.)

Sunting: dan tentu saja karena 'makefiles' disarankan, jawaban ini sejalan dengan anggapan itu. Tapi mungkin hanya skrip python atau (terkesiap) program Java sederhana akan lebih sesuai untuk tugas ini; bahasa scripting / pemrograman akan melakukan hal yang sama di seluruh platform.

michael
sumber