diff --git a/CHANGELOG.md b/CHANGELOG.md index b54256e552..8263822853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - #3149, Misleading "Starting PostgREST.." logs on schema cache reloading - @steve-chavez + - #2815, Build static executable with GSSAPI support - @wolfgangwalther ### Deprecated diff --git a/default.nix b/default.nix index 918a96f52d..6cf227b66a 100644 --- a/default.nix +++ b/default.nix @@ -36,7 +36,7 @@ let allOverlays.build-toolbox allOverlays.checked-shell-script allOverlays.gitignore - (allOverlays.postgresql-default { inherit patches; }) + allOverlays.postgresql-libpq allOverlays.postgresql-legacy allOverlays.postgresql-future allOverlays.postgis @@ -60,23 +60,11 @@ let { name = "postgresql-9.6"; postgresql = pkgs.postgresql_9_6.withPackages (p: [ p.postgis p.pg_safeupdate ]); } ]; - patches = - pkgs.callPackage nix/patches { }; - # Dynamic derivation for PostgREST postgrest = pkgs.haskell.packages."${compiler}".callCabal2nix name src { }; - # Functionality that derives a fully static Haskell package based on - # nh2/static-haskell-nix - staticHaskellPackage = - import nix/static-haskell-package.nix { inherit nixpkgs system compiler patches allOverlays; }; - - # Static executable. - postgrestStatic = - lib.justStaticExecutables (lib.dontCheck (staticHaskellPackage name src).package); - - packagesStatic = (staticHaskellPackage name src).survey; + staticHaskellPackage = import nix/static.nix { inherit compiler name pkgs src; }; # Options passed to cabal in dev tools and tests devCabalOptions = @@ -160,8 +148,8 @@ rec { }; } // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux rec { # Static executable. - inherit postgrestStatic; - inherit packagesStatic; + inherit (staticHaskellPackage) postgrestStatic; + inherit (staticHaskellPackage) packagesStatic; # Docker images and loading script. docker = diff --git a/nix/UPGRADE.md b/nix/UPGRADE.md index 5fd6d68a23..5c747e4480 100644 --- a/nix/UPGRADE.md +++ b/nix/UPGRADE.md @@ -33,15 +33,6 @@ postgrest-nixpkgs-upgrade ``` -## Update pinned version of `static-haskell-nix` - -We pin [`static-haskell-nix`](https://github.com/nh2/static-haskell-nix) in -[`nix/static-haskell-package.nix`](static-haskell-package.nix). Upgrade the -pinned revision and the tarball hash if necessary. See -[`nix/nixpkgs-upgrade.nix`](nixpkgs-upgrade.nix) for how to get the correct -tarball hash, or just change the hash to an arbitrary value of correct length, -run `nix-build` and use the expected value from the resulting error message. - ## Review overlays Check whether the individual [overlays](overlays) are still required. diff --git a/nix/libpq.nix b/nix/libpq.nix new file mode 100644 index 0000000000..c45956cbcc --- /dev/null +++ b/nix/libpq.nix @@ -0,0 +1,65 @@ +# Creating a separate libpq package is is discussed in +# https://github.com/NixOS/nixpkgs/issues/61580, but nixpkgs has not moved +# forward, yet. +# This package is passed to postgresql-libpq (haskell) which needs to be +# cross-compiled to the static build and possibly other architectures as +# as well. To reduce the number of dependencies that need to be built with +# it, this derivation focuses on building the client libraries only. No +# server, no tests. +{ stdenv +, lib +, openssl +, zlib +, libkrb5 +, icu +, postgresql +, pkg-config +, tzdata +}: + +stdenv.mkDerivation { + pname = "libpq"; + inherit (postgresql) src version; + + configureFlags = [ + "--without-gssapi" + "--without-icu" + "--without-readline" + "--with-gssapi" + "--with-openssl" + "--with-system-tzdata=${tzdata}/share/zoneinfo" + ]; + + nativeBuildInputs = [ pkg-config tzdata ]; + buildInputs = [ libkrb5 openssl zlib ]; + + buildFlags = [ "submake-libpq" "submake-libpgport" ]; + + installPhase = '' + runHook preInstall + + make -C src/bin/pg_config install + make -C src/common install + make -C src/include install + make -C src/interfaces/libpq install + make -C src/port install + + rm -rfv $out/share + + runHook postInstall + ''; + + # To avoid linking errors in the static build with gssapi + postInstall = '' + substituteInPlace $out/lib/pkgconfig/libpq.pc\ + --replace "Requires.private:" "Requires.private: krb5-gssapi," + ''; + + outputs = [ "out" ]; + + meta = with lib; { + homepage = "https://www.postgresql.org"; + description = "Client API library for PostgreSQL"; + license = licenses.postgresql; + }; +} diff --git a/nix/overlays/default.nix b/nix/overlays/default.nix index 8b0b3af4ff..434ccc72d8 100644 --- a/nix/overlays/default.nix +++ b/nix/overlays/default.nix @@ -4,7 +4,7 @@ gitignore = import ./gitignore.nix; haskell-packages = import ./haskell-packages.nix; postgis = import ./postgis.nix; - postgresql-default = import ./postgresql-default.nix; + postgresql-libpq = import ./postgresql-libpq.nix; postgresql-legacy = import ./postgresql-legacy.nix; postgresql-future = import ./postgresql-future.nix; slocat = import ./slocat.nix; diff --git a/nix/overlays/haskell-packages.nix b/nix/overlays/haskell-packages.nix index c94db37edf..b8515170f9 100644 --- a/nix/overlays/haskell-packages.nix +++ b/nix/overlays/haskell-packages.nix @@ -1,4 +1,4 @@ -{ compiler, extraOverrides ? (final: prev: { }) }: +{ compiler }: self: super: let @@ -41,11 +41,14 @@ let # Marked as broken (?) fuzzyset = lib.markUnbroken prev.fuzzyset; - postgresql-libpq = lib.dontCheck prev.postgresql-libpq_0_10_0_0; + postgresql-libpq = lib.dontCheck + (prev.postgresql-libpq_0_10_0_0.override { + postgresql = super.libpq; + }); hasql-pool = lib.dontCheck prev.hasql-pool_0_10; - } // extraOverrides final prev; + }; in { haskell = diff --git a/nix/overlays/postgresql-default.nix b/nix/overlays/postgresql-default.nix deleted file mode 100644 index 1e38b8fea1..0000000000 --- a/nix/overlays/postgresql-default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ patches }: self: super: -# Overlay that sets the default version of PostgreSQL. -with patches; -{ - postgresql = super.postgresql_15.overrideAttrs ({ patches ? [ ], ... }: { - patches = patches ++ [ postgresql-atexit ]; - }); -} diff --git a/nix/overlays/postgresql-libpq.nix b/nix/overlays/postgresql-libpq.nix new file mode 100644 index 0000000000..5f342bd866 --- /dev/null +++ b/nix/overlays/postgresql-libpq.nix @@ -0,0 +1,6 @@ +self: super: +{ + libpq = super.callPackage ../libpq.nix { + postgresql = super.postgresql_16; + }; +} diff --git a/nix/patches/default.nix b/nix/patches/default.nix deleted file mode 100644 index e3c5a97452..0000000000 --- a/nix/patches/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ runCommand }: - -{ - applyPatches = - name: src: patches: - runCommand - name - { inherit src patches; } - '' - set -eou pipefail - - cp -r $src $out - chmod -R u+w $out - - for patch in $patches; do - echo "Applying patch $patch" - patch -d "$out" -p1 < "$patch" - done - ''; - - static-haskell-nix-ncurses = - ./static-haskell-nix-ncurses.patch; - static-haskell-nix-ghc-bignum = - ./static-haskell-nix-ghc-bignum.patch; - static-haskell-nix-openssl = - ./static-haskell-nix-openssl.patch; - postgresql-atexit = - ./postgresql-atexit.patch; -} diff --git a/nix/patches/postgresql-atexit.patch b/nix/patches/postgresql-atexit.patch deleted file mode 100644 index 3c11119149..0000000000 --- a/nix/patches/postgresql-atexit.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/src/interfaces/libpq/Makefile -+++ b/src/interfaces/libpq/Makefile -@@ -118,7 +118,7 @@ backend_src = $(top_srcdir)/src/backend - libpq-refs-stamp: $(shlib) - ifneq ($(enable_coverage), yes) - ifeq (,$(filter aix solaris,$(PORTNAME))) -- @if nm -A -u $< 2>/dev/null | grep -v __cxa_atexit | grep exit; then \ -+ @if nm -A -u $< 2>/dev/null | grep " exit"; then \ - echo 'libpq must not be calling any function which invokes exit'; exit 1; \ - fi - endif diff --git a/nix/patches/static-haskell-nix-ghc-bignum.patch b/nix/patches/static-haskell-nix-ghc-bignum.patch deleted file mode 100644 index 568880d926..0000000000 --- a/nix/patches/static-haskell-nix-ghc-bignum.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/survey/default.nix b/survey/default.nix -index 70afbbc..28cb0e9 100644 ---- a/survey/default.nix -+++ b/survey/default.nix -@@ -81,6 +81,7 @@ let - # `.override` and the likes). - isProperHaskellPackage = val: - lib.isDerivation val && # must pass lib.isDerivation -+ val.pname != "ghc-bignum" && - val ? env; # must have an .env key - - # Function that tells us if a given Haskell package has an executable. diff --git a/nix/patches/static-haskell-nix-ncurses.patch b/nix/patches/static-haskell-nix-ncurses.patch deleted file mode 100644 index 195f842207..0000000000 --- a/nix/patches/static-haskell-nix-ncurses.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/survey/default.nix b/survey/default.nix -index 46d8066..a47f214 100644 ---- a/survey/default.nix -+++ b/survey/default.nix -@@ -1519,7 +1519,7 @@ let - [ - "--enable-executable-static" # requires `useFixedCabal` - # `enableShared` seems to be required to avoid `recompile with -fPIC` errors on some packages. -- "--extra-lib-dirs=${final.ncurses.override { enableStatic = true; enableShared = true; }}/lib" -+ "--extra-lib-dirs=${final.ncurses.override { enableStatic = true; }}/lib" - ] - # TODO Figure out why this and the below libffi are necessary. - # `working` and `workingStackageExecutables` don't seem to need that, diff --git a/nix/patches/static-haskell-nix-openssl.patch b/nix/patches/static-haskell-nix-openssl.patch deleted file mode 100644 index e580549f17..0000000000 --- a/nix/patches/static-haskell-nix-openssl.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/survey/default.nix b/survey/default.nix -index cf1bd31..9d34753 100644 ---- a/survey/default.nix -+++ b/survey/default.nix -@@ -736,6 +736,7 @@ let - openblas = previous.openblas.override { enableStatic = true; }; - - openssl = previous.openssl.override { static = true; }; -+ openssl_1_1 = previous.openssl_1_1.override { static = true; }; - - libsass = previous.libsass.overrideAttrs (old: { dontDisableStatic = true; }); - diff --git a/nix/static-haskell-package.nix b/nix/static-haskell-package.nix deleted file mode 100644 index 01ba11ee61..0000000000 --- a/nix/static-haskell-package.nix +++ /dev/null @@ -1,65 +0,0 @@ -# Derive a fully static Haskell package based on musl instead of glibc. -{ nixpkgs, system, compiler, patches, allOverlays }: - -name: src: -let - # The nh2/static-haskell-nix project does all the hard work for us. - static-haskell-nix = - let - rev = "bd66b86b72cff4479e1c76d5916a853c38d09837"; - in - builtins.fetchTarball { - url = "https://github.com/nh2/static-haskell-nix/archive/${rev}.tar.gz"; - sha256 = "0rnsxaw7v27znsg9lgqk1i4007ydqrc8gfgimrmhf24lv6galbjh"; - }; - - patched-static-haskell-nix = - patches.applyPatches "patched-static-haskell-nix" - static-haskell-nix - [ - patches.static-haskell-nix-ncurses - patches.static-haskell-nix-ghc-bignum - patches.static-haskell-nix-openssl - ]; - - extraOverrides = - final: prev: - rec { - # We need to add our package needs to the package set that we pass to - # static-haskell-nix. Using callCabal2nix on the haskellPackages that - # it returns would result in a dynamic build based on musl, and not the - # fully static build that we want. - "${name}" = prev.callCabal2nix name src { }; - }; - - overlays = - [ - allOverlays.postgresql-future - (allOverlays.postgresql-default { inherit patches; }) - (allOverlays.haskell-packages { inherit compiler extraOverrides; }) - # Disable failing tests for postgresql on musl that should have no impact - # on the libpq that we need (collate.icu.utf8 and foreign regression - # tests) - (self: super: - { postgresql = super.postgresql.overrideAttrs (_: { doCheck = false; }); } - ) - ]; - - # Apply our overlay to nixpkgs. - normalPkgs = - import nixpkgs { inherit overlays system; }; - - defaultCabalPackageVersionComingWithGhc = - { - ghc948 = "Cabal_3_8_1_0"; - }."${compiler}"; - - # The static-haskell-nix 'survey' derives a full static set of Haskell - # packages, applying fixes where necessary. - survey = - import "${patched-static-haskell-nix}/survey" { inherit normalPkgs compiler defaultCabalPackageVersionComingWithGhc; }; -in -{ - inherit survey; - package = survey.haskellPackages."${name}"; -} diff --git a/nix/static.nix b/nix/static.nix new file mode 100644 index 0000000000..0d14583d10 --- /dev/null +++ b/nix/static.nix @@ -0,0 +1,58 @@ +{ compiler +, name +, pkgs +, src +}: +let + # This builds a static PostgREST exectuable based on pkgsStatic. + # pkgsStatic is based on musl, so is a kind of cross-compilation. + # We still make this explicit here via pkgsCross, because we need + # to get postgresql/libpq for musl, too. + pkgsCross = pkgs.pkgsCross.musl64; + inherit (pkgsCross) pkgsStatic; + inherit (pkgsStatic.haskell) lib; + + packagesStatic = + pkgsStatic.haskell.packages."${compiler}".override (old: { + ghc = pkgsStatic.pkgsBuildHost.haskell.compiler."${compiler}".override { + # Using the bundled libffi generally works better for cross-compiling + libffi = null; + # Building sphinx fails on some platforms + enableDocs = false; + # Cross compiling with native bignum works better than with gmp + enableNativeBignum = true; + }; + + overrides = pkgs.lib.composeExtensions old.overrides (final: prev: { + postgresql-libpq = (prev.postgresql-libpq.override { + # postgresql doesn't build in the fully static overlay - but the default + # derivation is built with static libraries anyway. + postgresql = pkgsCross.libpq; + }).overrideAttrs (finalAttrs: prevAttrs: { + # Using use-pkg-config flag, because pg_config won't work when cross-compiling + configureFlags = prevAttrs.configureFlags ++ [ "-fuse-pkg-config" ]; + # Using pkg-config without pkgsCross, because "pkg-config" is hardcoded in + # postgresql-libpq's Setup.hs. Using pkgsStatic to make pkg-config return the + # static libs for libpq. + nativeBuildInputs = prevAttrs.nativeBuildInputs ++ [ pkgs.pkgsStatic.pkg-config ]; + + buildInputs = prevAttrs.buildInputs ++ [ + (pkgsStatic.libkrb5.overrideAttrs (finalAttrs: prevAttrs: { + # disable keyutils dependency, to avoid linking errors + configureFlags = prevAttrs.configureFlags ++ [ "--without-keyutils" ]; + })) + ]; + }); + }); + }); + + makeExecutableStatic = drv: + lib.justStaticExecutables + (lib.appendConfigureFlag drv "--enable-executable-static"); + +in +{ + inherit packagesStatic; + + postgrestStatic = makeExecutableStatic (packagesStatic.callCabal2nix name src { }); +}