2

This will most probably be obvious and / or a banality. But since I am trying different approaches for hours without success...

I am on Linux Mint 19. I am entirely new to Makefiles. Excuse me, if the problem is trivial.

Let it be clear, that I care for the distrib and SHA512SUMS targets only in this question.

As I heavily change the code of those scripts, I would like the SHA512SUMS file to be re-generated each time I run the distrib target, but not in case I run the check target, of course, that would make the check target irrelevant, as you can see.

This Makefile is becoming to be a little complicated for a shell scripter. Any help will be appreciated.


PREFIX?=/usr/local/bin
install_path=$(DESTDIR)$(PREFIX)

encrypt_script=encrypt-file-aes256
decrypt_script=decrypt-file-aes256
distrib_name=openssl-file-encryption-decryption-shell-scripts

.PHONY: check install uninstall distrib

check: $(encrypt_script) $(decrypt_script) SHA512SUMS
    echo && sha512sum --check --status SHA512SUMS && ( echo "Ok. You may use 'sudo make install' or '(sudo) make install PREFIX=SomeDir' command now." ) || ( echo "ERROR: Files hash sum mismatch!" && echo && exit 1 )

install: check
    echo && [ -d $(install_path) ] || mkdir --parents $(install_path)
    install --verbose --mode=0755 --target-directory=$(install_path) $(encrypt_script) $(decrypt_script)

uninstall:
    rm $(install_path)/$(encrypt_script) $(install_path)/$(decrypt_script)
    rmdir --ignore-fail-on-non-empty $(install_path)

distrib: check $(encrypt_script) $(decrypt_script) Makefile SHA512SUMS
    if [ $$(id --user) -eq 0 ]; then ( echo && echo "Target 'distrib' has to be run as normal user!" && echo && exit 1 ) fi
    rm --force $(distrib_name).tar.xz
    rm --force $(distrib_name).tar.xz.asc
    rm --force --recursive $(distrib_name)
    mkdir $(distrib_name)
#   sha512sum $(encrypt_script) $(decrypt_script) > $(distrib_name)/SHA512SUMS
    cp $(encrypt_script) $(decrypt_script) Makefile SHA512SUMS $(distrib_name)
    wget --quiet --output-document=$(distrib_name)/LICENSE https://git.io/fxByv # https://raw.githubusercontent.com/burianvlastimil/openssl-file-encryption-decryption-shell-scripts/master/LICENSE
    wget --quiet --output-document=$(distrib_name)/README.md https://git.io/fxByJ # https://raw.githubusercontent.com/burianvlastimil/openssl-file-encryption-decryption-shell-scripts/master/README.md
    chmod 755 $(distrib_name)/$(encrypt_script) $(distrib_name)/$(decrypt_script)
    chmod 644 $(distrib_name)/Makefile $(distrib_name)/SHA512SUMS $(distrib_name)/LICENSE $(distrib_name)/README.md
    tar --create --file=$(distrib_name).tar $(distrib_name)
    xz --format=xz -9 --extreme --check=sha256 $(distrib_name).tar
    rm --force --recursive $(distrib_name)
    gpg --local-user 7D2E022E39A88ACF3EF6D4498F37AF4CE46008C3 --sign --armor --output $(distrib_name).tar.xz.asc --detach-sig $(distrib_name).tar.xz

SHA512SUMS:
    sha512sum --check --status SHA512SUMS || sha512sum $(encrypt_script) $(decrypt_script) > SHA512SUMS
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52

3 Answers3

3

Reading on Force Targets, I came up, hopefully, with a solution below:

If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file, then make imagines this target to have been updated whenever its rule is run. This implies that all targets depending on this one will always have their recipe run.

Hence, I created an empty target force-rebuild-hash-file:.

Thus, the SHA512SUM file will always be re-created when calling this target or distrib target which depends on it.

I think it is finally solved overall, feel free to comment, if not.

In case you or I, myself, find any errors, I will update this answer to reflect them.

To de-duplicate some code I came across this answer and applied it.

I renamed SHA512SUMS to SHA512SUM, it does not matter much, but I find it more used.

I found $@ to print target names a good way of keeping track of what targets are being run. For instance, if SHA512SUM does not exist and we install it like this:

make install PREFIX=./test

we get a very nice overview (output):

echo && echo Target: check && echo

Target: check

if [ -f SHA512SUM ]; then ( echo && sha512sum --check SHA512SUM && ( echo && echo "Ok. You may use 'sudo make install' or '(sudo) make install PREFIX=SomeDir' command now." ) || ( echo && echo "ERROR: Files hash sum mismatch!" && echo && exit 1 ) ) else make --file=Makefile SHA512SUM; fi
make[1]: Entering directory '/home/vlastimil/Development/sh/openssl-encryption'
echo && echo Target: SHA512SUM && echo

Target: SHA512SUM

sha512sum encrypt-file-aes256 decrypt-file-aes256 > SHA512SUM
make[1]: Leaving directory '/home/vlastimil/Development/sh/openssl-encryption'
echo && echo Target: install && echo

Target: install

echo && [ -d ./test ] || mkdir --parents ./test

