1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2026-01-15 17:51:07 +00:00
uutils-coreutils/Makefile
Roman Gafiyatullin 092e4d1ed4 Implement expr.
Implemented as follows:

    Usage: expr EXPRESSION
      or:  expr OPTION

          --help     display this help and exit
          --version  output version information and exit

    Print the value of EXPRESSION to standard output.  A blank line below
    separates increasing precedence groups.  EXPRESSION may be:

      ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2

      ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0

      ARG1 < ARG2       ARG1 is less than ARG2
      ARG1 <= ARG2      ARG1 is less than or equal to ARG2
      ARG1 = ARG2       ARG1 is equal to ARG2
      ARG1 != ARG2      ARG1 is unequal to ARG2
      ARG1 >= ARG2      ARG1 is greater than or equal to ARG2
      ARG1 > ARG2       ARG1 is greater than ARG2

      ARG1 + ARG2       arithmetic sum of ARG1 and ARG2
      ARG1 - ARG2       arithmetic difference of ARG1 and ARG2

      ARG1 * ARG2       arithmetic product of ARG1 and ARG2
      ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2
      ARG1 % ARG2       arithmetic remainder of ARG1 divided by ARG2

      STRING : REGEXP   [NOT IMPLEMENTED] anchored pattern match of REGEXP in STRING

      match STRING REGEXP        [NOT IMPLEMENTED] same as STRING : REGEXP
      substr STRING POS LENGTH   [NOT IMPLEMENTED] substring of STRING, POS counted from 1
      index STRING CHARS         [NOT IMPLEMENTED] index in STRING where any CHARS is found, or 0
      length STRING              [NOT IMPLEMENTED] length of STRING
      + TOKEN                    interpret TOKEN as a string, even if it is a
                                   keyword like 'match' or an operator like '/'

      ( EXPRESSION )             value of EXPRESSION

    Beware that many operators need to be escaped or quoted for shells.
    Comparisons are arithmetic if both ARGs are numbers, else lexicographical.
    Pattern matches return the string matched between \( and \) or null; if
    \( and \) are not used, they return the number of characters matched or 0.

    Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null
    or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.

    Environment variables:
    	* EXPR_DEBUG_TOKENS=1   dump expression's tokens
    	* EXPR_DEBUG_RPN=1      dump expression represented in reverse polish notation
    	* EXPR_DEBUG_SYA_STEP=1 dump each parser step
    	* EXPR_DEBUG_AST=1      dump expression represented abstract syntax tree
2015-10-09 12:31:25 +03:00

440 lines
11 KiB
Makefile

