You are not logged in.

#1 2024-10-20 12:05:33

graysky
Wiki Maintainer
From: :wq
Registered: 2008-12-01
Posts: 10,637
Website

Makefile help - how to install to a custom PREFIX

In my Makefile, I'd like to allow the user to specify a value for PREFIX if not wanting the default of /usr which I did with PREFIX ?= /usr but am finding that when running the make install step, the value of /usr is inserted anyway.  For example:

% make PREFIX=/scratch/foo
% make DESTDIR=/scratch/foo install
installing main script and skel config...
install -p -d "/scratch/foo/usr/bin"
Installing manpage...
install -p -d "/scratch/foo/usr/share/man/man8"
install -p -d "/scratch/foo/usr/share/modprobed-db"
...

Note that insertion of /usr in those install lines.  Is the flaw in my Makefile or in my two make calls?

Makefile:

VERSION = 2.49
PN = modprobed-db

PREFIX ?= /usr
BINDIR = $(PREFIX)/bin
DOCDIR = $(PREFIX)/share/doc/$(PN)-$(VERSION)
MANDIR = $(PREFIX)/share/man/man8
INITDIR_SYSTEMD = $(PREFIX)/lib/systemd/user
SKELDIR = $(PREFIX)/share/$(PN)
BASHDIR = $(PREFIX)/share/bash-completion/completions
ZSHDIR = $(PREFIX)/share/zsh/site-functions

INSTALL = install -p
INSTALL_PROGRAM = $(INSTALL) -m755
INSTALL_DATA = $(INSTALL) -m644
INSTALL_DIR = $(INSTALL) -d

RM = rm
Q = @

all:
	$(Q)echo -e '\033[1;32mSetting version\033[0m'
	$(Q)sed -e 's|@VERSION@|$(VERSION)|' -e 's|@SKELPATH@|$(SKELDIR)|' common/$(PN).in > common/$(PN)
	$(Q)sed 's|@PREFIX@|$(PREFIX)|' init/$(PN).service.in > init/$(PN).service

clean:
	$(Q)$(RM) common/$(PN) init/$(PN).service

install-bin:
	$(Q)echo -e '\033[1;32mInstalling main script and skel config...\033[0m'
	$(INSTALL_DIR) "$(DESTDIR)$(BINDIR)"
	$(INSTALL_DIR) "$(DESTDIR)$(SKELDIR)"
	$(INSTALL_PROGRAM) common/$(PN) "$(DESTDIR)$(BINDIR)/$(PN)"
	$(INSTALL_DATA) common/$(PN).skel "$(DESTDIR)$(SKELDIR)/$(PN).skel"

	$(INSTALL_DIR) "$(DESTDIR)$(BASHDIR)"
	$(INSTALL_DATA) common/bash-completion "$(DESTDIR)$(BASHDIR)/modprobed-db"
	$(INSTALL_DIR) "$(DESTDIR)$(ZSHDIR)"
	$(INSTALL_DATA) common/zsh-completion "$(DESTDIR)$(ZSHDIR)/_modprobed-db"

	$(INSTALL_DIR) "$(DESTDIR)$(INITDIR_SYSTEMD)"
	$(INSTALL_DATA) init/modprobed-db.service "$(DESTDIR)$(INITDIR_SYSTEMD)/modprobed-db.service"
	$(INSTALL_DATA) init/modprobed-db.timer "$(DESTDIR)$(INITDIR_SYSTEMD)/modprobed-db.timer"

install-man:
	$(Q)echo -e '\033[1;32mInstalling manpage...\033[0m'
	$(INSTALL_DIR) "$(DESTDIR)$(MANDIR)"
	$(INSTALL_DATA) doc/$(PN).8 "$(DESTDIR)$(MANDIR)/$(PN).8"

install: install-bin install-man

uninstall:
	$(Q)$(RM) "$(DESTDIR)$(BINDIR)/$(PN)" "$(DESTDIR)$(MANDIR)/$(PN).8"
	$(Q)$(RM) -rf "$(DESTDIR)$(SKELDIR)"
	$(Q)$(RM) "$(DESTDIR)$(INITDIR_SYSTEMD)/modprobed-db.service" "$(DESTDIR)$(INITDIR_SYSTEMD)/modprobed-db.timer"
	$(Q)$(RM) "$(DESTDIR)$(BASHDIR)/modprobed-db" "$(DESTDIR)$(ZSHDIR)/_modprobed-db"

