coreutils/GNUmakefile
Etienne Cordonnier e1441eff2c GNUMakefile: install libstdbuf
Use external libstdbuf.so when building with make, as embedding the library
is only needed to work around "cargo install" limitations with shared libraries.

Also change default installation directory to /usr/local/libexec/coreutils/ for consistency
with GNU coreutils

Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
2025-06-22 23:30:34 +02:00

478 lines
11 KiB
Makefile

# spell-checker:ignore (misc) testsuite runtest findstring (targets) busytest toybox distclean pkgs nextest ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MULTICALL DATAROOTDIR TESTDIR manpages
# Config options
PROFILE ?= debug
MULTICALL ?= n
COMPLETIONS ?= y
MANPAGES ?= y
LOCALES ?= y
INSTALL ?= install
ifneq (,$(filter install, $(MAKECMDGOALS)))
override PROFILE:=release
endif
# Needed for the foreach loops to split each loop into a separate command
define newline
endef
PROFILE_CMD :=
ifeq ($(PROFILE),release)
PROFILE_CMD = --release
endif
RM := rm -rf
# Binaries
CARGO ?= cargo
CARGOFLAGS ?=
# Install directories
PREFIX ?= /usr/local
DESTDIR ?=
BINDIR ?= $(PREFIX)/bin
DATAROOTDIR ?= $(PREFIX)/share
LIBSTDBUF_DIR ?= $(PREFIX)/libexec/coreutils
# Export variable so that it is used during the build
export LIBSTDBUF_DIR
INSTALLDIR_BIN=$(DESTDIR)$(BINDIR)
#prefix to apply to coreutils binary and all tool binaries
PROG_PREFIX ?=
# This won't support any directory with spaces in its name, but you can just
# make a symlink without spaces that points to the directory.
BASEDIR ?= $(shell pwd)
ifdef CARGO_TARGET_DIR
BUILDDIR := $(CARGO_TARGET_DIR)/${PROFILE}
else
BUILDDIR := $(BASEDIR)/target/${PROFILE}
endif
PKG_BUILDDIR := $(BUILDDIR)/deps
DOCSDIR := $(BASEDIR)/docs
BUSYBOX_ROOT := $(BASEDIR)/tmp
BUSYBOX_VER := 1.36.1
BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER)
TOYBOX_ROOT := $(BASEDIR)/tmp
TOYBOX_VER := 0.8.12
TOYBOX_SRC := $(TOYBOX_ROOT)/toybox-$(TOYBOX_VER)
#------------------------------------------------------------------------
# Detect the host system.
# On Windows the environment already sets OS = Windows_NT.
# Otherwise let it default to the kernel name returned by uname -s
# (Linux, Darwin, FreeBSD, …).
#------------------------------------------------------------------------
OS ?= $(shell uname -s)
ifdef SELINUX_ENABLED
override SELINUX_ENABLED := 0
# Now check if we should enable it (only on non-Windows)
ifneq ($(OS),Windows_NT)
ifeq ($(shell if [ -x /sbin/selinuxenabled ] && /sbin/selinuxenabled 2>/dev/null; then echo 0; else echo 1; fi),0)
override SELINUX_ENABLED := 1
$(info /sbin/selinuxenabled successful)
else
$(info SELINUX_ENABLED=1 but /sbin/selinuxenabled failed)
endif
endif
endif
# Possible programs
PROGS := \
base32 \
base64 \
basenc \
basename \
cat \
cksum \
comm \
cp \
csplit \
cut \
date \
dd \
df \
dir \
dircolors \
dirname \
echo \
env \
expand \
expr \
factor \
false \
fmt \
fold \
hashsum \
head \
join \
link \
ln \
ls \
mkdir \
mktemp \
more \
mv \
nl \
numfmt \
nproc \
od \
paste \
pr \
printenv \
printf \
ptx \
pwd \
readlink \
realpath \
rm \
rmdir \
seq \
shred \
shuf \
sleep \
sort \
split \
stty \
sum \
sync \
tac \
tail \
tee \
test \
tr \
true \
truncate \
tsort \
unexpand \
uniq \
vdir \
wc \
whoami \
yes
UNIX_PROGS := \
arch \
chgrp \
chmod \
chown \
chroot \
du \
groups \
hostid \
hostname \
id \
install \
kill \
logname \
mkfifo \
mknod \
nice \
nohup \
pathchk \
pinky \
stat \
stdbuf \
timeout \
touch \
tty \
uname \
unlink \
uptime \
users \
who
SELINUX_PROGS := \
chcon \
runcon
$(info Detected OS = $(OS))
# Don't build the SELinux programs on macOS (Darwin)
ifeq ($(OS),Darwin)
SELINUX_PROGS :=
endif
ifneq ($(OS),Windows_NT)
PROGS := $(PROGS) $(UNIX_PROGS)
# Build the selinux command even if not on the system
PROGS := $(PROGS) $(SELINUX_PROGS)
# Always use external libstdbuf when building with make (Unix only)
CARGOFLAGS += --features feat_external_libstdbuf
endif
UTILS ?= $(PROGS)
# Programs with usable tests
TEST_PROGS := \
base32 \
base64 \
basename \
cat \
chcon \
chgrp \
chmod \
chown \
cksum \
comm \
cp \
csplit \
cut \
date \
dircolors \
dirname \
echo \
env \
expr \
factor \
false \
fold \
hashsum \
head \
install \
link \
ln \
ls \
mkdir \
mktemp \
mv \
nl \
numfmt \
od \
paste \
pathchk \
pinky \
pr \
printf \
ptx \
pwd \
readlink \
realpath \
rm \
rmdir \
runcon \
seq \
sleep \
sort \
split \
stat \
stdbuf \
sum \
tac \
tail \
test \
touch \
tr \
true \
truncate \
tsort \
uname \
unexpand \
uniq \
unlink \
wc \
who
TESTS := \
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(TEST_PROGS))))
TEST_NO_FAIL_FAST :=
TEST_SPEC_FEATURE :=
ifneq ($(SPEC),)
TEST_NO_FAIL_FAST :=--no-fail-fast
TEST_SPEC_FEATURE := test_unimplemented
else ifeq ($(SELINUX_ENABLED),1)
TEST_NO_FAIL_FAST :=
TEST_SPEC_FEATURE := selinux
BUILD_SPEC_FEATURE := selinux
endif
define TEST_BUSYBOX
test_busybox_$(1):
-(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS) $(1))
endef
# Output names
EXES := \
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(PROGS))))
INSTALLEES := ${EXES}
ifeq (${MULTICALL}, y)
INSTALLEES := ${INSTALLEES} coreutils
endif
all: build
do_install = $(INSTALL) ${1}
use_default := 1
build-pkgs:
ifneq (${MULTICALL}, y)
ifdef BUILD_SPEC_FEATURE
${CARGO} build ${CARGOFLAGS} --features "$(BUILD_SPEC_FEATURE)" ${PROFILE_CMD} $(foreach pkg,$(EXES),-p uu_$(pkg))
else
${CARGO} build ${CARGOFLAGS} ${PROFILE_CMD} $(foreach pkg,$(EXES),-p uu_$(pkg))
endif
endif
build-coreutils: locales
${CARGO} build ${CARGOFLAGS} --features "${EXES} $(BUILD_SPEC_FEATURE)" ${PROFILE_CMD} --no-default-features
build: build-coreutils build-pkgs
$(foreach test,$(filter-out $(SKIP_UTILS),$(PROGS)),$(eval $(call TEST_BUSYBOX,$(test))))
test:
${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST)
nextest:
${CARGO} nextest run ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST)
test_toybox:
-(cd $(TOYBOX_SRC)/ && make tests)
toybox-src:
if [ ! -e "$(TOYBOX_SRC)" ] ; then \
mkdir -p "$(TOYBOX_ROOT)" ; \
wget "https://github.com/landley/toybox/archive/refs/tags/$(TOYBOX_VER).tar.gz" -P "$(TOYBOX_ROOT)" ; \
tar -C "$(TOYBOX_ROOT)" -xf "$(TOYBOX_ROOT)/$(TOYBOX_VER).tar.gz" ; \
sed -i -e "s|TESTDIR=\".*\"|TESTDIR=\"$(BUILDDIR)\"|g" $(TOYBOX_SRC)/scripts/test.sh; \
sed -i -e "s/ || exit 1//g" $(TOYBOX_SRC)/scripts/test.sh; \
fi ;
busybox-src:
if [ ! -e "$(BUSYBOX_SRC)" ] ; then \
mkdir -p "$(BUSYBOX_ROOT)" ; \
wget "https://busybox.net/downloads/busybox-$(BUSYBOX_VER).tar.bz2" -P "$(BUSYBOX_ROOT)" ; \
tar -C "$(BUSYBOX_ROOT)" -xf "$(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER).tar.bz2" ; \
fi ;
# This is a busybox-specific config file their test suite wants to parse.
$(BUILDDIR)/.config: $(BASEDIR)/.busybox-config
cp $< $@
# Test under the busybox test suite
$(BUILDDIR)/busybox: busybox-src build-coreutils $(BUILDDIR)/.config
cp "$(BUILDDIR)/coreutils" "$(BUILDDIR)/busybox"
chmod +x $@
prepare-busytest: $(BUILDDIR)/busybox
# disable inapplicable tests
-( cd "$(BUSYBOX_SRC)/testsuite" ; if [ -e "busybox.tests" ] ; then mv busybox.tests busybox.tests- ; fi ; )
ifeq ($(EXES),)
busytest:
else
busytest: $(BUILDDIR)/busybox $(addprefix test_busybox_,$(filter-out $(SKIP_UTILS),$(EXES)))
endif
clean:
cargo clean
cd $(DOCSDIR) && $(MAKE) clean
distclean: clean
$(CARGO) clean $(CARGOFLAGS) && $(CARGO) update $(CARGOFLAGS)
ifeq ($(MANPAGES),y)
manpages: build-coreutils
mkdir -p $(BUILDDIR)/man/
$(foreach prog, $(INSTALLEES), \
$(BUILDDIR)/coreutils manpage $(prog) > $(BUILDDIR)/man/$(PROG_PREFIX)$(prog).1 $(newline) \
)
install-manpages: manpages
mkdir -p $(DESTDIR)$(DATAROOTDIR)/man/man1
$(foreach prog, $(INSTALLEES), \
$(INSTALL) $(BUILDDIR)/man/$(PROG_PREFIX)$(prog).1 $(DESTDIR)$(DATAROOTDIR)/man/man1/ $(newline) \
)
else
install-manpages:
endif
ifeq ($(COMPLETIONS),y)
completions: build-coreutils
mkdir -p $(BUILDDIR)/completions/zsh $(BUILDDIR)/completions/bash $(BUILDDIR)/completions/fish
$(foreach prog, $(INSTALLEES), \
$(BUILDDIR)/coreutils completion $(prog) zsh > $(BUILDDIR)/completions/zsh/_$(PROG_PREFIX)$(prog) $(newline) \
$(BUILDDIR)/coreutils completion $(prog) bash > $(BUILDDIR)/completions/bash/$(PROG_PREFIX)$(prog) $(newline) \
$(BUILDDIR)/coreutils completion $(prog) fish > $(BUILDDIR)/completions/fish/$(PROG_PREFIX)$(prog).fish $(newline) \
)
install-completions: completions
mkdir -p $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions
mkdir -p $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions
mkdir -p $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d
$(foreach prog, $(INSTALLEES), \
$(INSTALL) $(BUILDDIR)/completions/zsh/_$(PROG_PREFIX)$(prog) $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/ $(newline) \
$(INSTALL) $(BUILDDIR)/completions/bash/$(PROG_PREFIX)$(prog) $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/ $(newline) \
$(INSTALL) $(BUILDDIR)/completions/fish/$(PROG_PREFIX)$(prog).fish $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/ $(newline) \
)
else
install-completions:
endif
ifeq ($(LOCALES),y)
locales:
$(foreach prog, $(INSTALLEES), \
if [ -d "$(BASEDIR)/src/uu/$(prog)/locales" ]; then \
mkdir -p "$(BUILDDIR)/locales/$(prog)"; \
for locale_file in "$(BASEDIR)"/src/uu/$(prog)/locales/*.ftl; do \
$(INSTALL) -v "$$locale_file" "$(BUILDDIR)/locales/$(prog)/"; \
done; \
fi $(newline) \
)
install-locales:
$(foreach prog, $(INSTALLEES), \
if [ -d "$(BASEDIR)/src/uu/$(prog)/locales" ]; then \
mkdir -p "$(DESTDIR)$(DATAROOTDIR)/locales/$(prog)"; \
for locale_file in "$(BASEDIR)"/src/uu/$(prog)/locales/*.ftl; do \
$(INSTALL) -v "$$locale_file" "$(DESTDIR)$(DATAROOTDIR)/locales/$(prog)/"; \
done; \
fi $(newline) \
)
else
install-locales:
endif
install: build install-manpages install-completions install-locales
mkdir -p $(INSTALLDIR_BIN)
ifneq ($(OS),Windows_NT)
mkdir -p $(DESTDIR)$(LIBSTDBUF_DIR)
$(INSTALL) -m 755 $(BUILDDIR)/deps/libstdbuf* $(DESTDIR)$(LIBSTDBUF_DIR)/
endif
ifeq (${MULTICALL}, y)
$(INSTALL) $(BUILDDIR)/coreutils $(INSTALLDIR_BIN)/$(PROG_PREFIX)coreutils
$(foreach prog, $(filter-out coreutils, $(INSTALLEES)), \
cd $(INSTALLDIR_BIN) && ln -fs $(PROG_PREFIX)coreutils $(PROG_PREFIX)$(prog) $(newline) \
)
$(if $(findstring test,$(INSTALLEES)), cd $(INSTALLDIR_BIN) && ln -fs $(PROG_PREFIX)coreutils $(PROG_PREFIX)[)
else
$(foreach prog, $(INSTALLEES), \
$(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog) $(newline) \
)
$(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[)
endif
uninstall:
ifneq ($(OS),Windows_NT)
rm -f $(DESTDIR)$(LIBSTDBUF_DIR)/libstdbuf*
-rmdir $(DESTDIR)$(LIBSTDBUF_DIR) 2>/dev/null || true
endif
ifeq (${MULTICALL}, y)
rm -f $(addprefix $(INSTALLDIR_BIN)/,$(PROG_PREFIX)coreutils)
endif
rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS))
rm -f $(INSTALLDIR_BIN)/$(PROG_PREFIX)[
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/zsh/site-functions/_$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/bash-completion/completions/$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS)))
rm -f $(addprefix $(DESTDIR)$(DATAROOTDIR)/man/man1/$(PROG_PREFIX),$(addsuffix .1,$(PROGS)))
.PHONY: all build build-coreutils build-pkgs test distclean clean busytest install uninstall