From 4eb5c0b6615d4b0923c478c36265fc08f8dd3863 Mon Sep 17 00:00:00 2001 From: "David E. Wheeler" Date: Tue, 18 Jun 2024 10:23:26 -0400 Subject: [PATCH] POC Trunk/OCI binary distribution --- .gitignore | 3 +- Makefile | 5 +- docker-compose.yml | 57 +++++++++ install_trunk | 152 +++++++++++++++++++++++ push_trunk | 114 ++++++++++++++++++ trunk.mk | 293 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 622 insertions(+), 2 deletions(-) create mode 100644 docker-compose.yml create mode 100755 install_trunk create mode 100755 push_trunk create mode 100644 trunk.mk diff --git a/.gitignore b/.gitignore index 3ad5050..44cc862 100644 --- a/.gitignore +++ b/.gitignore @@ -4,12 +4,13 @@ results/ *.dll tmp/ *.o +*.bc regression.diffs regression.out /sql/semver--?.??.?.sql /semver-* +/semver_annotations.json /latest-changes.md -/src/*.bc /semver_binary_copy.bin /.vscode /*.bin diff --git a/Makefile b/Makefile index 8777ed1..28187f7 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) 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..b1b6d61 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,57 @@ +version: "3.9" +name: trunking + +# Start a Zot service for pushing and pulling OCI images, and a +# pgxn/pgxn-tools image for building and testing Linux/AMD binaries. +# +# docker compose up -d +# docker compose exec linux bash +# make clean && make && make trunk +# +# On macOS: +# make clean && make && make trunk +# ./push_trunk localhost:5000/theory/semver semver-0.32.1+pg16-darwin-23.5.0-arm64 semver-0.32.1+pg16-linux-amd64 +# clean -dfx --exclude=.vscode +# find "$(pg_config --sharedir)" "$(pg_config --pkglibdir)" "$(pg_config --docdir)" -name '*semver*' -exec rm -rf "{}" \; +# +# ./install_trunk localhost:5000/theory/semver:v1 +# find "$(pg_config --sharedir)" "$(pg_config --pkglibdir)" "$(pg_config --docdir)" -name '*semver*' +# +# Back on Linux +# ./install_trunk zot:5000/theory/semver:v1 +# find "$(pg_config --sharedir)" "$(pg_config --pkglibdir)" "$(pg_config --docdir)" -name '*semver*' + +# 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 + hostname: linux + working_dir: /work + volumes: + - ".:/work" + # Install oras, then start Postgres 16 and install rsync and jq + 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..78521f4 --- /dev/null +++ b/install_trunk @@ -0,0 +1,152 @@ +#!/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 + + # Download. + local file + file=$(basename "$(oras pull --no-tty --plain-http --format 'go-template={{(first .files).path}}' --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 pgsql directory. + if [ ! -d 'pgsql' ]; then + printf "Package contains no install files; exiting\n" + exit 1 + fi + + cd 'pgsql' || 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..b36d574 --- /dev/null +++ b/push_trunk @@ -0,0 +1,114 @@ +#!/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. + +trap 'exit' ERR +set -E + +# 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_image() { + # Push the image into the OCI layout directory $OCI_DIR. + local trunk=$1 + oras push --no-tty \ + --oci-layout "$OCI_DIR" \ + --artifact-type "${ARTIFACT_TYPE}" \ + --config "${trunk}_config.json":"$CONFIG_TYPE" \ + --format go-template='{{.digest}}' \ + --annotation-file "${trunk}_annotations.json" \ + "$trunk.trunk":"$MEDIA_TYPE" +} + +make_manifest() { + local trunk=$1 + local digest=$2 + local anno platform + + # Extract just the pgxn.trunk annotations. + anno=$(jq -c \ + '.["$manifest"] | with_entries(select(.key | startswith("org.pgxn.trunk.")))' \ + "${trunk}_annotations.json" + ) + + # Extract the platform config. + platform=$(jq \ + 'pick(.os, .["os.version"], .architecture)| with_entries(select(.value |. !=null and . != ""))' \ + "$trunk"_config.json + ) + + # Create and return the image manifest. + oras manifest fetch --oci-layout "$OCI_DIR@${digest}" --descriptor \ + | jq --argjson anno "$anno" --argjson platform "$platform" \ + '{ + mediaType: .mediaType, + size: .size, + digest: .digest, + platform: $platform, + annotations: $anno + }' +} + +write_index() { + darwin_manifest=$1 + linux_manifest=$2 + + # Build the image index with the two manifests. + jq -n --argjson linux "$linux_manifest" \ + --argjson darwin "$darwin_manifest" \ + --argjson annotations "$(cat semver_annotations.json)" \ + '{ + schemaVersion: 2, + mediaType: "application/vnd.oci.image.index.v1+json", + manifests: [$linux, $darwin], + annotations: $annotations + }' > "$INDEX_FILE" +} + +push_trunk() { + # Only testing for Darwin and Linux rn. + local repo=$1 + local darwin_trunk=$2 + local linux_trunk=$3 + + if [ -z "$repo" ] || [ -z "$darwin_trunk" ] || [ -z "$linux_trunk" ]; then + printf "Usage:\n\n %s REPO DARWIN.trunk LINUX.trunk\n" "$0" + exit 1 + fi + + # Push the images and grab the resulting digests. + darwin_digest=$(push_image "$darwin_trunk") + linux_digest=$(push_image "$linux_trunk") + + # Create the image manifests. + darwin_manifest=$(make_manifest "$darwin_trunk" "$darwin_digest") + linux_manifest=$(make_manifest "$linux_trunk" "$linux_digest") + + # Write out and push the image index. + write_index "$darwin_manifest" "$linux_manifest" + oras manifest push --oci-layout ./"$OCI_DIR":image-index "$INDEX_FILE" + + # Push everything from the local layout to the remote 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 + + # Cleanup. + rm -rf "$OCI_DIR" "$INDEX_FILE" +} + +push_trunk "$@" diff --git a/trunk.mk b/trunk.mk new file mode 100644 index 0000000..b2ec09c --- /dev/null +++ b/trunk.mk @@ -0,0 +1,293 @@ +# 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 +# TITLE = Bike +# DESCRIPTION = A bicycle inside your database. +# LICENSE = mit +# LANGUAGE = c +# VENDOR = PGXN +# URL = https://pgxn.org/dist/bike +# REPO_URL = https://github.com/pgxn/bike +# +# 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 +# ``` +# +# This will create a file with a name similar to +# +# bike-1.2.1+pg16-darwin-23.5.0-arm64 +# +# 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_os_ver)-$(pkg_arch) +else +pkg := $(EXTENSION)-$(DISTVERSION)+pg$(MAJORVERSION)-$(PORTNAME)-$(pkg_arch) +endif +pkg_dir := $(pkg) +pkg_installdir := $(pkg_dir)/pgsql +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