Files
redis/Makefile
0b0d1784b8 MOD-18280 - make install default build (#15754)
<!-- CURSOR_SUMMARY -->
> [!NOTE]
> **Low Risk**
> Behavior change is limited to install defaults and safer config file
permissions during deploy; no auth or runtime data-path changes.
> 
> **Overview**
> **`make install` now runs a build before copying artifacts**, matching
upstream Redis behavior and aligning it with `make deploy`. The Makefile
no longer sets `install: SKIP_BUILD ?= 1`; install and deploy both
invoke `scripts/build.sh` unless you pass **`SKIP_BUILD=1`** (documented
for cases like `sudo make install` where compiling as root would pollute
`~/.cargo` and module build dirs).
> 
> The README adds an **Install** subsection with
`PREFIX`/`DESTDIR`/`uninstall` examples and the opt-out build flag.
> 
> **`scripts/deploy.sh`** updates header comments for the new defaults
and fixes config rewriting under `sudo`: before patching `loadmodule`
blocks, the temp file is seeded with **`cp -p`** on the existing conf so
**`mv` does not leave `redis.conf` / `redis-full.conf` at mode 0600 or
root-owned** when the user still needs to edit them.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
782c3bcd79. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: TalBarYakar <tal.baryakar@redis.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:44:00 +03:00

181 lines
8.3 KiB
Makefile

# Top level makefile, the real stuff is at ./src/Makefile and in ./modules/Makefile
# Explicitly export $(MAKE) so recipe shells (scripts/build.sh, deploy.sh, ...)
# can read it as $MAKE and use the same make binary the user invoked. GNU make
# only auto-propagates MAKE to recursive `$(MAKE) -C ...` sub-makes — recipes
# that are shell scripts get an EMPTY $MAKE env var by default. Without this,
# `MAKE_BIN="${MAKE:-make}"` in scripts falls back to PATH-lookup of `make`,
# which can resolve to Apple's stock /usr/bin/make 3.81 in non-interactive
# recipe shells (different PATH ordering than the user's interactive shell).
export MAKE
.DEFAULT_GOAL := build
# Used only by .DEFAULT: below, for goals with no explicit rule in
# this Makefile (e.g. `make distclean`, `make 32bit`) — those still recurse
# into src/ only, matching upstream Redis. Modules are never part of this;
# `make` / `make build` route through scripts/build.sh instead,
# which decides per-module inclusion from what's actually cloned under
# modules/*/src, not from a build flag.
SUBDIRS = src
# Manifest parser (modules.yaml → AVAILABLE_MODULES + helpers) shared with
# per-module builds via modules/common.mk. The `sync-redis-conf` target lives
# in this top-level Makefile (not in manifest.mk) so per-module builds —
# which include common.mk → manifest.mk — don't see it as their default goal.
include modules/manifest.mk
# ----------------------------------------------------------------------------
# Positional-arg capture for goals that take a list of module/test names.
#
# `make modules-update redistimeseries redisjson` is parsed by Make as three
# goals; we want only `modules-update` to run, with the rest captured into
# MODULES_ARGS. Each entry in GOALS_WITH_ARGS is `<goal>:<VAR>`. To add a
# new positional-arg goal, append it here — the dispatch and no-op .PHONY
# targets fall out automatically.
# ----------------------------------------------------------------------------
GOALS_WITH_ARGS := \
modules-update:MODULES_ARGS \
modules-shallow:SHALLOW_ARGS \
run:RUN_ARGS \
build:BUILD_ARGS \
clean:CLEAN_ARGS \
bootstrap:BOOTSTRAP_ARGS \
deploy:DEPLOY_ARGS \
install:DEPLOY_ARGS \
uninstall:UNINSTALL_ARGS \
test:TEST_ARGS \
sync-redis-conf:SYNC_ARGS
GOAL_NAMES_WITH_ARGS := $(foreach pair,$(GOALS_WITH_ARGS),$(firstword $(subst :, ,$(pair))))
# When <goal> is the top-level goal, stash trailing positional args into <var>
# and turn each non-':'-bearing token into a no-op .PHONY target so .DEFAULT
# below doesn't recurse into $(SUBDIRS) for them. Tokens containing ':' are
# skipped here (they'd crash Make's static-pattern parser); goals that want to
# forbid them validate in a follow-up block.
define _capture_goal_args
ifeq ($$(firstword $$(MAKECMDGOALS)),$(1))
$(2) := $$(filter-out $(1),$$(MAKECMDGOALS))
$$(foreach m,$$($(2)),$$(if $$(findstring :,$$(m)),,$$(eval .PHONY: $$(m))$$(eval $$(m): ; @:)))
endif
endef
$(foreach pair,$(GOALS_WITH_ARGS), \
$(eval $(call _capture_goal_args,$(firstword $(subst :, ,$(pair))),$(lastword $(subst :, ,$(pair))))))
ifeq ($(filter $(firstword $(MAKECMDGOALS)),$(GOAL_NAMES_WITH_ARGS)),)
all: build
endif
# `test` extra validation: positional names containing ':' (e.g. `file:test`)
# would fail Make parsing, so force them through TEST=<name>.
ifeq ($(firstword $(MAKECMDGOALS)),test)
TEST_ARGS_BAD := $(strip $(foreach m,$(TEST_ARGS),$(if $(findstring :,$(m)),$(m))))
ifneq ($(TEST_ARGS_BAD),)
$(error Test name(s) containing ':' cannot be passed positionally to make: '$(TEST_ARGS_BAD)'. Use TEST=<name> instead, e.g. `$(MAKE) test redistimeseries TEST='$(firstword $(TEST_ARGS_BAD))'`)
endif
endif
# `sync-redis-conf <name> ...` glue: feed positional args into MODULES (which
# the recipe below passes to scripts/sync-redis-conf.sh). Recursive invocations
# from build/modules-update pass MODULES= explicitly, so SYNC_ARGS stays empty
# there.
ifeq ($(firstword $(MAKECMDGOALS)),sync-redis-conf)
ifneq ($(SYNC_ARGS),)
MODULES := $(SYNC_ARGS)
endif
endif
.DEFAULT:
for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@; done
# `install` is an alias for `deploy` — same args, same PREFIX/DESTDIR. Like
# upstream's install it builds first; nothing already up to date is recompiled,
# because Redis core and each module short-circuit on their own artifacts. See
# the `sudo make install` note in README.md: redisearch and redisjson ask cargo
# whether they are up to date, so it has to be on root's PATH.
install: deploy
# clean [<name> ...|all|.|redis|none] — Redis core + selected modules.
# Same per-module dispatch as scripts/build.sh. Env vars set on the make
# line (e.g. `make clean DEPS=1`) propagate to the per-module clean via
# the shell environment.
clean:
+@scripts/clean.sh $(CLEAN_ARGS)
# ----------------------------------------------------------------------------
# Module / build / test orchestration. Recipes are thin wrappers around
# scripts/ so the logic stays out of Make. See each script's header for full
# usage. All scripts respect $(MAKE) and run from the repo root.
# ----------------------------------------------------------------------------
# build [<name> ...|all|.|redis|core|none] — Redis core + selected modules.
build:
+@PROG_SUFFIX='$(PROG_SUFFIX)' scripts/build.sh $(BUILD_ARGS)
# bootstrap [<name> ...|all|.] — install per-module build/test prereqs.
bootstrap:
+@scripts/bootstrap.sh $(BOOTSTRAP_ARGS)
# deploy [<name> ...|all|.|redis|none] [PREFIX=<path>] [DESTDIR=<path>]
# [PROG_SUFFIX=<suffix>] [SKIP_BUILD=1]
# Install Redis core + selected modules (default: every cloned module),
# then rewrite the `loadmodule` paths in redis-full.conf (and redis.conf, if
# it carries a Modules block) to point at the installed .so paths under
# $(PREFIX)/lib/redis/modules. PREFIX defaults to /usr/local (same as
# `make install`). Done directly by scripts/deploy.sh — no apply step.
deploy: PREFIX ?= /usr/local
deploy:
+@PREFIX='$(PREFIX)' DESTDIR='$(DESTDIR)' PROG_SUFFIX='$(PROG_SUFFIX)' \
SKIP_BUILD='$(SKIP_BUILD)' scripts/deploy.sh $(DEPLOY_ARGS)
# uninstall [<name> ...|all|.|redis|none] [PREFIX=<path>] [DESTDIR=<path>]
# [PROG_SUFFIX=<suffix>]
# Exact inverse of `make install` / `make deploy`: removes the core binaries
# and symlinks from $(PREFIX)/bin and the selected modules' .so files from
# $(PREFIX)/lib/redis/modules (default: every module in modules.yaml, so a
# plain `sudo make uninstall` cleans up whatever a previous install left).
# `redis`/`none` uninstall the core only. See scripts/uninstall.sh.
uninstall: PREFIX ?= /usr/local
uninstall:
@PREFIX='$(PREFIX)' DESTDIR='$(DESTDIR)' PROG_SUFFIX='$(PROG_SUFFIX)' \
scripts/uninstall.sh $(UNINSTALL_ARGS)
# run [<name> ...|all|.|none] [ARGS="<redis-server flags>"]
run:
@ARGS='$(ARGS)' PROG_SUFFIX='$(PROG_SUFFIX)' scripts/run.sh $(RUN_ARGS)
# test [redis|all|<module> [<test_name>]] [TEST=<name>] — see scripts/test.sh.
test:
+@TEST='$(TEST)' PROG_SUFFIX='$(PROG_SUFFIX)' scripts/test.sh $(TEST_ARGS)
# modules-update [<name> ...|all|.] [MODULES_UPDATE_SHALLOW=1]
# Idempotent clone/refresh per modules.yaml.
modules-update:
+@MODULES_UPDATE_SHALLOW='$(MODULES_UPDATE_SHALLOW)' scripts/modules-update.sh $(MODULES_ARGS)
# modules-shallow <name> [<name> ...] — re-clone selected modules with --depth 1.
modules-shallow:
@scripts/modules-shallow.sh $(SHALLOW_ARGS)
# tarball TAG=<ref> [STAGING_DIR=...] [OUT_PATH=...] [TAR=...] [TARBALL_SKIP_MODULES_UPDATE=1]
# Reproducible Redis+modules source tarball.
tarball:
@TAG='$(TAG)' STAGING_DIR='$(STAGING_DIR)' OUT_PATH='$(OUT_PATH)' \
TAR='$(TAR)' TARBALL_SKIP_MODULES_UPDATE='$(TARBALL_SKIP_MODULES_UPDATE)' \
scripts/tarball.sh
# sync-redis-conf [<name> ...] [MODULES="<names>"] [ASSUME_BUILT=1|yes|true]
# Rewrite the untracked redis-full.conf from redis.conf + modules.yaml +
# per-module module.conf files. See scripts/sync-redis-conf.sh for the full
# contract (env vars, file layout, private-block stripping).
sync-redis-conf:
@REDIS_CONF='$(REDIS_CONF)' REDIS_GEN_CONF='$(REDIS_GEN_CONF)' \
MODULES='$(strip $(MODULES))' ASSUME_BUILT='$(strip $(ASSUME_BUILT))' \
MODULES_MANIFEST_FILE='$(MODULES_MANIFEST_FILE)' \
PREFIX='$(PREFIX)' \
scripts/sync-redis-conf.sh
.PHONY: install uninstall clean build run test bootstrap deploy modules-update modules-shallow sync-redis-conf tarball