1let
2
3 generic =
4 # dependencies
5 { stdenv, lib, fetchurl, makeWrapper, fetchpatch
6 , glibc, zlib, readline, openssl, icu, lz4, zstd, systemd, libossp_uuid
7 , pkg-config, libxml2, tzdata, libkrb5, substituteAll, darwin
8 , linux-pam
9
10 # This is important to obtain a version of `libpq` that does not depend on systemd.
11 , systemdSupport ? lib.meta.availableOn stdenv.hostPlatform systemd && !stdenv.hostPlatform.isStatic
12 , enableSystemd ? null
13 , gssSupport ? with stdenv.hostPlatform; !isWindows && !isStatic
14
15 # for postgresql.pkgs
16 , self, newScope, buildEnv
17
18 # source specification
19 , version, hash, muslPatches ? {}
20
21 # for tests
22 , testers, nixosTests
23
24 # JIT
25 , jitSupport
26 , nukeReferences, patchelf, llvmPackages
27
28 # PL/Python
29 , pythonSupport ? false
30 , python3
31
32 # detection of crypt fails when using llvm stdenv, so we add it manually
33 # for <13 (where it got removed: https://github.com/postgres/postgres/commit/c45643d618e35ec2fe91438df15abd4f3c0d85ca)
34 , libxcrypt
35 } @args:
36 let
37 atLeast = lib.versionAtLeast version;
38 olderThan = lib.versionOlder version;
39 lz4Enabled = atLeast "14";
40 zstdEnabled = atLeast "15";
41
42 systemdSupport' = if enableSystemd == null then systemdSupport else (lib.warn "postgresql: argument enableSystemd is deprecated, please use systemdSupport instead." enableSystemd);
43
44 pname = "postgresql";
45
46 stdenv' = if jitSupport then llvmPackages.stdenv else stdenv;
47 in stdenv'.mkDerivation (finalAttrs: {
48 inherit version;
49 pname = pname + lib.optionalString jitSupport "-jit";
50
51 src = fetchurl {
52 url = "mirror://postgresql/source/v${version}/${pname}-${version}.tar.bz2";
53 inherit hash;
54 };
55
56 hardeningEnable = lib.optionals (!stdenv'.cc.isClang) [ "pie" ];
57
58 outputs = [ "out" "lib" "doc" "man" ];
59 setOutputFlags = false; # $out retains configureFlags :-/
60
61 buildInputs = [
62 zlib
63 readline
64 openssl
65 libxml2
66 icu
67 ]
68 ++ lib.optionals (olderThan "13") [ libxcrypt ]
69 ++ lib.optionals jitSupport [ llvmPackages.llvm ]
70 ++ lib.optionals lz4Enabled [ lz4 ]
71 ++ lib.optionals zstdEnabled [ zstd ]
72 ++ lib.optionals systemdSupport' [ systemd ]
73 ++ lib.optionals pythonSupport [ python3 ]
74 ++ lib.optionals gssSupport [ libkrb5 ]
75 ++ lib.optionals stdenv'.isLinux [ linux-pam ]
76 ++ lib.optionals (!stdenv'.isDarwin) [ libossp_uuid ];
77
78 nativeBuildInputs = [
79 makeWrapper
80 pkg-config
81 ]
82 ++ lib.optionals jitSupport [ llvmPackages.llvm.dev nukeReferences patchelf ];
83
84 enableParallelBuilding = true;
85
86 separateDebugInfo = true;
87
88 buildFlags = [ "world" ];
89
90 # Makes cross-compiling work when xml2-config can't be executed on the host.
91 # Fixed upstream in https://github.com/postgres/postgres/commit/0bc8cebdb889368abdf224aeac8bc197fe4c9ae6
92 env.NIX_CFLAGS_COMPILE = lib.optionalString (olderThan "13") "-I${libxml2.dev}/include/libxml2";
93
94 configureFlags = [
95 "--with-openssl"
96 "--with-libxml"
97 "--with-icu"
98 "--sysconfdir=/etc"
99 "--libdir=$(lib)/lib"
100 "--with-system-tzdata=${tzdata}/share/zoneinfo"
101 "--enable-debug"
102 (lib.optionalString systemdSupport' "--with-systemd")
103 (if stdenv'.isDarwin then "--with-uuid=e2fs" else "--with-ossp-uuid")
104 ] ++ lib.optionals lz4Enabled [ "--with-lz4" ]
105 ++ lib.optionals zstdEnabled [ "--with-zstd" ]
106 ++ lib.optionals gssSupport [ "--with-gssapi" ]
107 ++ lib.optionals pythonSupport [ "--with-python" ]
108 ++ lib.optionals jitSupport [ "--with-llvm" ]
109 ++ lib.optionals stdenv'.isLinux [ "--with-pam" ];
110
111 patches = [
112 (if atLeast "16" then ./patches/relative-to-symlinks-16+.patch else ./patches/relative-to-symlinks.patch)
113 ./patches/less-is-more.patch
114 ./patches/paths-for-split-outputs.patch
115 ./patches/specify_pkglibdir_at_runtime.patch
116 ./patches/paths-with-postgresql-suffix.patch
117
118 (substituteAll {
119 src = ./patches/locale-binary-path.patch;
120 locale = "${if stdenv.isDarwin then darwin.adv_cmds else lib.getBin stdenv.cc.libc}/bin/locale";
121 })
122
123 ] ++ lib.optionals stdenv'.hostPlatform.isMusl (
124 # Using fetchurl instead of fetchpatch on purpose: https://github.com/NixOS/nixpkgs/issues/240141
125 map fetchurl (lib.attrValues muslPatches)
126 ) ++ lib.optionals stdenv'.isLinux [
127 (if atLeast "13" then ./patches/socketdir-in-run-13+.patch else ./patches/socketdir-in-run.patch)
128 ];
129
130 installTargets = [ "install-world" ];
131
132 postPatch = ''
133 # Hardcode the path to pgxs so pg_config returns the path in $out
134 substituteInPlace "src/common/config_info.c" --subst-var out
135 '' + lib.optionalString jitSupport ''
136 # Force lookup of jit stuff in $out instead of $lib
137 substituteInPlace src/backend/jit/jit.c --replace pkglib_path \"$out/lib\"
138 substituteInPlace src/backend/jit/llvm/llvmjit.c --replace pkglib_path \"$out/lib\"
139 substituteInPlace src/backend/jit/llvm/llvmjit_inline.cpp --replace pkglib_path \"$out/lib\"
140 '';
141
142 postInstall =
143 ''
144 moveToOutput "lib/pgxs" "$out" # looks strange, but not deleting it
145 moveToOutput "lib/libpgcommon*.a" "$out"
146 moveToOutput "lib/libpgport*.a" "$out"
147 moveToOutput "lib/libecpg*" "$out"
148
149 # Prevent a retained dependency on gcc-wrapper.
150 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/ld ld
151
152 if [ -z "''${dontDisableStatic:-}" ]; then
153 # Remove static libraries in case dynamic are available.
154 for i in $out/lib/*.a $lib/lib/*.a; do
155 name="$(basename "$i")"
156 ext="${stdenv'.hostPlatform.extensions.sharedLibrary}"
157 if [ -e "$lib/lib/''${name%.a}$ext" ] || [ -e "''${i%.a}$ext" ]; then
158 rm "$i"
159 fi
160 done
161 fi
162 '' + lib.optionalString jitSupport ''
163 # Move the bitcode and libllvmjit.so library out of $lib; otherwise, every client that
164 # depends on libpq.so will also have libLLVM.so in its closure too, bloating it
165 moveToOutput "lib/bitcode" "$out"
166 moveToOutput "lib/llvmjit*" "$out"
167
168 # In the case of JIT support, prevent a retained dependency on clang-wrapper
169 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/clang clang
170 nuke-refs $out/lib/llvmjit_types.bc $(find $out/lib/bitcode -type f)
171
172 # Stop out depending on the default output of llvm
173 substituteInPlace $out/lib/pgxs/src/Makefile.global \
174 --replace ${llvmPackages.llvm.out}/bin "" \
175 --replace '$(LLVM_BINPATH)/' ""
176
177 # Stop out depending on the -dev output of llvm
178 substituteInPlace $out/lib/pgxs/src/Makefile.global \
179 --replace ${llvmPackages.llvm.dev}/bin/llvm-config llvm-config \
180 --replace -I${llvmPackages.llvm.dev}/include ""
181
182 ${lib.optionalString (!stdenv'.isDarwin) ''
183 # Stop lib depending on the -dev output of llvm
184 rpath=$(patchelf --print-rpath $out/lib/llvmjit.so)
185 nuke-refs -e $out $out/lib/llvmjit.so
186 # Restore the correct rpath
187 patchelf $out/lib/llvmjit.so --set-rpath "$rpath"
188 ''}
189 '';
190
191 postFixup = lib.optionalString (!stdenv'.isDarwin && stdenv'.hostPlatform.libc == "glibc")
192 ''
193 # initdb needs access to "locale" command from glibc.
194 wrapProgram $out/bin/initdb --prefix PATH ":" ${glibc.bin}/bin
195 '';
196
197 doCheck = !stdenv'.isDarwin;
198 # autodetection doesn't seem to able to find this, but it's there.
199 checkTarget = "check";
200
201 disallowedReferences = [ stdenv'.cc ];
202
203 passthru = let
204 this = self.callPackage generic args;
205 jitToggle = this.override {
206 jitSupport = !jitSupport;
207 };
208 in
209 {
210 psqlSchema = lib.versions.major version;
211
212 withJIT = if jitSupport then this else jitToggle;
213 withoutJIT = if jitSupport then jitToggle else this;
214
215 dlSuffix = if olderThan "16" then ".so" else stdenv.hostPlatform.extensions.sharedLibrary;
216
217 pkgs = let
218 scope = {
219 inherit jitSupport;
220 inherit (llvmPackages) llvm;
221 postgresql = this;
222 stdenv = stdenv';
223 };
224 newSelf = self // scope;
225 newSuper = { callPackage = newScope (scope // this.pkgs); };
226 in import ./ext newSelf newSuper;
227
228 withPackages = postgresqlWithPackages {
229 inherit makeWrapper buildEnv;
230 postgresql = this;
231 }
232 this.pkgs;
233
234 tests = {
235 postgresql-wal-receiver = import ../../../../nixos/tests/postgresql-wal-receiver.nix {
236 inherit (stdenv) system;
237 pkgs = self;
238 package = this;
239 };
240 pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
241 } // lib.optionalAttrs jitSupport {
242 postgresql-jit = import ../../../../nixos/tests/postgresql-jit.nix {
243 inherit (stdenv) system;
244 pkgs = self;
245 package = this;
246 };
247 };
248 };
249
250 meta = with lib; {
251 homepage = "https://www.postgresql.org";
252 description = "A powerful, open source object-relational database system";
253 license = licenses.postgresql;
254 changelog = "https://www.postgresql.org/docs/release/${finalAttrs.version}/";
255 maintainers = with maintainers; [ thoughtpolice danbst globin ivan ma27 ];
256 pkgConfigModules = [ "libecpg" "libecpg_compat" "libpgtypes" "libpq" ];
257 platforms = platforms.unix;
258
259 # JIT support doesn't work with cross-compilation. It is attempted to build LLVM-bytecode
260 # (`%.bc` is the corresponding `make(1)`-rule) for each sub-directory in `backend/` for
261 # the JIT apparently, but with a $(CLANG) that can produce binaries for the build, not the
262 # host-platform.
263 #
264 # I managed to get a cross-build with JIT support working with
265 # `depsBuildBuild = [ llvmPackages.clang ] ++ buildInputs`, but considering that the
266 # resulting LLVM IR isn't platform-independent this doesn't give you much.
267 # In fact, I tried to test the result in a VM-test, but as soon as JIT was used to optimize
268 # a query, postgres would coredump with `Illegal instruction`.
269 broken = (jitSupport && stdenv.hostPlatform != stdenv.buildPlatform)
270 # Allmost all tests fail FATAL errors for v12 and v13
271 || (jitSupport && stdenv.hostPlatform.isMusl && olderThan "14");
272 };
273 });
274
275 postgresqlWithPackages = { postgresql, makeWrapper, buildEnv }: pkgs: f: buildEnv {
276 name = "postgresql-and-plugins-${postgresql.version}";
277 paths = f pkgs ++ [
278 postgresql
279 postgresql.lib
280 postgresql.man # in case user installs this into environment
281 ];
282 nativeBuildInputs = [ makeWrapper ];
283
284
285 # We include /bin to ensure the $out/bin directory is created, which is
286 # needed because we'll be removing the files from that directory in postBuild
287 # below. See #22653
288 pathsToLink = ["/" "/bin"];
289
290 # Note: the duplication of executables is about 4MB size.
291 # So a nicer solution was patching postgresql to allow setting the
292 # libdir explicitly.
293 postBuild = ''
294 mkdir -p $out/bin
295 rm $out/bin/{pg_config,postgres,pg_ctl}
296 cp --target-directory=$out/bin ${postgresql}/bin/{postgres,pg_config,pg_ctl}
297 wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
298 '';
299
300 passthru.version = postgresql.version;
301 passthru.psqlSchema = postgresql.psqlSchema;
302 };
303
304in
305# passed by <major>.nix
306versionArgs:
307# passed by default.nix
308{ self, ... } @defaultArgs:
309self.callPackage generic (defaultArgs // versionArgs)