INTERNAL = Makefile.internal ARGS = with_llvm=no ifdef DEBUG ARGS+=DEBUG=1 endif UNAME := $(shell uname) ifeq ($(UNAME), Darwin) PAGER ?= less else PAGER ?= pager endif # Parallelism for the instrumented coverage rebuild (portable nproc). NPROC ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) # --------------------------------------------------------------------------- # This is a thin "porcelain" wrapper. The real build (the PGXS targets: all, # install, clean, installcheck, tdkc, ...) lives in Makefile.internal; the # catch-all `%:` rule below forwards any target not defined here down to it. # Targets defined here (test, docs, website, deploy, the studio/playground/ # wasm helpers) override that forward. Run `make help` for the menu. # # Note: because of the `%:` forward, a mistyped target (e.g. `make instal`) # is silently passed to Makefile.internal, which then errors -- not the # wrapper. Check `make help` if a target behaves unexpectedly. # --------------------------------------------------------------------------- .PHONY: default default: $(MAKE) -f $(INTERNAL) $(ARGS) %: $(MAKE) -f $(INTERNAL) $@ $(ARGS) ## =========================================================================== ## Build (delegated to Makefile.internal / PGXS) ## =========================================================================== ## make Build the extension (default) ## install Install into the local PostgreSQL (PGXS) ## clean Remove build artefacts (PGXS + EXTRA_CLEAN) ## tdkc Build the tree-decomposition knowledge-compiler binary ## provsql_migrate_mmap Build the mmap circuit-store migration helper .PHONY: tdkc provsql_migrate_mmap tdkc provsql_migrate_mmap: $(MAKE) -f $(INTERNAL) $@ $(ARGS) ## =========================================================================== ## Test & QA ## =========================================================================== ## test Run the SQL/C regression suite (pg_regress, via tdkc) .PHONY: test test: tdkc bash -c "set -o pipefail && bash test/kcmcp/with-tdkc.sh make installcheck 2>&1 | tee test.log" || $(PAGER) `grep regression.diffs test.log | perl -pe 's/.*?"//;s/".*//'` # Test coverage: rebuild the C/C++ extension instrumented, then run the full # suite against a throwaway PostgreSQL cluster owned by the invoking user (see # test/coverage/run-coverage.sh). Produces a gcovr line+branch report under # coverage/ plus coverage/zero_call.txt, the provsql functions the suite never # calls. The cluster loads the instrumented build from a private staging prefix, # so NOTHING is installed into the system PostgreSQL and no sudo is needed; this # requires PostgreSQL >= 18. See test/coverage/README.md. Needs gcovr # (pipx install gcovr). tdkc is (re)built uninstrumented so the kcmcp client # tests run instead of skipping. # # make coverage # make coverage PROVSQL_COVERAGE_PORT=55000 GCOVR=~/.local/bin/gcovr ## coverage Instrumented rebuild + gcovr line/branch report GCOVR ?= gcovr .PHONY: coverage coverage: $(MAKE) -f $(INTERNAL) clean $(ARGS) $(MAKE) -f $(INTERNAL) -j $(NPROC) COVERAGE=1 $(ARGS) $(MAKE) -f $(INTERNAL) tdkc $(ARGS) GCOVR="$(GCOVR)" bash test/coverage/run-coverage.sh @echo "The system PostgreSQL was untouched; restore the normal local build with: make" # Upgrade-chain parity: a database upgraded from 1.0.0 must be # catalog-identical to a fresh install (the strong form of the # extension_upgrade canary; run before every release). Pass psql # options via PSQL_ARGS, e.g. make test-upgrade-parity PSQL_ARGS=--port=5434 ## test-upgrade-parity Prove an upgraded DB == a fresh install (catalog parity) .PHONY: test-upgrade-parity test-upgrade-parity: test/upgrade_parity.sh $(PSQL_ARGS) ## lint-studio ruff check over the Studio Python .PHONY: lint-studio lint-studio: cd studio && ruff check . ## test-studio Studio unit tests (ruff first, then pytest; no e2e) .PHONY: test-studio test-studio: lint-studio # tests/web (browser/PGlite e2e) needs the assembled doc-root + headless # Chromium; run it separately with `make test-playground`. cd studio && python3 -m pytest tests --ignore=tests/web ## =========================================================================== ## Docs & website ## =========================================================================== # Regenerate the Studio example notebooks (tutorial + case studies) # from the annotated user-guide .rst sources. Also a prerequisite of # `make docs`, so editing an annotated .rst cannot leave the committed # .ipynb files under studio/provsql_studio/notebooks/ stale. Skipped # with a warning where pandoc is missing (e.g. the docs CI runner): # regeneration is a repo-maintenance step, not a docs artifact. ## notebooks Regenerate the Studio example notebooks from .rst .PHONY: notebooks notebooks: @if command -v pandoc >/dev/null; then \ python3 studio/scripts/rst2nb.py; \ else \ echo "WARNING: pandoc not found; skipping example-notebook regeneration"; \ fi ## docs Build the Sphinx HTML documentation .PHONY: docs docs: notebooks # Regenerate the concatenated sql/provsql.sql (the Doxygen SQL input, built # from sql/provsql.common.sql + sql/provsql.14.sql) via Makefile.internal, # whose rule tracks those sources. Delegating is required: listing # sql/provsql.sql as a bare prerequisite here resolves it through the # catch-all `%:' rule, which carries no prerequisites, so an existing but # stale file is treated as up-to-date and SQL docstring edits never reach # the generated API reference. $(MAKE) -f $(INTERNAL) sql/provsql.sql $(ARGS) cd doc/source && make html ## website Build docs + assemble the Jekyll site .PHONY: website website: docs # Copy branding assets into website source cp -r branding/fonts/. website/assets/fonts cp branding/logo.png website/assets/images/logo.png cp branding/favicon.ico website/assets/images/favicon.ico cp branding/favicon.ico website/favicon.ico # Generate SCSS partial for fonts (adjust path from fonts/ to ../fonts/) sed "s|url('fonts/|url('../fonts/|g" branding/fonts-face.css > website/assets/css/_fonts-face.scss # Copy generated docs into Jekyll source tree so jekyll serve also sees them. # rsync --delete so files removed upstream (e.g. retired sql/index.rst) # don't linger as stale, half-styled artifacts under website/docs/. # --omit-dir-times: setting a directory's mtime needs ownership, not just # write access, so it fails when the staging dirs are owned by another user # sharing the repo (group-writable); file times are still preserved. mkdir -p website/docs website/doxygen-sql/html website/doxygen-c/html rsync -a --omit-dir-times --delete doc/source/_build/html/ website/docs/ rsync -a --omit-dir-times --delete doc/doxygen-sql/html/ website/doxygen-sql/html/ rsync -a --omit-dir-times --delete doc/doxygen-c/html/ website/doxygen-c/html/ cd website && bundle exec jekyll build ## deploy Build the website and rsync it to provsql.org .PHONY: deploy deploy: website # -c hashes content so Jekyll's fresh mtimes don't trigger spurious transfers rsync -avzcP website/_site/ provsql:/var/www/provsql/ ## =========================================================================== ## Playground & WASM (in-browser build; heavy, local-only) ## =========================================================================== # Reproduce the GitHub `wasm` workflow's build locally: build the PGlite WASM # core + the ProvSQL extension against the Emscripten builder image. Needs a # container runtime (podman or docker), Node/corepack, and Boost headers; it is # heavy (pulls the multi-GB builder image and compiles the PG tree). # See wasm/build-wasm.sh. ## wasm Build the PGlite + ProvSQL WASM core (container build) .PHONY: wasm wasm: wasm/build-wasm.sh # Assemble the ProvSQL Playground doc-root (the in-browser build). The heavy # WASM artifacts (the matched PGlite dist + provsql.tar.gz, from wasm/; see # studio/web/README.md) are needed only the first time, then reused in place: # # make playground PGLITE_DIST= PROVSQL_TARGZ= # first build # make playground # re-assemble (reuse) # # Re-running picks up the current Studio frontend/backend, case studies and # vendored deps without rebuilding the WASM core. ## playground Assemble the Playground doc-root (reuses WASM artifacts) .PHONY: playground playground: cd studio/web && ./build.sh \ $(if $(PGLITE_DIST),--pglite "$(PGLITE_DIST)") \ $(if $(PROVSQL_TARGZ),--provsql "$(PROVSQL_TARGZ)") # Browser e2e for the assembled Playground (headless Chromium via # pytest-playwright). Assembles the doc-root first; run `make wasm` beforehand # to test freshly built WASM artifacts rather than the in-place ones. ## test-playground Browser e2e over the assembled Playground .PHONY: test-playground test-playground: playground cd studio && python3 -m pytest tests/web # Build (above) then deploy to provsql.org/playground/. The build is # path-portable, so it needs no server config beyond serving the files (the # shipped .htaccess adds the WASM MIME type and belt-and-suspenders redirects). ## deploy-playground Assemble the Playground and rsync it to provsql.org .PHONY: deploy-playground deploy-playground: playground rsync -avzcP --delete \ --exclude=build.sh --exclude=vendor.sh --exclude=build-casestudies.py \ --exclude=serve.py --exclude=README.md --exclude=.gitignore \ studio/web/ provsql:/var/www/provsql/playground/ ## =========================================================================== ## Studio (dev server) ## =========================================================================== ## studio Run the Studio dev server (python -m provsql_studio) .PHONY: studio studio: cd studio && python3 -m provsql_studio ## =========================================================================== ## Packaging ## =========================================================================== EXTVERSION = $(shell grep default_version provsql.common.control | \ sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/") ## docker-build Build the provsql Docker image (runs `clean` first) .PHONY: docker-build docker-build: make clean docker build -f docker/Dockerfile \ --build-arg PROVSQL_VERSION=$(EXTVERSION) \ -t provsql:$(EXTVERSION) . ## =========================================================================== ## Help ## =========================================================================== ## help Show this target menu .PHONY: help help: @grep -hE '^## ' $(firstword $(MAKEFILE_LIST)) | sed -e 's/^## //'