# Config options
ENABLE_LTO ?= n
ENABLE_STRIP ?= n
# Binaries
RUSTC ?= rustc
CARGO ?= cargo
CC ?= gcc
RM := rm
# Install directories
PREFIX ?= /usr/local
BINDIR ?= /bin
LIBDIR ?= /lib
# 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)
SRCDIR := $(BASEDIR)/src
BUILDDIR := $(BASEDIR)/build
TESTDIR := $(BASEDIR)/test
TEMPDIR := $(BASEDIR)/tmp
# Flags
RUSTCFLAGS := -O
RMFLAGS :=
RUSTCLIBFLAGS := $(RUSTCFLAGS) -L $(BUILDDIR)/
RUSTCTESTFLAGS := $(RUSTCFLAGS)
# Handle config setup
ifeq ($(ENABLE_LTO),y)
RUSTCBINFLAGS := $(RUSTCLIBFLAGS) -C lto
else
RUSTCBINFLAGS := $(RUSTCLIBFLAGS)
endif
ifneq ($(ENABLE_STRIP),y)
ENABLE_STRIP :=
endif
# Possible programs
PROGS := \
base64 \
basename \
cat \
chmod \
cksum \
comm \
cp \
cut \
dirname \
echo \
env \
expand \
expr \
factor \
false \
fmt \
fold \
link \
hashsum \
ln \
mkdir \
nl \
nproc \
od \
paste \
printenv \
ptx \
pwd \
readlink \
realpath \
relpath \
rm \
rmdir \
sleep \
split \
seq \
shuf \
sort \
sum \
sync \
tac \
tee \
test \
tr \
true \
truncate \
tsort \
unexpand \
uniq \
wc \
yes \
head \
tail \
whoami
UNIX_PROGS := \
chroot \
du \
groups \
hostid \
hostname \
id \
kill \
logname \
mkfifo \
mv \
nice \
nohup \
stdbuf \
timeout \
touch \
tty \
uname \
unlink \
uptime \
users
ifneq ($(OS),Windows_NT)
PROGS := $(PROGS) $(UNIX_PROGS)
endif
ALIASES := \
hashsum:md5sum \
hashsum:sha1sum \
hashsum:sha224sum \
hashsum:sha256sum \
hashsum:sha384sum \
hashsum:sha512sum
BUILD ?= $(PROGS)
# Output names
EXES := \
$(sort $(filter $(BUILD),$(filter-out $(DONT_BUILD),$(PROGS))))
CRATE_RLIBS :=
INSTALL ?= $(EXES)
INSTALLEES := \
$(filter $(INSTALL),$(filter-out $(DONT_INSTALL),$(EXES) uutils))
# Shared library extension
SYSTEM := $(shell uname)
DYLIB_EXT :=
ifeq ($(SYSTEM),Linux)
DYLIB_EXT := so
DYLIB_FLAGS := -shared
endif
ifeq ($(SYSTEM),Darwin)
DYLIB_EXT := dylib
DYLIB_FLAGS := -dynamiclib -undefined dynamic_lookup
endif
# Libaries to install
LIBS :=
ifneq (,$(findstring stdbuf, $(INSTALLEES)))
LIBS += libstdbuf.$(DYLIB_EXT)
endif
# Programs with usable tests
TEST_PROGS := \
base64 \
basename \
cat \
cksum \
cp \
cut \
env \
dirname \
echo \
factor \
false \
fold \
hashsum \
head \
ln \
mkdir \
mv \
nl \
paste \
ptx \
pwd \
readlink \
realpath \
rm \
seq \
sort \
split \
stdbuf \
sum \
tac \
test \
touch \
tr \
true \
truncate \
tsort \
unlink \
unexpand \
wc
TEST ?= $(TEST_PROGS)
TESTS := \
$(filter $(TEST),$(filter-out $(DONT_TEST),$(filter $(BUILD),$(filter-out $(DONT_BUILD),$(TEST_PROGS)))))
# figure out what dependencies we need based on which programs we're building
define DEP_INCLUDE
-include $(SRCDIR)/$(1)/deps.mk
endef
# we always depend on libc because common/util does
# we also depend on getopts since all utilities support command-line arguments
DEPLIBS := libc getopts
DEPPLUGS :=
# now, add in deps in src/utilname/deps.mk
# if we're testing, only consider the TESTS variable,
# otherwise consider the EXES variable
ifeq ($(MAKECMDGOALS),test)
$(foreach build,$(TESTS),$(eval $(call DEP_INCLUDE,$(build))))
else
$(foreach build,$(sort $(TESTS) $(EXES)),$(eval $(call DEP_INCLUDE,$(build))))
endif
# uniqify deps
DEPLIBS := $(sort $(DEPLIBS))
DEPPLUGS := $(sort $(DEPPLUGS))
# build --extern commandline for rustc
DEP_EXTERN := $(foreach lib,$(subst -,_,$(DEPLIBS)),--extern $(lib)=$(BUILDDIR)/lib$(lib).rlib)
DEP_EXTERN += $(foreach plug,$(subst -,_,$(DEPPLUGS)),--extern $(plug)=$(BUILDDIR)/lib$(plug).$(DYLIB_EXT))
# Setup for building crates
define BUILD_SETUP
X := $(shell $(RUSTC) --print file-names --crate-type rlib $(SRCDIR)/$(1)/$(1).rs)
$(1)_RLIB := $$(X)
CRATE_RLIBS += $$(X)
endef
$(foreach crate,$(EXES),$(eval $(call BUILD_SETUP,$(crate))))
# Utils stuff
EXES_PATHS := $(addprefix $(BUILDDIR)/,$(EXES))
RLIB_PATHS := $(addprefix $(BUILDDIR)/,$(CRATE_RLIBS))
command = sh -c '$(1)'
RESERVED_EXTERNS := --extern uufalse=$(BUILDDIR)/libfalse.rlib --extern uutrue=$(BUILDDIR)/libtrue.rlib --extern uutest=$(BUILDDIR)/libtest.rlib
# Main exe build rule
define EXE_BUILD
$(BUILDDIR)/gen/$(1).rs: $(BUILDDIR)/mkmain
$(BUILDDIR)/mkmain $(1) $$@
$(BUILDDIR)/$(1): $(BUILDDIR)/gen/$(1).rs $(BUILDDIR)/$($(1)_RLIB) | $(BUILDDIR) deps
$(RUSTC) $(RUSTCBINFLAGS) $(RESERVED_EXTERNS) -o $$@ $$<
$(if $(ENABLE_STRIP),strip $$@,)
endef
# GRRR rust-crypto makes a crate called "crypto".
# This should NOT be allowed by crates.io. GRRRR.
define DEP_BUILD
DEP_$(1):
ifeq ($(1),crypto)
cd $(BASEDIR)/deps && $(CARGO) build --package rust-crypto --release
else ifeq ($(1),kernel32)
cd $(BASEDIR)/deps && $(CARGO) build --package kernel32-sys --release
else ifeq ($(1),advapi32)
cd $(BASEDIR)/deps && $(CARGO) build --package advapi32-sys --release
else
cd $(BASEDIR)/deps && $(CARGO) build --package $(1) --release
endif
endef
define CRATE_BUILD
-include $(BUILDDIR)/$(1).d
$(BUILDDIR)/$($(1)_RLIB): $(SRCDIR)/$(1)/$(1).rs | $(BUILDDIR) deps
$(RUSTC) $(RUSTCLIBFLAGS) $(DEP_EXTERN) --crate-type rlib --emit link,dep-info $$< --out-dir $(BUILDDIR)
endef
# Aliases build rule
ALIAS_SOURCE = $(firstword $(subst :, ,$(1)))
ALIAS_TARGET = $(word 2,$(subst :, ,$(1)))
define MAKE_ALIAS
ifneq ($(ALIAS_TARGET,$(1)),)
all: $(BUILDDIR)/$(call ALIAS_TARGET,$(1))
$(BUILDDIR)/$(call ALIAS_TARGET,$(1)): $(BUILDDIR)/$(call ALIAS_SOURCE,$(1))
$(call command,install $$@ $$<)
endif
endef
# Test exe built rules
define TEST_BUILD
test_$(1): $(BUILDDIR)/$(1) $(TEMPDIR)/$(1)/$(1)_test
$(call command,cp $(BUILDDIR)/$(1) $(TEMPDIR)/$(1) && cd $(TEMPDIR)/$(1) && $(TEMPDIR)/$(1)/$(1)_test)
$(TEMPDIR)/$(1)/$(1)_test: $(TESTDIR)/$(1).rs | $(TEMPDIR)/$(1)
$(call command,$(RUSTC) $(RUSTCTESTFLAGS) $(DEP_EXTERN) --test -o $$@ $$<)
$(TEMPDIR)/$(1): | $(TEMPDIR)
$(call command,cp -r $(TESTDIR)/fixtures/$(1) $$@ || mkdir $$@)
endef
# Main rules
all: $(EXES_PATHS) $(BUILDDIR)/uutils
# Creating necessary rules for each targets
$(foreach crate,$(EXES),$(eval $(call CRATE_BUILD,$(crate))))
$(foreach exe,$(EXES),$(eval $(call EXE_BUILD,$(exe))))
$(foreach alias,$(ALIASES),$(eval $(call MAKE_ALIAS,$(alias))))
$(foreach test,$(TESTS),$(eval $(call TEST_BUILD,$(test))))
$(foreach dep,$(sort $(DEPLIBS) $(DEPPLUGS)),$(eval $(call DEP_BUILD,$(dep))))
-include $(BUILDDIR)/uutils.d
$(BUILDDIR)/uutils: $(SRCDIR)/uutils/uutils.rs $(BUILDDIR)/mkuutils $(RLIB_PATHS)
$(BUILDDIR)/mkuutils $(BUILDDIR)/gen/uutils.rs $(EXES)
$(RUSTC) $(RUSTCBINFLAGS) $(RESERVED_EXTERNS) --emit link,dep-info $(BUILDDIR)/gen/uutils.rs --out-dir $(BUILDDIR)
$(if $(ENABLE_STRIP),strip $@)
# Library for stdbuf
$(BUILDDIR)/libstdbuf.$(DYLIB_EXT): $(SRCDIR)/stdbuf/libstdbuf.rs $(SRCDIR)/stdbuf/libstdbuf.c $(SRCDIR)/stdbuf/libstdbuf.h | $(BUILDDIR)
cd $(SRCDIR)/stdbuf && \
$(RUSTC) libstdbuf.rs --extern libc=$(BUILDDIR)/liblibc.rlib && \
$(CC) -c -Wall -Werror -fPIC libstdbuf.c && \
$(CC) $(DYLIB_FLAGS) -o libstdbuf.$(DYLIB_EXT) liblibstdbuf.a libstdbuf.o && \
mv *.$(DYLIB_EXT) $(BUILDDIR) && $(RM) *.o && $(RM) *.a
$(BUILDDIR)/stdbuf: $(BUILDDIR)/libstdbuf.$(DYLIB_EXT)
deps: $(BUILDDIR) $(SRCDIR)/cksum/crc_table.rs $(addprefix DEP_,$(DEPLIBS) $(DEPPLUGS))
$(foreach lib,$(subst -,_,$(DEPLIBS)),$(shell cp $(BASEDIR)/deps/target/release/deps/lib$(lib)-*.rlib $(BUILDDIR)/lib$(lib).rlib))
$(foreach plug,$(subst -,_,$(DEPPLUGS)),$(shell cp $(BASEDIR)/deps/target/release/deps/lib$(plug)-*.$(DYLIB_EXT) $(BUILDDIR)/lib$(plug).$(DYLIB_EXT)))
$(BUILDDIR)/mkmain: mkmain.rs | $(BUILDDIR)
$(RUSTC) $(RUSTCFLAGS) $< -o $@
$(BUILDDIR)/mkuutils: mkuutils.rs | $(BUILDDIR)
$(RUSTC) $(RUSTCFLAGS) $< -o $@
$(SRCDIR)/cksum/crc_table.rs: $(SRCDIR)/cksum/gen_table.rs
cd $(SRCDIR)/cksum && $(RUSTC) $(RUSTCBINFLAGS) gen_table.rs && ./gen_table && $(RM) gen_table
$(SRCDIR)/factor/prime_table.rs: $(SRCDIR)/factor/gen_table.rs
cd $(SRCDIR)/factor && $(RUSTC) $(RUSTCBINFLAGS) gen_table.rs && ./gen_table > $@ && $(RM) gen_table
crates:
echo $(EXES)
test: $(TEMPDIR) $(addprefix test_,$(TESTS))
$(RM) -rf $(TEMPDIR)
clean:
$(RM) -rf $(BUILDDIR) $(TEMPDIR)
distclean: clean
cd $(BASEDIR)/deps && $(CARGO) clean && $(CARGO) update
$(BUILDDIR):
mkdir -p $(BUILDDIR)/gen
$(TEMPDIR):
$(RM) -rf $(TEMPDIR)
mkdir $(TEMPDIR)
install: $(addprefix $(BUILDDIR)/,$(INSTALLEES))
mkdir -p $(DESTDIR)$(PREFIX)$(BINDIR)
for prog in $(INSTALLEES); do \
install $(BUILDDIR)/$$prog $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX)$$prog; \
done
mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)
for lib in $(LIBS); do \
install $(BUILDDIR)/$$lib $(DESTDIR)$(PREFIX)$(LIBDIR)/$$lib; \
done
# TODO: figure out if there is way for prefixes to work with the symlinks
install-multicall: $(BUILDDIR)/uutils
mkdir -p $(DESTDIR)$(PREFIX)$(BINDIR)
install $(BUILDDIR)/uutils $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX)uutils
cd $(DESTDIR)$(PREFIX)$(BINDIR)
for prog in $(INSTALLEES); do \
ln -s $(PROG_PREFIX)uutils $$prog; \
done
mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)
for lib in $(LIBS); do \
install $(BUILDDIR)/$$lib $(DESTDIR)$(PREFIX)$(LIBDIR)/$$lib; \
done
uninstall:
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(LIBDIR)/,$(LIBS))
uninstall-multicall:
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/,$(PROGS) $(PROG_PREFIX)uutils)
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(LIBDIR)/,$(LIBS))
# Test under the busybox testsuite
$(BUILDDIR)/busybox: $(BUILDDIR)/uutils
rm -f $(BUILDDIR)/busybox
ln -s $(BUILDDIR)/uutils $(BUILDDIR)/busybox
# This is a busybox-specific config file their test suite wants to parse.
$(BUILDDIR)/.config: $(BASEDIR)/.busybox-config $(BUILDDIR)/uutils
cp $< $@
ifeq ($(BUSYBOX_SRC),)
busytest:
@echo
@echo "To run \`busytest\` set BUSYBOX_SRC to the directory of the compiled busybox source code."
@echo "Optionally set RUNTEST_ARGS to arguments to pass to the busybox \`runtest\` program."
@echo
@false
else
busytest: $(BUILDDIR)/busybox $(BUILDDIR)/.config
(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS))
endif
# This rule will build each program, ignore all output, and return pass
# or fail depending on whether the build has errors.
build-check:
@for prog in $(sort $(PROGS)); do \
make BUILD="$$prog" >/dev/null 2>&1; status=$$?; \
if [ $$status -eq 0 ]; \
then printf "%-10s\t\033[1;32mpass\033[00;m\n" $$prog; \
else printf "%-10s\t\033[1;31mfail\033[00;m\n" $$prog; \
fi; \
done
# This rule will test each program, ignore all output, and return pass
# or fail depending on whether the test has errors.
test-check:
@for prog in $(sort $(TEST_PROGS)); do \
make TEST="$$prog" test >/dev/null 2>&1; status=$$?; \
if [ $$status -eq 0 ]; \
then printf "%-10s\t\033[1;32mpass\033[00;m\n" $$prog; \
else printf "%-10s\t\033[1;31mfail\033[00;m\n" $$prog; \
fi; \
done
.PHONY: $(TEMPDIR) all deps test distclean clean busytest install uninstall