install --verbose --mode=0755 --target-directory=./test encrypt-file-aes256 decrypt-file-aes256
'encrypt-file-aes256' -> './test/encrypt-file-aes256'
'decrypt-file-aes256' -> './test/decrypt-file-aes256'

Current Makefile

DESTDIR ?=
PREFIX ?= /usr/local/bin
install_path := $(DESTDIR)$(PREFIX)
encrypt_script := encrypt-file-aes256
decrypt_script := decrypt-file-aes256
distrib_name := openssl-encryption
this_file := $(lastword $(MAKEFILE_LIST))

.PHONY: check install uninstall distrib

# https://stackoverflow.com/a/27132934/1997354
check: $(encrypt_script) $(decrypt_script)
    echo && echo Target: $@ && echo
    if [ -f SHA512SUM ]; then ( echo && sha512sum --check SHA512SUM && ( echo && echo "Ok. You may use 'sudo make install' or '(sudo) make install PREFIX=SomeDir' command now." ) || ( echo && echo "ERROR: Files hash sum mismatch!" && echo && exit 1 ) ) else $(MAKE) --file=$(this_file) SHA512SUM; fi

install: check
    echo && echo Target: $@ && echo
    echo && [ -d $(install_path) ] || mkdir --parents $(install_path)
    install --verbose --mode=0755 --target-directory=$(install_path) $(encrypt_script) $(decrypt_script)

uninstall:
    echo && echo Target: $@ && echo
    rm $(install_path)/$(encrypt_script) $(install_path)/$(decrypt_script)
    rmdir --ignore-fail-on-non-empty $(install_path)

distrib: SHA512SUM check $(encrypt_script) $(decrypt_script) Makefile
    echo && echo Target: $@ && echo
    # https://english.stackexchange.com/a/468131/319970
    # https://stackoverflow.com/a/52782747/1997354
    if [ $$(id --user) -eq 0 ]; then ( echo && echo "Target 'distrib' has to be run as normal user!" && echo && exit 1 ) fi
    rm --force $(distrib_name).tar.xz
    rm --force $(distrib_name).tar.xz.asc
    rm --force --recursive $(distrib_name)
    mkdir $(distrib_name)
    cp $(encrypt_script) $(decrypt_script) Makefile SHA512SUM $(distrib_name)
    wget --quiet --output-document=$(distrib_name)/LICENSE https://git.io/fxByv
    wget --quiet --output-document=$(distrib_name)/README https://git.io/fxByJ
    chmod 755 $(distrib_name)/$(encrypt_script) $(distrib_name)/$(decrypt_script)
    chmod 644 $(distrib_name)/Makefile $(distrib_name)/SHA512SUM $(distrib_name)/LICENSE $(distrib_name)/README
    tar --create --file=$(distrib_name).tar $(distrib_name)
    xz --format=xz -9 --extreme --check=sha256 $(distrib_name).tar
    rm --force --recursive $(distrib_name)
    gpg --local-user 7D2E022E39A88ACF3EF6D4498F37AF4CE46008C3 --sign --armor --output $(distrib_name).tar.xz.asc --detach-sig $(distrib_name).tar.xz

# https://www.gnu.org/software/make/manual/html_node/Force-Targets.html
force-rebuild-hash-file:

# real target file
SHA512SUM: force-rebuild-hash-file
    echo && echo Target: $@ && echo
    sha512sum $(encrypt_script) $(decrypt_script) > SHA512SUM
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
0

You could also declare SHA512SUM as order-only prerequisite of check, not a prerequisite of distrib but add $(MAKE) --always-make SHA512SUM to your distrib recipe:

check: $(encrypt_script) $(decrypt_script) | SHA512SUM
    ...

distrib: check $(encrypt_script) $(decrypt_script) Makefile
    $(MAKE) --always-make SHA512SUM
    ...
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • This does not work in the situation I call `make SHA512SUM`, while I have intentionally changed that file. It says: `make: 'SHA512SUM' is up to date.` Therefore I find my answer be more explicit and to account for more situations. – Vlastimil Burián Oct 13 '18 at 22:33
  • A plain call of `$(MAKE)` is a very common practice. But of course, you are absolutely free to refuse using recursive make for your own projects. – Renaud Pacalet Oct 14 '18 at 04:55
  • If you use make it is much better to stick with its basic principle: one target file depends on prerequisite files and the prerequisites are properly listed in the target's rule. With your `SHA512SUM` target you violate this principle, by not listing its prerequisites. And with the experiment you describe, you ask make to do something it has not been designed for: guess that you changed `SHA512SUM` by another mean. But of course, you can also use make in non-standard ways; as long as it does what you want, it's fine. – Renaud Pacalet Oct 14 '18 at 05:01
  • I am open to the recursive calls, I use it in my answer, just a maybe safer version, anyways, thank you for pointing all of that out. I am learning Makefiles still. – Vlastimil Burián Oct 14 '18 at 05:04
-1

I think the best would be to remove the explicit dependency on SHA512SUMS from the check-target, and have a (shell) test inside that target and explicitly create the file if it's not there yet:

check: ... ... if [ ! -e SHA512SUM ] ; then <create SHA512SUM HERE>; fi .. do something with SHA512SUM ...

Volker Stolz
  • 7,274
  • 1
  • 32
  • 50