diff --git a/.gitignore b/.gitignore index 3ad5050..011f240 100644 --- a/.gitignore +++ b/.gitignore @@ -4,12 +4,12 @@ results/ *.dll tmp/ *.o +*.bc regression.diffs regression.out /sql/semver--?.??.?.sql /semver-* /latest-changes.md -/src/*.bc /semver_binary_copy.bin /.vscode /*.bin diff --git a/Makefile b/Makefile index 8777ed1..837d9ce 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,9 @@ DISTVERSION = $(shell grep -m 1 '[[:space:]]\{3\}"version":' META.json | \ sed -e 's/[[:space:]]*"version":[[:space:]]*"\([^"]*\)",\{0,1\}/\1/') MODULEDIR = $(EXTENSION) -DATA = $(wildcard sql/*.sql) +DESCRIPTION = A Postgres data type for the Semantic Version format with support for btree and hash indexing. +REPO_URL = https://github.com/theory/pg-semver +DATA = $(wildcard sql/*--*.sql) sql/$(EXTENSION)--$(EXTVERSION).sql DOCS = $(wildcard doc/*.mmd) TESTS = $(wildcard test/sql/*.sql) REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) @@ -22,6 +24,7 @@ endif PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) +include ./trunk.mk all: sql/$(EXTENSION)--$(EXTVERSION).sql diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..323723e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +version: "3.9" +name: trunking + +# Name the network for all of the services to join. +networks: + default: + name: pgxnnet + +services: + zot: + image: ghcr.io/project-zot/zot-linux-arm64:latest + container_name: zot + ports: + - 5000:5000 + hostname: zot + + linux: + image: pgxn/pgxn-tools + platform: "linux/amd64" + container_name: linux + # stdin_open: true + # tty: true # Keep it running + working_dir: /work + volumes: + - ".:/work" + entrypoint: + - "/bin/sh" + - -ecx + - | + cd /tmp + curl -LO "https://github.com/oras-project/oras/releases/download/v1.2.0/oras_1.2.0_linux_amd64.tar.gz" + mkdir -p oras-install/ + tar -zxf oras_1.2.0_*.tar.gz -C oras-install/ + sudo mv oras-install/oras /usr/local/bin/ + rm -rf oras_1.2.0_*.tar.gz oras-install/ + pg-start 16 rsync jq + tail -f /dev/null diff --git a/install_trunk b/install_trunk new file mode 100755 index 0000000..1186036 --- /dev/null +++ b/install_trunk @@ -0,0 +1,155 @@ +#!/bin/bash + +# POC for installing Trunk format binaries created with trunk.mk. Requires: +# +# * bash +# * tar +# * shasum +# * jq +# * uname +# * pg_config +# * rsync + +trap 'exit' ERR +set -E + +install_trunk() { + local trunk=$1 + + if [ -z "$trunk" ]; then + printf "Usage:\n\n %s PACKAGE_PATH\n" "$0" + exit 1 + fi + + # Determine the platform. + local my_os my_osv my_arch platform + my_os=$(uname | tr '[:upper:]' '[:lower:]') + my_osv=$(uname -r) + my_arch="$(uname -m)" + if [ "$my_arch" == "x86_64" ]; then my_arch=amd64; fi + if [ "$my_os" == "darwin" ]; then + platform="$my_os/$my_arch:$my_osv" + else + platform="$my_os/$my_arch" + fi + + # Fetch the file name. + local file + file=$(oras manifest fetch --plain-http --platform "$platform" "$trunk" | jq -r '.layers[0].annotations["org.opencontainers.image.title"]') + + # Download. + oras pull --no-tty --plain-http --platform "$platform" "$trunk" + + # Unpack. + printf "Unpacking %s\n" "$file" + tar zxf "$file" + + # Go into the directory + local dir="${file%.*}" + cd "$dir" || exit + + # Verify the checksums. + printf "Verifying all checksums..." + shasum --check -b --strict < digests + printf "Done!\n" + + # Verify the Trunk version + printf "Verifying compatibility with Trunk package 0.1.0\n" + local tv + tv=$(jq -r .trunk trunk.json) + if [ "$tv" != "0.1.0" ]; then + printf "Unsupported Trunk format version %s\n" "$tv" + exit 1 + fi + + # Verify the Postgres version. + printf "Verifying compatibility with PostgreSQL %s\n" "$my_pg" + local pkg_pg my_pg + pkg_pg=$(jq -r .postgres.version trunk.json) + my_pg=$(pg_config --version | sed -E 's/^[^ ]+ ([^ ]+).*$/\1/') + if [ "$pkg_pg" != "$my_pg" ]; then + printf "Trunk package contains binaries for Postgres %s but this host runs Postgres %s\n" "$pkg_pg" "$my_pg" + exit 1 + fi + + printf "Verifying compatibility with %s/%s:%s \n" "$my_os" "$my_arch" "$my_osv" + local pkg_os + pkg_os=$(jq -r .platform.os trunk.json) + if [ "$pkg_os" != "any" ]; then + # Verify the OS + if [ "$pkg_os" != "$my_os" ]; then + printf "Trunk package contains %s binaries but this host runs %s\n" "$pkg_os" "$my_os" + exit 1 + fi + + # Verify the architecture. + local pkg_arch + pkg_arch=$(jq -r .platform.arch trunk.json) + if [ "$pkg_arch" != "$my_arch" ]; then + printf "Trunk package contains %s binaries but this host runs %s\n" "$pkg_arch" "$my_arch" + exit 1 + fi + fi + + # Make sure we have install directories. + if [ ! -d 'install' ]; then + printf "Package contains no install files; exiting\n" + exit 1 + fi + + cd 'install' || exit + for subdir in *; do + [[ -d "$subdir" ]] || continue + case $subdir in + share) + install_dir "$subdir" "$(pg_config --sharedir)" + ;; + pkglib) + install_dir "$subdir" "$(pg_config --pkglibdir)" + ;; + pkginclude) + install_dir "$subdir" "$(pg_config --pkgincludedir)" + ;; + lib) + install_dir "$subdir" "$(pg_config --libdir)" + ;; + include) + install_dir "$subdir" "$(pg_config --includedir)" + ;; + bin) + install_dir "$subdir" "$(pg_config --bindir)" + ;; + doc) + install_dir "$subdir" "$(pg_config --docdir)" + ;; + man) + install_dir "$subdir" "$(pg_config --mandir)" + ;; + html) + install_dir "$subdir" "$(pg_config --htmldir)" + ;; + locale) + install_dir "$subdir" "$(pg_config --localedir)" + ;; + sysconf) + install_dir "$subdir" "$(pg_config --sysconfdir)" + ;; + *) + printf "Unknown install directory %s; skipping\n" "$subdir" + ;; + esac + done + +} + +install_dir() { + local src="$1" + local dst="$2" + printf "Installing %s into %s..." "$src" "$dst" + cd "$src" || exit + rsync -q -a -v . "$dst" || exit + printf "Done\n" + cd .. +} + +install_trunk "$@" diff --git a/push_trunk b/push_trunk new file mode 100755 index 0000000..cd5d993 --- /dev/null +++ b/push_trunk @@ -0,0 +1,96 @@ +#!/bin/bash + +# POC for publishing Trunk packages to an OCI repository with an image index +# to allow pulling a platform-specific binary. Requires: +# +# * oras +# * jq +# * zot: docker run -d -p 5000:5000 --name oras-quickstart ghcr.io/project-zot/zot-linux-arm64:latest +# +# Inspired by the Homebrew implementation of the pattern as referenced in +# https://github.com/oras-project/oras/issues/237, and with thanks to the +# denizens of the #oras and #zot channels on the CNCF Slack. + +set -e + +# Onlyl testing semver for Darwin and Linux rn. +REPO=localhost:5000/theory/semver +LINUX_AMD64_TRUNK=semver-0.32.1+pg16-linux-amd64 +DARWIN_ARM64_TRUNK=semver-0.32.1+pg16-darwin-arm64-23.5.0 + +# OCI types to create. +ARTIFACT_TYPE=application/vnd.pgxn.trunk.layer.v1 +MEDIA_TYPE=application/vnd.oci.image.layer.v1.tar+gzip +CONFIG_TYPE=application/vnd.oci.image.config.v1+json +OCI_DIR=oci_dir +INDEX_FILE=image_index.json + +# Push the Darwin image and grab the resulting digest. +DIGEST_DARWIN_ARM64=$(oras push --no-tty \ + --oci-layout "$OCI_DIR" \ + --artifact-type "${ARTIFACT_TYPE}" \ + --config "${DARWIN_ARM64_TRUNK}_config.json":"$CONFIG_TYPE" \ + --format go-template='{{.digest}}' \ + --annotation-file "${DARWIN_ARM64_TRUNK}_annotations.json" \ + "$DARWIN_ARM64_TRUNK.trunk":"$MEDIA_TYPE" +) + +# Push the Linux image and grab the resulting digest. +DIGEST_LINUX_AMD64=$(oras push --no-tty \ + --oci-layout "$OCI_DIR" \ + --artifact-type "${ARTIFACT_TYPE}" \ + --config "${LINUX_AMD64_TRUNK}_config.json":"$CONFIG_TYPE" \ + --format go-template='{{.digest}}' \ + --annotation-file "${LINUX_AMD64_TRUNK}_annotations.json" \ + "$LINUX_AMD64_TRUNK.trunk":"$MEDIA_TYPE" +) + + +# Create the image manifest for Darwin. +trunk_anno=$(jq -c '.["$manifest"] | with_entries(select(.key | startswith("org.pgxn.trunk.")))' "${DARWIN_ARM64_TRUNK}_annotations.json") +DARWIN_ARM64_MANIFEST=$(oras manifest fetch --oci-layout "$OCI_DIR@${DIGEST_DARWIN_ARM64}" --pretty --descriptor | jq --argjson anno "$trunk_anno" '{ + mediaType: .mediaType, + size: .size, + digest: .digest, + platform: { + architecture: "arm64", + os: "darwin", + "os.version": "23.5.0" + }, + annotations: $anno +}') + +# Create the image manifest for Linux. +trunk_anno=$(jq -c '.["$manifest"] | with_entries(select(.key | startswith("org.pgxn.trunk.")))' "${LINUX_AMD64_TRUNK}_annotations.json") +LINUX_AMD64_MANIFEST=$(oras manifest fetch --oci-layout "$OCI_DIR@${DIGEST_LINUX_AMD64}" --pretty --descriptor | jq --argjson anno "$trunk_anno" '{ + mediaType: .mediaType, + size: .size, + digest: .digest, + platform: { + architecture: "amd64", + os: "linux" + }, + annotations: $anno +}') + +# Write out the resulting image index. +jq -n --argjson amd64 "$LINUX_AMD64_MANIFEST" --argjson arm64 "$DARWIN_ARM64_MANIFEST" --argjson annotations "$(cat semver_annotations.json)" '{ + schemaVersion: 2, + mediaType: "application/vnd.oci.image.index.v1+json", + manifests: [$amd64, $arm64], + annotations: $annotations +}' > "$INDEX_FILE" + +# Push the image index to the registry +oras manifest push --oci-layout ./"$OCI_DIR":image-index "$INDEX_FILE" + +# View the local manifest +#oras manifest get --pretty --oci-layout ./"$OCI_DIR":image-index + +# Push the index and artifacts to the registry +oras cp --from-oci-layout ./"$OCI_DIR":image-index --to-plain-http "${REPO}:v1" + +# View the remote image index manifest. +oras manifest get --plain-http "${REPO}:v1" | jq + +rm -rf "$OCI_DIR" "$INDEX_FILE" diff --git a/trunk.mk b/trunk.mk new file mode 100644 index 0000000..7057243 --- /dev/null +++ b/trunk.mk @@ -0,0 +1,290 @@ +# Trunk packaging. To use, create a standard PGXS Makefile for your extension. +# The only extra variables are DISTVERSION, TITLE, DESCRIPTION, LICENSE, +# LANGUAGE, VENDOR, URL, and REPO_URL. +# +# ``` make +# DISTVERSION = 1.2.1 +# LICENSE = mit +# LANGUAGE = c +# TITLE = Bike +# DESCRIPTION = A bicycle inside your database. +# +# EXTENSION = bike +# MODULEDIR = $(EXTENSION) +# DATA = $(wildcard sql/*.sql) +# DOCS = $(wildcard doc/*.mmd) +# MODULES = $(patsubst %.c,%,$(wildcard src/*.c)) +# PG_CONFIG ?= pg_config +# +# PGXS := $(shell $(PG_CONFIG) --pgxs) +# include $(PGXS) +# include ./trunk.mk +# ``` +# +# Then build it: +# +# ``` sh +# make trunk BUILD_TAG=2 +# ``` +# +# This will create a file with a name similar to +# +# bike-1.2.1+2-c-pg16-darwin_aarch64.trunk +# +# Requires: +# +# * pg_config +# * PGXS (from `pg_config --pgxs`) +# * tar +# * shasum +# * jq + +LAUNGUAGE ?= c +LICENSE ?= PostgreSQL +TITLE ?= $(EXTENSION) +VENDOR ?= PGXN +URL ?= $(REPO_URL) + +pkg_arch := $(shell uname -m) +ifeq ($(pkg_arch),x86_64) +pkg_arch := amd64 +endif +ifeq ($(PORTNAME),darwin) +pkg_os_ver := $(shell uname -r) +pkg := $(EXTENSION)-$(DISTVERSION)+pg$(MAJORVERSION)-$(PORTNAME)-$(pkg_arch)-$(pkg_os_ver) +else +pkg := $(EXTENSION)-$(DISTVERSION)+pg$(MAJORVERSION)-$(PORTNAME)-$(pkg_arch) +endif +pkg_dir := $(pkg) +pkg_installdir := $(pkg_dir)/install +pkg_sharedir := $(pkg_installdir)/share +pkg_libdir := $(pkg_installdir)/lib +pkg_pkglibdir := $(pkg_installdir)/pkglib +pkg_docdir := $(pkg_installdir)/doc/$(docmoduledir) +pkg_bindir := $(pkg_installdir)/bin +pkg_incdir := $(pkg_installdir)/include/server/$(docmoduledir) +ifdef SO_MAJOR_VERSION +pkg_pkgconfigdir = $(pkg_libdir)/pkgconfig +endif +pkg_info_files ?= $(wildcard README* readme* Readme* LICENSE* license* License* CHANGE* change* Change*) +EXTRA_CLEAN += $(EXTENSION)-$(DISTVERSION)+*/ + +# Phony target to create the trunk and OCI JSON files. +trunk: $(pkg).trunk $(pkg)_config.json $(pkg)_annotations.json $(EXTENSION)_annotations.json + +# Use jq to create the OCI image index annoations. +# https://github.com/opencontainers/image-spec/blob/main/annotations.md +$(EXTENSION)_annotations.json: + jq -n \ + --arg org.opencontainers.image.created "$$(date +%Y-%m-%dT%TZ)" \ + --arg org.opencontainers.image.licenses "$(LICENSE)" \ + --arg org.opencontainers.image.title "$(TITLE)" \ + --arg org.opencontainers.image.description "$(DESCRIPTION)" \ + --arg org.opencontainers.image.source "$(REPO_URL)" \ + --arg org.opencontainers.image.vendor "$(VENDOR)" \ + --arg org.opencontainers.image.ref.name "$(DISTVERSION)" \ + --arg org.opencontainers.image.version "$(DISTVERSION)" \ + --arg org.opencontainers.image.url "$(URL)" \ + '$$ARGS.named | with_entries(select(.value |. !=null and . != ""))' > $@ + +# Use jq to create the OCI image configuration. +$(pkg)_config.json: + @jq -n \ + --arg os "$(PORTNAME)" \ + --arg os.version "$(pkg_os_ver)" \ + --arg architecture "$(pkg_arch)" \ + --arg created "$$(date +%Y-%m-%dT%TZ)" \ + '$$ARGS.named | with_entries(select(.value |. !=null and . != ""))' > $@ + +# Use jq to create the OCI image manifest annotations. +$(pkg)_annotations.json: $(pkg).trunk $(pkg)_config.json + @anno=$$(jq -n \ + --arg org.opencontainers.image.created "$$(date +%Y-%m-%dT%TZ)" \ + --arg org.opencontainers.image.title "$(pkg).trunk" \ + --arg org.opencontainers.image.licenses "$(LICENSE)" \ + --arg org.opencontainers.image.description "$(DESCRIPTION)" \ + --arg org.opencontainers.image.source "$(REPO_URL)" \ + --arg org.opencontainers.image.vendor "$(VENDOR)" \ + --arg org.opencontainers.image.ref.name "$(DISTVERSION)" \ + --arg org.opencontainers.image.version "$(DISTVERSION)" \ + --arg org.opencontainers.image.url "$(URL)" \ + --arg org.pgxn.trunk.pg.version "$(VERSION)" \ + --arg org.pgxn.trunk.pg.major "$(MAJORVERSION)" \ + --arg org.pgxn.trunk.pg.version_num "$(VERSION_NUM)" \ + --arg org.pgxn.trunk.version "0.1.0" \ + '$$ARGS.named | with_entries(select(.value |. !=null and . != ""))' \ + ) && jq -n \ + --argjson '$$manifest' "$$anno" \ + '$$ARGS.named' > $@ + +$(pkg).trunk: package + tar zcvf $@ $(pkg_dir) + +# Use jq to build trunk.json. XXX Add dependencies +$(pkg_dir)/trunk.json: pkg_dirs + @pg=$$(jq -n \ + --arg version "$(VERSION)" \ + --arg major "$(MAJORVERSION)" \ + --argjson number "$(VERSION_NUM)" \ + --arg libs "$(LIBS)" \ + --arg cppflags "$(CPPFLAGS)" \ + --arg cflags "$(CFLAGS)" \ + --arg ldflags "$(LDFLAGS)" \ + '$$ARGS.named' \ + ) && pkg=$$(jq -n \ + --arg name "$(EXTENSION)" \ + --arg version $(DISTVERSION) \ + --arg language "$(LAUNGUAGE)" \ + --arg license "$(LICENSE)" \ + '$$ARGS.named' \ + ) && plat=$$(jq -n \ + --arg os "$(PORTNAME)" \ + --arg version "$(pkg_os_ver)" \ + --arg arch $(pkg_arch) \ + '$$ARGS.named | with_entries(select(.value |. !=null and . != ""))' \ + ) && jq -n \ + --arg trunk 0.1.0 \ + --argjson package "$$pkg" \ + --argjson postgres "$$pg" \ + --argjson platform "$$plat" \ + '$$ARGS.named' > $@ + + +# Based on install in https://github.com/postgres/postgres/blob/REL_17_BETA1/src/makefiles/pgxs.mk#L237C1-L276 +package: all pkg_dirs $(pkg_dir)/trunk.json +ifneq (,$(EXTENSION)) + $(INSTALL_DATA) $(addprefix $(srcdir)/, $(addsuffix .control, $(EXTENSION))) '$(pkg_sharedir)/extension/' +endif # EXTENSION +ifneq (,$(DATA)$(DATA_built)) + $(INSTALL_DATA) $(addprefix $(srcdir)/, $(DATA)) $(DATA_built) '$(pkg_sharedir)/$(datamoduledir)/' +endif # DATA +ifneq (,$(DATA_TSEARCH)) + $(INSTALL_DATA) $(addprefix $(srcdir)/, $(DATA_TSEARCH)) '$(pkg_sharedir)/tsearch_data/' +endif # DATA_TSEARCH +ifdef MODULES + $(INSTALL_SHLIB) $(addsuffix $(DLSUFFIX), $(MODULES)) '$(pkg_pkglibdir)/' +ifeq ($(with_llvm), yes) + $(foreach mod, $(MODULES), $(call package_llvm_module,$(mod),$(mod).bc)) +endif # with_llvm +endif # MODULES +ifdef DOCS +ifdef docdir + $(INSTALL_DATA) $(addprefix $(srcdir)/, $(DOCS)) '$(pkg_docdir)/' +endif # docdir +endif # DOCS +ifdef PROGRAM + $(INSTALL_PROGRAM) $(PROGRAM)$(X) '$(pkg_bindir)' +endif # PROGRAM +ifdef SCRIPTS + $(INSTALL_SCRIPT) $(addprefix $(srcdir)/, $(SCRIPTS)) '$(pkg_bindir)/' +endif # SCRIPTS +ifdef SCRIPTS_built + $(INSTALL_SCRIPT) $(SCRIPTS_built) '$(pkg_bindir)/' +endif # SCRIPTS_built +ifneq (,$(strip $(HEADER_dirs))) + $(foreach dir,$(HEADER_dirs),$(call package_headers,$(dir),$(HEADER_files_$(dir)))) +endif # HEADERS +ifdef MODULE_big +ifeq ($(with_llvm), yes) + $(call package_llvm_module,$(MODULE_big),$(OBJS)) +endif # with_llvm +package: package-lib +endif # MODULE_big +ifneq (,$(pkg_info_files)) + $(INSTALL_DATA) $(addprefix $(srcdir)/, $(pkg_info_files)) '$(pkg_dir)/' +endif + rm -f "$(pkg_dir)/digests" + cd "$(pkg_dir)/" && find * -type f | xargs shasum --tag -ba 256 > digests + +# Based on installdirs in https://github.com/postgres/postgres/blob/REL_17_BETA1/src/makefiles/pgxs.mk#L279C1-L303 +pkg_dirs: +ifneq (,$(EXTENSION)) + $(MKDIR_P) '$(pkg_sharedir)/extension' +endif +ifneq (,$(DATA)$(DATA_built)) + $(MKDIR_P) '$(pkg_sharedir)/$(datamoduledir)' +endif +ifneq (,$(DATA_TSEARCH)) + $(MKDIR_P) '$(pkg_sharedir)/tsearch_data' +endif +ifneq (,$(MODULES)) + $(MKDIR_P) '$(pkg_pkglibdir)' +endif +ifdef DOCS + $(MKDIR_P) '$(pkg_docdir)' +endif +ifneq (,$(PROGRAM)$(SCRIPTS)$(SCRIPTS_built)) + $(MKDIR_P) '$(pkg_bindir)' +endif +ifdef MODULE_big +pkg_dirs: pkg_dirs-lib +endif # MODULE_big + + +# Based on https://github.com/postgres/postgres/blob/REL_17_BETA1/src/Makefile.shlib#L364-L399. +.PHONY: package-lib package-lib-static package-lib-shared installdirs-lib +package-lib: package-lib-shared +ifdef soname +package-lib: package-lib-static +package-lib: package-lib-pc +endif + +package-lib-pc: lib$(NAME).pc installdirs-lib + $(INSTALL_DATA) $< '$(pkg_pkgconfigdir)/lib$(NAME).pc' + +package-lib-static: $(stlib) installdirs-lib + $(INSTALL_STLIB) $< '$(pkg_libdir)/$(stlib)' + +package-lib-shared: $(shlib) installdirs-lib +ifdef soname +# we don't install $(shlib) on AIX +# (see http://archives.postgresql.org/message-id/52EF20B2E3209443BC37736D00C3C1380A6E79FE@EXADV1.host.magwien.gv.at) +ifneq ($(PORTNAME), aix) + $(INSTALL_SHLIB) $< '$(pkg_libdir)/$(shlib)' +ifneq ($(PORTNAME), cygwin) +ifneq ($(PORTNAME), win32) +ifneq ($(shlib), $(shlib_major)) + cd '$(pkg_libdir)' && \ + rm -f $(shlib_major) && \ + $(LN_S) $(shlib) $(shlib_major) +endif +ifneq ($(shlib), $(shlib_bare)) + cd '$(pkg_libdir)' && \ + rm -f $(shlib_bare) && \ + $(LN_S) $(shlib) $(shlib_bare) +endif +endif # not win32 +endif # not cygwin +endif # not aix +ifneq (,$(findstring $(PORTNAME),win32 cygwin)) + $(INSTALL_SHLIB) $< '$(DESTDIR)$(bindir)/$(shlib)' +endif +else # no soname + $(INSTALL_SHLIB) $< '$(DESTDIR)$(pkglibdir)/$(shlib)' +endif + + +# Based on installdirs-lib in https://github.com/postgres/postgres/blob/REL_17_BETA1/src/Makefile.shlib#L402-L407. +pkg_dirs-lib: +ifdef soname + $(MKDIR_P) '$(pkg_libdir)' '$(pkg_pkgconfigdir)' $(if $(findstring $(PORTNAME),win32 cygwin),'$(pkg_bindir)') +else + $(MKDIR_P) '$(pkg_pkgconfigdir)' +endif + + +# Based on install_llvm_module in https://github.com/postgres/postgres/blob/REL_17_BETA1/src/Makefile.global.in#L1090-L1107. +define package_llvm_module +$(MKDIR_P) '$(DESTDIR)${bitcodedir}/$(1)' +$(MKDIR_P) $(sort $(dir $(addprefix '$(pkg_pkglibdir)/bitcode'/$(1)/, $(2)))) +$(foreach obj, ${2}, $(INSTALL_DATA) $(patsubst %.o,%.bc, $(obj)) '$(pkg_pkglibdir)/bitcode'/$(1)/$(dir $(obj)) +) +cd '$(pkg_pkglibdir)/bitcode' && $(LLVM_BINPATH)/llvm-lto -thinlto -thinlto-action=thinlink -o $(1).index.bc $(addprefix $(1)/,$(patsubst %.o,%.bc, $(2))) +endef + + +# Based on install_headers in https://github.com/postgres/postgres/blob/REL_17_BETA1/src/makefiles/pgxs.mk#L202-L207 +define package_headers +$(MKDIR_P) '$(pkg_incdir)/$(1)/' +$(INSTALL_DATA) $(2) '$(pkg_incdir)/$(1)/' +endef