Possible commands to generate a checksum
Unfortunately, there's no standard utility to generate a cryptographic checksum. There is a standard utility to generate a CRC: cksum
; this may be sufficient for your purpose of detecting changes in a non-hostile environment.
I would recommend using SHA1 rather than MD5. There aren't many systems that have an MD5 utility but no SHA1, and if you're going to use cryptographic checksums, you might as well use an algorithm with no known method to find collisions (assuming you also check the size).
One tool that's not standard but common and can calculate digests is OpenSSL. It's available for Cygwin, Debian and OSX, but unfortunately not part of the default installation on OSX.
openssl dgst -sha1
On OSX 10.6, there is a shasum
utility, which is also present on Debian (it's part of the perl
package) and I believe on Cygwin too. This is a Perl script. Most unix systems have Perl installed, so you could bundle that script alongside your makefile if you're worried about this script not being available everywhere.
Selecting the right command for your system
Ok, let's say you really can't find a command that works everywhere.
In the shell
Use the type
built-in to see if a command is available.
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 make
You can use the shell
function to run a shell snippet when the makefile is loaded and store the output in a variable.
sum := $(shell { command -v sha1sum || command -v sha1 || command -v shasum; } 2>/dev/null)
%.sum: %
$(sum) $< >$@
Portable (POSIX) make
You can only run shell commands in rule, so each rule that computes a checksum has to contain the lookup code. You can put the snippet in a variable. Remember that separate lines in rules are evaluated independently. Also remember that $
signs that are to be passed to the shell need to be escaped to $$
.
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
autotools
make checksum
to generate checksum data under a Dropbox folder, I want the makefile uses an appropriate command after detecting which checksum command is available in the current machine.