Is this the correct syntax to make sure the dependent program is downloaded and installed?
If the package name is correct, this is the correct syntax to make make packages work. It does assume that the person running the program has sudo rights to execute apt-get. It also runs that command unconditionally for make packages, but that shouldn't be too much of a problem because apt-get will check if the package is already installed.
The main problem is that make all doesn't execute make packages, which can be accomplished with
all: myprogram.c packages
# command
Since apt-get is inherently non-portable, it's correct if it works on your box :)
That is not what makefiles are for. Makefile only handles building the software and installing it into the system in a generic way (without a package manager). It does not care (and should not care) if you have the requirements to actually run the application. That is by design. Consider several points:
1) If your distribution uses a package managers (almost all of them do in some way), you should not call make install directly anyway, because that bypasses the package manager and pollutes your system. In that case make install is called in a "sandbox" environment when you build the package, the installation gets packaged and the package is installed and handled by your package manager of choice.
2) There should be no requirement of installing everything in the "correct" order. In fact, this will most certainly lead to circular dependencies and it will be impossible to install. Even package managers usually get too strict about this which leads to problems. Also, when you are building a package (a buildscript calls make install), you actually don't intend to run the program and probably don't have the requirements installed anyway. You are after all just building a package that will be installed on some other computer.
3) There isn't a portable way of doing this. How will your make install which is by definition platform-independent, know where to look for the requirements (Hardwired urls or something? That would break in a second!). It cannot go through the package manager because it must run on all possibilities, including the future ones you haven't anticipated - also the versions change.
4) There isn't a one and only decision what to install. Shared libraries can be provided by different packages. There is more than one libc, even. And more than one package that provides OpenGL functionality (different graphics cards), different packages for matrix algebra, different libraries for media playback (vlc vs. gstreamer), and I could go on for ages. It's your choice how you design your systems and what components you use, it's the beauty of this modular design (instead of the old windows classic of putting everything on one CD/DVD, and thus having every library installed a thousand times by different packages, and gigabytes of installation for every application that shouldn't exceed 10MB with a sane design).
5) It's not the job of make install, it's a different level of maintenance. configure && make && make install handles checking what you have installed (for build-time dependencies), compiling the code and showing you where files should be put. Requirements on what versions of other software you need falls into the domain of packaging and distribution, which is a separate process -- the package manager, or the system admin if he installs things the traditional way. You should never mix these two concepts - it would lead to chaos. If things are separated into well defined layers, the developers can change things independent of the packagers and distribution maintainters: if the distro decides to repackage things with different names and use different alternatives, put things in different directories, they shouldn't expect the application developer, who takes care of the makefile, to know or care about this.
In short - no matter if the dependencies are build-time dependencies (without which the make cannot run - which is usually detected by the configure script), or the runtime dependencies, it shouldn't be done at the makefile level. Please don't do things the wrong way and consider the standards. If you are dealing with something that has no package yet (check the user-provided packages, it may be there already), you should investigate what is needed and actually build the package - it's better for others as well, who can then enjoy the package you made.
This is a Makefile target that I sometimes use to deploy stuff in systems where i do not know exactly what installed packages I can rely on being already installed. I should be possible to extend this also beyond apt and pacman.
What you actually do is depending on the needed executable. The target for the executable is trying to fetch the correct package that contains it.
ifneq (,$(wildcard /usr/bin/apt))
# USE APT
/usr/bin/apt-file:
$(warning $@ not installed. trying to install via apt ...)
sudo apt install -y apt-file
sudo apt-file update
/usr/bin/%: /usr/bin/apt-file
$(warning $@ not installed. trying to install via apt ...)
sudo apt install -y $(shell apt-file --fixed-string --package-only search $@)
else ifneq (,$(wildcard /usr/bin/pacman))
# USE PACMAN
/usr/bin/%:
$(warning $@ not installed. trying to install via pacman ...)
sudo pacman -Fy
sudo pacman -Sy $(shell sudo pacman -Fq $@)
else
# NO PACKAGE MANAGER SUPPORT
/usr/bin/%:
$(error $@ not installed. please install manually and try again ...)
endif
With this in your makefile you can easily add other targets like this:
index.html: | /usr/bin/wget
/usr/bin/wget www.google.de
You should only need to care about updating your package databases eventually.
Make to install dependencies in multiple projects Makefile - Stack Overflow
How do I install makefile dependencies automatically?
build system - Why should makefiles have an "install" target? - Software Engineering Stack Exchange
linux - Makefile: Target dependency - How to always-make it? - Stack Overflow
Many build scripts or Makefiles have an installation target because they were created before package managers existed, and because even today lots of systems don't have package managers. Plus, there are systems where make install actually is the preferred way of managing packages.
A makefile might have no install target, and more importantly, you can have programs which are not even supposed to be installable (e.g. because they should run from their build directory, or because they can run installed anywhere). The install target is just a convention for usual makefile-s.
However, many programs require external resources to be run (for example: fonts, databases, configuration files, etc). And their executable often make some hypothesis about these resources. For example, your bash shell would generally read some initialization file from /etc/bash.bashrc etc.... These resources are generally in the file system (see hier(7) for conventions about the file hierarchy) and the default file path is built in your executable.
Try to use strings(1) on most executables of your system. You'll find out which file paths are known to it.
BTW, for many GNU programs using autoconf, you could run make install DESTDIR=/tmp/destdir/ without being root. Then /tmp/destdir/ is filled with the files that should be later packaged.
FWIW, I tend to believe that my bismon (GPLv3+ licensed) program (described in my bismon-chariot-doc.pdf report) cannot be "installed"; I am not sure to be able to prove that, and I cannot imagine how could I make that program installable.
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
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
...