# pg_lion — build with: make PG_CONFIG= # (the default is .local/pg/bin/pg_config when that exists, else pg_config on PATH) MODULE_big = pg_lion # The page layer (lion.h): pages, the meta page, the relation state, entries, # and writing container chains. PAGES_OBJS = src/lion_pages.o src/lion_meta.o src/lion_state.o src/lion_entry.o \ src/lion_posting_put.o # The count engine: its interface is src/lion_count.h, and its files share the # private header src/lion_count_int.h. COUNT_OBJS = src/lion_set.o src/lion_set_copy.o src/lion_cursor.o src/lion_expr.o src/lion_vis.o \ src/lion_count.o src/lion_count_groups.o src/lion_count_decode.o src/lion_slice_decode.o src/lion_count_shared.o \ src/lion_rangesrc.o src/lion_range.o src/lion_count_sql.o src/lion_facets.o src/lion_slice.o # The LionCount custom scan: its planner half (lion_plan_*) and its executor # half (lion_exec_*), which share the private header src/lion_customscan.h. CUSTOMSCAN_OBJS = src/lion_plan_match.o src/lion_plan_partition.o src/lion_plan_target.o \ src/lion_plan_cost.o src/lion_plan_fkjoin_cost.o src/lion_plan_fkjoin.o \ src/lion_plan_count.o src/lion_plan_gsets.o src/lion_plan_hooks.o src/lion_plan_units.o \ src/lion_plan_private.o src/lion_plan_partial.o src/lion_plan_nonempty.o \ src/lion_plan_cells.o src/lion_plan_anti.o src/lion_ordjoin.o \ src/lion_exec_begin.o src/lion_exec_locate.o src/lion_exec_count.o \ src/lion_exec_cells.o src/lion_exec_slice.o \ src/lion_exec_fkjoin.o src/lion_exec_anti.o src/lion_exec_run.o src/lion_exec_explain.o \ src/lion_probejoin.o # The SQL-callable helpers: lion_funcs.c and lion_index_verify()'s files, which # share the private header src/lion_funcs.h. FUNCS_OBJS = src/lion_funcs.o src/lion_verify.o src/lion_verify_dir.o src/lion_verify_heap.o \ src/lion_verify_summary.o src/lion_verify_slice.o # lionvec, the nearest-neighbour index of pgvector's `vector` and `halfvec` # (DESIGN.md §44): the AM, its scan, and its arithmetic, which is unit-tested # standalone. VEC_OBJS = src/lion_vec.o src/lion_vec_scan.o src/lion_vec_loc.o src/lion_vec_math.o # Reading a relation's blocks in an order its reader predicts: a read stream # over them from 17 on, asks of the kernel before (DESIGN.md §44.4, "Read # streams"); the ring's bookkeeping is unit-tested standalone. READAHEAD_OBJS = src/lion_readahead.o src/lion_readahead_ring.o # Bit-plane arithmetic and the extension's one choice of SIMD implementation # (DESIGN.md §50), below the container library and lionvec; unit-tested # standalone. OBJS = src/lion_planes.o src/lion_container.o src/lion_sparse.o src/lion_positions.o src/lion_wal.o src/lion_waldelta.o $(PAGES_OBJS) src/lion_dir.o src/lion_dir_delete.o src/lion_posting.o src/lion_posting_delete.o src/lion_postree.o src/lion_posbuild.o src/lion_posfilter.o src/lion_bm25.o src/lion_bm25_scan.o src/lion_reader.o \ src/lion_am.o src/lion_amcost.o src/lion_build.o src/lion_spool.o src/lion_scan.o \ src/lion_insert.o src/lion_vacuum.o $(FUNCS_OBJS) $(COUNT_OBJS) $(CUSTOMSCAN_OBJS) \ src/lion_multikey.o src/lion_jsonb.o src/lion_fkjoin.o src/lion_ordered.o src/lion_selfuncs.o \ src/lion_costs.o src/lion_arena.o $(VEC_OBJS) $(READAHEAD_OBJS) PGFILEDESC = "pg_lion - roaring bitmap inverted index" EXTENSION = pg_lion pg_lion_citext pg_lion_vector DATA = $(foreach e,$(EXTENSION),$(wildcard $(e)--*.sql)) REGRESS = $(patsubst test/sql/%.sql,%,$(sort $(wildcard test/sql/*.sql))) REGRESS_OPTS = --inputdir=test --outputdir=test ISOLATION = $(patsubst test/isolation/%.spec,%,$(sort $(wildcard test/isolation/*.spec))) ISOLATION_OPTS = --inputdir=test/isolation --outputdir=test/isolation PG_CFLAGS = -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Isrc # `make WERROR=1` makes every warning an error, here and in the unit tests; CI # builds that way on every supported major. The two -Wno- flags stay: the # PostgreSQL headers themselves trip both. ifeq ($(WERROR),1) PG_CFLAGS += -Werror endif # `make LION_NO_SIMD=1` leaves out the x86-64 kernels - the container # library's AVX2 and POPCNT ones, lion_planes.c's AVX-512, AVX2 and POPCNT # ones (lionvec's plane 1 among them) and lionvec's AVX2 and F16C ones - # which x86-64 GCC and clang builds pick between at run time (DESIGN.md §3, # "Whole-bitset kernels"; §44.3, "Kernels"; §50), and runs the portable ones # everywhere. The unit tests always build a copy that way too. ifeq ($(LION_NO_SIMD),1) PG_CFLAGS += -DLION_NO_SIMD endif # lionvec's arithmetic is compiled without fused multiply-adds, which GCC # and clang would otherwise make of a multiply and an add wherever the target # has them - aarch64, an x86-64 baseline such as x86-64-v3 - so that it rounds # as written everywhere and its kernels agree to the bit (DESIGN.md §44.3, # "Kernels"); the unit tests compile it so too. VEC_MATH_CFLAGS = -ffp-contract=off src/lion_vec_math.o: override CFLAGS += $(VEC_MATH_CFLAGS) src/lion_vec_math.bc: override BITCODE_CFLAGS += $(VEC_MATH_CFLAGS) EXTRA_CLEAN = test/unit/container_test test/unit/container_test_nosimd test/unit/sparse_test test/unit/positions_test \ test/unit/waldelta_test test/unit/entry_test test/unit/vec_test test/unit/vec_test_nosimd \ test/unit/readahead_test test/unit/arena_test \ test/unit/planes_test test/unit/planes_test_nosimd test/unit/planes_bench test/unit/vecplanes_eval \ test/results test/isolation/results # Every object and dependency file in src, not only those OBJS names now, so # that a source removed or renamed leaves no object behind. EXTRA_CLEAN += src/*.o src/*.d src/*.bc PG_CONFIG ?= $(if $(wildcard .local/pg/bin/pg_config),.local/pg/bin/pg_config,pg_config) PGXS := $(shell $(PG_CONFIG) --pgxs) # The isolation specs that park a backend on an injection point need a server # configured with --enable-injection-points (PostgreSQL 17 or later) and the # injection_points test module installed. Where that module is missing they # are left out, and the run says so; INJECTION_POINTS=1/0 overrides the guess. INJECTION_SPECS = $(patsubst test/isolation/%.spec,%,$(shell grep -l injection_points test/isolation/*.spec)) INJECTION_POINTS ?= $(if $(wildcard $(shell $(PG_CONFIG) --sharedir)/extension/injection_points.control),1,0) ifneq ($(INJECTION_POINTS),1) ISOLATION := $(filter-out $(INJECTION_SPECS),$(ISOLATION)) $(info pg_lion: no injection_points module in this installation; skipping isolation specs: $(INJECTION_SPECS)) endif # lionvec's tests (test/sql/vector*.sql, test/isolation/lionvec_*.spec) need # pgvector installed; where it is missing they are left out, and the run says # so; PGVECTOR=1/0 overrides the guess. VECTOR_TESTS = $(patsubst test/sql/%.sql,%,$(sort $(wildcard test/sql/vector*.sql))) VECTOR_SPECS = $(patsubst test/isolation/%.spec,%,$(sort $(wildcard test/isolation/lionvec_*.spec))) PGVECTOR ?= $(if $(wildcard $(shell $(PG_CONFIG) --sharedir)/extension/vector.control),1,0) ifneq ($(PGVECTOR),1) REGRESS := $(filter-out $(VECTOR_TESTS),$(REGRESS)) ISOLATION := $(filter-out $(VECTOR_SPECS),$(ISOLATION)) $(info pg_lion: no pgvector in this installation; skipping tests: $(VECTOR_TESTS) $(VECTOR_SPECS)) endif include $(PGXS) # Standalone unit tests for the container library (no server needed). UNIT_CFLAGS = -O1 -g -Wall -Wextra -Wno-unused-parameter -DFRONTEND -Isrc \ -I$(shell $(PG_CONFIG) --includedir-server) -I$(shell $(PG_CONFIG) --includedir) ifeq ($(WERROR),1) UNIT_CFLAGS += -Werror endif ifeq ($(LION_NO_SIMD),1) UNIT_CFLAGS += -DLION_NO_SIMD endif # pkglibdir first: the Debian/Ubuntu packages put the server's own # libpgcommon.a and libpgport.a there, while libdir holds libpq-dev's copies, # which are of whatever major libpq-dev is at. Source builds have them in # libdir only. UNIT_LDFLAGS = -L$(shell $(PG_CONFIG) --pkglibdir) -L$(shell $(PG_CONFIG) --libdir) -lpgcommon -lpgport -lm # `make unit SANITIZE=1` builds the unit tests with AddressSanitizer and # UndefinedBehaviorSanitizer and makes every report fatal, which CI does on # every major. The unit tests are frontend programs that link nothing but # libpgcommon and libpgport, so the sanitizers need no help from the server, # and they are what feeds the container and sparse code malformed input. The # binaries are always rebuilt under SANITIZE=1: a plain `make unit` leaves # binaries that are up to date by their sources, and running those would # silently test nothing extra. (The reverse is harmless: a plain `make unit` # after a sanitized one runs the sanitized binaries until a source changes.) ifeq ($(SANITIZE),1) UNIT_CFLAGS += -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer UNIT_LDFLAGS += -fsanitize=address,undefined test/unit/container_test test/unit/container_test_nosimd test/unit/sparse_test test/unit/positions_test \ test/unit/waldelta_test test/unit/entry_test test/unit/vec_test test/unit/vec_test_nosimd \ test/unit/readahead_test test/unit/arena_test \ test/unit/planes_test test/unit/planes_test_nosimd: .lion-force-unit .PHONY: .lion-force-unit endif # The container library picks its whole-bitset kernels by the extension's # one choice of SIMD implementation, which lion_planes.c holds, so every test # that links the library links that too. test/unit/container_test: test/unit/container_test.c src/lion_container.c src/lion_planes.c \ src/lion_container.h src/lion_planes.h src/lion_tid.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/container_test.c src/lion_container.c src/lion_planes.c $(UNIT_LDFLAGS) # The same tests with -DLION_NO_SIMD: the build without the x86-64 kernels, # which must refuse to force them and run the portable one. On an x86-64 # host also -mpopcnt, which makes that kernel the fused loop other # architectures run, where x86 built for its baseline counts through # pg_popcount() - which container_test covers when it forces the portable # kernel. UNIT_NOSIMD_CFLAGS = -DLION_NO_SIMD $(if $(filter x86_64 amd64,$(shell uname -m)),-mpopcnt) test/unit/container_test_nosimd: test/unit/container_test.c src/lion_container.c src/lion_planes.c \ src/lion_container.h src/lion_planes.h src/lion_tid.h $(CC) $(UNIT_CFLAGS) $(UNIT_NOSIMD_CFLAGS) -o $@ test/unit/container_test.c src/lion_container.c src/lion_planes.c \ $(UNIT_LDFLAGS) test/unit/sparse_test: test/unit/sparse_test.c src/lion_sparse.c src/lion_container.c src/lion_planes.c \ src/lion_sparse.h src/lion_positions.h src/lion_container.h src/lion_planes.h \ src/lion_tid.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/sparse_test.c src/lion_sparse.c src/lion_container.c src/lion_planes.c \ $(UNIT_LDFLAGS) test/unit/positions_test: test/unit/positions_test.c src/lion_positions.c \ src/lion_positions.h src/lion_container.h src/lion_planes.h src/lion_tid.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/positions_test.c src/lion_positions.c $(UNIT_LDFLAGS) # The WAL's item encoding (DESIGN.md §25, LION_OP_DELTA and LION_OP_SPLICE): # what the writer logs and what the redo rebuilds from it, round-tripped. test/unit/waldelta_test: test/unit/waldelta_test.c src/lion_waldelta.c src/lion_waldelta.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/waldelta_test.c src/lion_waldelta.c $(UNIT_LDFLAGS) test/unit/entry_test: test/unit/entry_test.c src/lion_entryfmt.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/entry_test.c $(UNIT_LDFLAGS) # lionvec's arithmetic (DESIGN.md §44.3 - §44.4): the rotation, the codes, the # kernels and how often the estimates' bounds hold; and the same without the # x86-64 kernels, as container_test_nosimd is built. Its plane-1 kernel and # its choice of kernels are lion_planes.c's, linked with it. VEC_TEST_SRCS = test/unit/vec_test.c src/lion_vec_math.c src/lion_planes.c VEC_TEST_DEPS = $(VEC_TEST_SRCS) src/lion_vec_math.h src/lion_planes.h test/unit/vec_test: $(VEC_TEST_DEPS) $(CC) $(UNIT_CFLAGS) $(VEC_MATH_CFLAGS) -o $@ $(VEC_TEST_SRCS) $(UNIT_LDFLAGS) test/unit/vec_test_nosimd: $(VEC_TEST_DEPS) $(CC) $(UNIT_CFLAGS) $(VEC_MATH_CFLAGS) $(UNIT_NOSIMD_CFLAGS) -o $@ $(VEC_TEST_SRCS) $(UNIT_LDFLAGS) # Bit-plane arithmetic and the choice of SIMD implementation (DESIGN.md §50): # every implementation's popcounts per plane, in both layouts, against a # count a bit at a time, the transpose and the values' planes both ways; and # against lionvec's own plane-1 kernel and query planes, so lionvec's # arithmetic is linked and compiled as vec_test compiles it. Again without # the x86-64 kernels. `make planes-bench` times the kernels, built at -O2. PLANES_TEST_SRCS = test/unit/planes_test.c src/lion_planes.c src/lion_vec_math.c PLANES_TEST_DEPS = $(PLANES_TEST_SRCS) src/lion_planes.h src/lion_vec_math.h test/unit/planes_test: $(PLANES_TEST_DEPS) $(CC) $(UNIT_CFLAGS) $(VEC_MATH_CFLAGS) -o $@ $(PLANES_TEST_SRCS) $(UNIT_LDFLAGS) test/unit/planes_test_nosimd: $(PLANES_TEST_DEPS) $(CC) $(UNIT_CFLAGS) $(VEC_MATH_CFLAGS) $(UNIT_NOSIMD_CFLAGS) -o $@ $(PLANES_TEST_SRCS) $(UNIT_LDFLAGS) test/unit/planes_bench: $(PLANES_TEST_DEPS) $(CC) $(UNIT_CFLAGS) $(VEC_MATH_CFLAGS) -O2 -DNDEBUG -o $@ $(PLANES_TEST_SRCS) $(UNIT_LDFLAGS) .PHONY: planes-bench planes-bench: test/unit/planes_bench ./test/unit/planes_bench --bench # An evaluation, not a test (DESIGN.md §44.14): whether lionvec's 8-bit codes # kept as bit-planes 2 to 8 would let a refine stop early - the planes a # refine needs on vec_test's kinds of data, and what a plane's sum costs # against the codes' - linked as vec_test is, built at -O2. Not in `make # unit`: it takes minutes, and what it prints is measurements. test/unit/vecplanes_eval: test/unit/vecplanes_eval.c $(VEC_TEST_DEPS) $(CC) $(UNIT_CFLAGS) $(VEC_MATH_CFLAGS) -O2 -DNDEBUG -o $@ test/unit/vecplanes_eval.c \ src/lion_vec_math.c src/lion_planes.c $(UNIT_LDFLAGS) .PHONY: vecplanes-eval vecplanes-eval: test/unit/vecplanes_eval ./test/unit/vecplanes_eval # The read stream ring's bookkeeping (DESIGN.md §44.4, "Read streams"), # against a model of core's read stream. test/unit/readahead_test: test/unit/readahead_test.c src/lion_readahead_ring.c src/lion_readahead_ring.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/readahead_test.c src/lion_readahead_ring.c $(UNIT_LDFLAGS) # The arena a LionOrdered set spills to (DESIGN.md §30.4, "Spilling"): the # size classes, the free lists, the regions over a temporary file, reset and # release, against a shadow model. test/unit/arena_test: test/unit/arena_test.c src/lion_arena.c src/lion_arena.h $(CC) $(UNIT_CFLAGS) -o $@ test/unit/arena_test.c src/lion_arena.c $(UNIT_LDFLAGS) .PHONY: unit unit: test/unit/planes_test test/unit/planes_test_nosimd \ test/unit/container_test test/unit/container_test_nosimd test/unit/sparse_test test/unit/positions_test \ test/unit/waldelta_test test/unit/entry_test test/unit/vec_test test/unit/vec_test_nosimd \ test/unit/readahead_test test/unit/arena_test ./test/unit/planes_test ./test/unit/planes_test_nosimd ./test/unit/container_test ./test/unit/container_test_nosimd ./test/unit/sparse_test ./test/unit/positions_test ./test/unit/waldelta_test ./test/unit/entry_test ./test/unit/vec_test ./test/unit/vec_test_nosimd ./test/unit/readahead_test ./test/unit/arena_test # Header dependencies, made by the compiler: each object's .d file lists every # header its source includes, so no hand-kept list can miss one and leave a # stale object with an old struct layout after a header change. A server # configured with --enable-depend already does this in its own rules (into # .deps/); elsewhere - the distributions' packages are not - it is done here. # -MP keeps a deleted header from breaking the build. ifneq ($(autodepend),yes) override CFLAGS += -MMD -MP -include $(OBJS:.o=.d) endif # Crash-recovery and hot-standby tests (test/recovery/README.md). These need a # whole PostgreSQL *installation* to initdb their own private clusters into, # not just a pg_config, and they install the extension into it, so the prefix # is named separately rather than derived from PG_CONFIG: # # make recovery-check PG_CONFIG=/bin/pg_config RECOVERY_PREFIX= # # RECOVERY_PREFIX is REQUIRED: run.sh refuses to start without it rather than # guess, and it is deliberately not derived from PG_CONFIG, so a bare "make # recovery-check" can never install into whatever installation the dev cluster # happens to use. As root (a container, a CI image) also set # RECOVERY_RUN_AS=, because initdb and postgres refuse to # run as root. Nothing here touches the dev cluster: run.sh creates its own # clusters in a private mktemp -d directory, with the socket directory inside # it, and removes that directory on exit. RECOVERY_PREFIX ?= EXTRA_CLEAN += test/recovery/log # What the expected outputs assume of the server, established by installcheck # itself rather than left to whichever cluster it runs against. The session # settings go to every connection the suite makes, regression and isolation # alike, through PGOPTIONS: plans and their EXPLAIN shapes depend on them, and # a test that needs another value SETs it, as before. ./dev.sh's cluster sets # the same values server-wide. What a session cannot set is checked first: # the contrib modules some tests read pages and WAL with, whose absence # otherwise shows up as a dozen unrelated diffs. LION_TEST_OPTIONS = -c work_mem=64MB -c maintenance_work_mem=1GB \ -c max_parallel_workers_per_gather=0 \ -c max_parallel_maintenance_workers=0 -c jit=off LION_TEST_EXTENSIONS = citext pageinspect pg_buffercache pg_freespacemap pg_walinspect installcheck: export PGOPTIONS := $(PGOPTIONS) $(LION_TEST_OPTIONS) installcheck: lion-test-env .PHONY: lion-test-env lion-test-env: @missing=$$($(bindir)/psql -X -At -d postgres -c "SELECT string_agg(e, ' ') FROM unnest(string_to_array('$(LION_TEST_EXTENSIONS)', ' ')) e WHERE e NOT IN (SELECT name FROM pg_available_extensions)") || exit 1; \ if [ -n "$$missing" ]; then \ echo "pg_lion: the server has no $$missing extension, which the tests need (install PostgreSQL's contrib modules)" >&2; \ exit 1; \ fi # The whole suite with the custom WAL resource manager registered (DESIGN.md # §25). The resource manager can only be registered from # shared_preload_libraries, and a preloaded library is loaded once at # postmaster start, so this RESTARTS the dev cluster with the option on the # command line, runs installcheck, and restarts it back into generic mode. # Nothing is written into postgresql.conf, so an interrupted run leaves no # trace. # # make installcheck-rmgr # make installcheck-rmgr WAL_CONSISTENCY=1 ... and replay every page and # compare it, which is the # proof that redo reproduces # them .PHONY: installcheck-rmgr installcheck-rmgr: WAL_CONSISTENCY=$(if $(WAL_CONSISTENCY),$(WAL_CONSISTENCY),0) \ PG_CONFIG="$(PG_CONFIG)" ./test/rmgr-check.sh # pg_lion beside another extension that chains the same planner hook and # registers its own WAL resource manager, in both load orders (DESIGN.md §23), # the table-AM refusals that need a table AM other than the heap (§2), # counts on a pool of sixteen buffers, which the pin budgets must fit (§15), # and, on PostgreSQL 16, that no lion index is read while # old_snapshot_threshold is set (§9). # Builds and installs the test-only test/modules/lion_hooktest into the # installation PG_CONFIG names, and restarts the dev cluster as # installcheck-rmgr does. # # make hookcheck # make hookcheck HOOKCHECK_FULL=1 ... and the whole suite in both preload # orders .PHONY: hookcheck hookcheck: HOOKCHECK_FULL=$(if $(HOOKCHECK_FULL),$(HOOKCHECK_FULL),0) WERROR=$(if $(WERROR),$(WERROR),0) \ PG_CONFIG="$(PG_CONFIG)" ./test/hook-check.sh # The extensions' SQL versions (DESIGN.md §23, "Extension versions"): the # lint, against UPGRADE_BASE (default origin/main) when that names a commit, # then ALTER EXTENSION ... UPDATE from every earlier install script in the git # history, each against a fresh install of the current one. Needs the build # installed, the dev cluster running (eval "$(./dev.sh env)"), write access to # the installation's extension directory, and the full git history. # # make upgradecheck # make upgradecheck UPGRADE_BASE=HEAD~1 UPGRADE_BASE ?= origin/main .PHONY: upgradecheck upgradecheck: ./test/upgrade/lint.py $(shell git rev-parse -q --verify '$(UPGRADE_BASE)^{commit}' >/dev/null && echo '$(UPGRADE_BASE)') PG_CONFIG="$(PG_CONFIG)" ./test/upgrade/run.sh .PHONY: recovery-check recovery-check: ./test/recovery/run.sh $(if $(RECOVERY_PREFIX),--prefix "$(RECOVERY_PREFIX)") \ $(if $(RECOVERY_MODE),--mode $(RECOVERY_MODE)) \ $(if $(WAL_CONSISTENCY),--conf "wal_consistency_checking = '$(if $(filter rmgr,$(RECOVERY_MODE)),pg_lion,generic)'") # The same harness with the custom WAL resource manager registered and every # page of every lion record replayed and compared (DESIGN.md §25). This is # the proof that redo reproduces the writer's pages: the standby replays # everything phase 1 and phase 2 write, and a mismatch is a FATAL in the # startup process. .PHONY: recovery-check-rmgr recovery-check-rmgr: ./test/recovery/run.sh $(if $(RECOVERY_PREFIX),--prefix "$(RECOVERY_PREFIX)") \ --mode rmgr --conf "wal_consistency_checking = 'pg_lion'" # The concurrent write + VACUUM + count soak (test/soak/README.md): the dev # cluster restarted into each WAL mode in turn, as installcheck-rmgr does, # with a hot standby in rmgr mode, and put back afterwards. # # make soak 10 minutes a mode # make soak SOAK_DURATION=120 SOAK_MODES=rmgr # make soak SOAK_RUN_AS= as root: the cluster's user .PHONY: soak soak: PG_CONFIG="$(PG_CONFIG)" ./test/soak/modes.sh # The PGXN release archive: pg_lion-.zip, made by git archive from # the committed HEAD, so it holds exactly the tracked files named here - what # PGXS needs, the documentation and the test suites - and nothing from the # working tree (.local, benchmark results, build products, .deps). The # version is META.json's; the extension's own version is the control files' # default_version, and the two map as DESIGN.md section 23 says. DIST_VERSION = $(shell sed -n 's/^ "version": "\(.*\)",$$/\1/p' META.json) DIST_NAME = pg_lion-$(DIST_VERSION) DIST_FILES = META.json README.md LICENSE DESIGN.md docs Makefile dev.sh \ $(addsuffix .control,$(EXTENSION)) $(DATA) src \ test/sql test/expected test/isolation test/unit test/recovery test/rmgr-check.sh \ test/hook-check.sh test/modules .PHONY: dist dist: @test -n "$(DIST_VERSION)" || { echo "no version in META.json" >&2; exit 1; } @git diff --quiet HEAD -- $(DIST_FILES) || \ echo "warning: uncommitted changes are not in $(DIST_NAME).zip, which is built from HEAD" >&2 git archive --format=zip --prefix=$(DIST_NAME)/ -o $(DIST_NAME).zip HEAD -- $(DIST_FILES)