CPU-optimized Linux-ck packages @ Repo-ck  • AUR packagesZsh and other configs

Offline

#2 2024-10-20 13:01:44

astralc
Member
Registered: 2022-09-17
Posts: 88

Re: Makefile help - how to install to a custom PREFIX

PREFIX ?= /usr
BINDIR = $(PREFIX)/bin

it will make "BINDIR = /usr/bin" if you don't specify PREFIX for the make install call.
maybe you want also to check DESTDIR value for when you set (default) PREFIX?

Offline

#3 2024-10-20 13:33:58

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,290
Website

Re: Makefile help - how to install to a custom PREFIX

DESTDIR and PREFIX should not be the same path, and as noted above, setting one for a build step and the other for the install step is (also) nonsensical.  You can build optionally providing a PREFIX, but then when you install you must provide the same PREFIX (if any) and you may also optionally provide an additional DESTDIR.

Further, this may be personal taste, but your excessive use of variables just ends up making the Makefile much harder to read (and subject to a range of mistakes).  You don't need to hide every possible invocation of an install command behind a different variable.  And building on this, there's no reason to have so many steps just for creating directories when you're just using `install` to put something there anyways.  The first step in troubleshooting should be simplifying: don't bother trying to find everything that might be wrong in a complex Makefile if a much much simpler Makefile would do the same thing, be easier to read, and easier to spot errors.

Also, by tradition, "clean" should not remove installation targets, but only intermediate files that will not be installed ("make install" is traditionally expected to work properly even after a "make clean").  "dist-clean" (or sometimes "more-clean") is a commonly used for removing everything that can be regenerated.

Along with the excess use of variables, there's inconsistent use of the PN variable: sometimes you use $(PN), others you hardcode the value.  Pick one.  As it is, PN is a variable that could not actually vary without breaking everything.  (I'm not sure if I should pile on with asking what PN stands for.  It doesn't strike me as a very good variable name.  Is it for Project Name?  I think NAME might be more clear.)


EXAMPLE:

NAME      = modprobed-db
VERSION   = 2.49
PREFIX   ?= /usr

all:
	# and fix $(NAME).in to rely on PREFIX not SKELPATH
	sed 's|@VERSION@|$(VERSION)|;s|@PREFIX@|$(PREFIX)|' common/$(NAME).in > common/$(NAME)
	sed 's|@PREFIX@|$(PREFIX)|' init/$(NAME).service.in > init/$(NAME).service

dist-clean:
	rm common/$(NAME) init/$(NAME).service

install:
	install -Dm755 common/$(NAME)            "$(DESTDIR)$(PREFIX)/bin/$(NAME)"
	install -Dm644 common/$(NAME).skel       "$(DESTDIR)$(PREFIX)/share/$(NAME)/$(NAME).skel"
	install -Dm644 common/bash-completion    "$(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(NAME)"
	install -Dm644 common/zsh-completion     "$(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(NAME)"
	install -Dm644 init/modprobed-db.service "$(DESTDIR)$(PREFIX)/lib/systemd/user/modprobed-db.service"
	install -Dm644 init/modprobed-db.timer   "$(DESTDIR)$(PREFIX)/lib/systemd/user/modprobed-db.timer"
	install -Dm644 doc/$(NAME).8             "$(DESTDIR)$(PREFIX)/share/man/man8/$(NAME).8"

uninstall:
	rm "$(DESTDIR)$(PREFIX)/bin/$(NAME)"
	rm "$(DESTDIR)$(PREFIX)/share/man/man8/$(NAME).8"
	rm -rf "$(DESTDIR)$(PREFIX)/share/$(NAME)"
	rm "$(DESTDIR)$(PREFIX)/lib/systemd/user/$(NAME).service"
	rm "$(DESTDIR)$(PREFIX)/lib/systemd/user/$(NAME).timer"
	rm "$(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(NAME)"
	rm "$(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(NAME)"
make PREFIX=/toilet
make DESTDIR=/tmp/plumbing PREFIX=/toilet install
# or more realistically
make
make DESTDIR=${pkgdir} install
# or realistic but not ideal
make PREFIX=/opt
make DESTDIR=${pkgdir} PREFIX=/opt install

Last edited by Trilby (2024-10-20 15:08:03)


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

Board footer

Powered by FluxBB