Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

postgresql: split -lib and -dev outputs cleanly #294504

Merged
merged 6 commits into from
Aug 24, 2024

Conversation

wolfgangwalther
Copy link
Contributor

@wolfgangwalther wolfgangwalther commented Mar 9, 2024

Description of changes

TLDR: This splits outputs for the postgresql package cleanly, using a minimum of patching and/or nuking of references. Instead, dead references to other store paths are removed at compile and link time. The minimal -lib output is then added as a top-level libpq package.

This builds on my previous work in #292993 and #293996 and contains commits from those two branches. Please ignore the first ~20 commits here and provide feedback for those in the two other PRs. This PR starts with treewide: prepare pg_config moving to dev. This commit (by @jtojnar) and the 4 commits after (by @SuperSandro2000) were cherry-picked from #179962. Compared to #179962, the approach taken in this PR is simpler and requires far less patching of postgresql source code. In fact, the overall size of patches is reduced compared to before and fewer references needed to be removed afterwards.

While the most work here involved splitting the -dev output, a clean -lib output comes with that naturally. Thus, this PR replaces #179962 and #273175. The cleaned up lib output was discussed in #61580 (comment) (@thoughtpolice). With this output available, it's easy to create a top-level attribute libpq pointing to the latest version's lib output automatically as suggested by @danbst in #61580 (comment), which should resolve #61580 (@nh2). A true separate libpq package as proposed in #234470 (@szlend) would then not be necessary. This PR will be followed-up by another PR to build postgresql v16+ based on meson instead of autotools as mentioned in #292993 (comment). With a bit of patching (of which I have a working PoC already), this will allow us to build postgresql (at least libpq, but possibly even more) in pkgsStatic - which is probably the biggest thing that didn't work so far and why a separate libpq package was asked for in the first place.

After the split, the outputs contain the following:

  • default out:
    • All binaries, except pg_config and ecpg which are in the dev output. The default output thus includes both server-side and client-side binaries.
    • All contrib/core extension related files: server-libraries, extension control files etc.
  • lib:
    • libpq
    • libecpg, including libecpg_compat and libpgtypes
    • theoretically the /share/locale folders, if there were any built, which is not the case right now
  • doc and man as before
  • dev:
    • all header files in /include (both server and client)
    • the pgxs infrastructure to build extensions
    • static support libraries libpgport*.a, libpgcommon*.a and libpgfeutils.a
    • pkg-config files
    • ecpg and pg_config binaries as mentioned above

pg_config outputs all paths correctly. Example:

BINDIR = /nix/store/cc6n22zq8xg30d04km0l5ablzn3c8sw6-postgresql-13.14/bin
DOCDIR = /nix/store/i3wz2pp3xdxr36ydawhp4zvgfg96v1xm-postgresql-13.14-doc/share/doc/postgresql
HTMLDIR = /nix/store/i3wz2pp3xdxr36ydawhp4zvgfg96v1xm-postgresql-13.14-doc/share/doc/postgresql
INCLUDEDIR = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/include
PKGINCLUDEDIR = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/include
INCLUDEDIR-SERVER = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/include/server
LIBDIR = /nix/store/1785qgnghmk01k9q4x5bysywb6alrsfs-postgresql-13.14-lib/lib
PKGLIBDIR = /nix/store/cc6n22zq8xg30d04km0l5ablzn3c8sw6-postgresql-13.14/lib
LOCALEDIR = /nix/store/1785qgnghmk01k9q4x5bysywb6alrsfs-postgresql-13.14-lib/share/locale
MANDIR = /nix/store/ad6qwl677y7x9bcrrxps4sfvchdjk03f-postgresql-13.14-man/share/man
SHAREDIR = /nix/store/cc6n22zq8xg30d04km0l5ablzn3c8sw6-postgresql-13.14/share/postgresql
SYSCONFDIR = /etc/postgresql
PGXS = /nix/store/0mn3a190bwza34dpgnaiwmhm2b9v30xp-postgresql-13.14-dev/lib/pgxs/src/makefiles/pgxs.mk

One thing that is still missing right now, is that the -dev/lib folder must be added to the pkg-config file, so that libpgcommon, libpgport etc. can be found. It's still unclear to me whether we need to add this to some other parts of the pg_config output, too, to make it possible for pg_config-based builds to actually find those static libraries. This should work, see comment below. I think this question was also raised by @szlend in #273175 (comment).

Maintainer ping, if not mentioned above already: @globin @marsam @ivan @Ma27

Things done

I built all 5 versions (12-16) with and without JIT support, with glibc (default) and via pkgsMusl. I also built .tests for the glibc variants (musl didn't work for me for unrelated reasons). I built all extensions with various versions (which resulted in #294457). This works very well, so far.

What I did not build, yet, is any downstream packages actually depending on postgresql and the new -dev output. This will be the next step, but I would like to put this PR out for feedback already.

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@Ma27 Ma27 marked this pull request as draft March 9, 2024 16:52
@Ma27
Copy link
Member

Ma27 commented Mar 9, 2024

Converting to a draft until the base PRs are merged.

@Ma27
Copy link
Member

Ma27 commented Mar 9, 2024

Compared to #179962, the approach taken in this PR is simpler and requires far less patching of postgresql source code. In fact, the overall size of patches is reduced compared to before and fewer references needed to be removed afterwards.

Yeah, from a first glance I prefer this PR over the alternatives.
But I think the refactorings are still a good idea, so I'll focus on them for now.

@wolfgangwalther wolfgangwalther mentioned this pull request Mar 10, 2024
13 tasks
@wolfgangwalther
Copy link
Contributor Author

With this output available, it's easy to create a top-level attribute libpq pointing to the latest version's lib output automatically

I don't think this libpq -> postgresql_latest.lib top-level attribute will actually work. IIUC, when passing postgresql as a buildInput, it is actually using lib.getDev behind the scenes, to use the dev output of the postgresql package. But this won't work with this kind of libpq package - because lib.getDev postgresql.lib does not return the -dev output, but still only the -lib output. Without any of the headers, pkg-config files and static libraries... linking against libpq will certainly fail.

Of course the fix is simple - just make libpq point to postgresql_latest directly and not the lib output, which will have everything we actually wanted to, now that the outputs are split cleanly.

@wolfgangwalther
Copy link
Contributor Author

One thing that is still missing right now, is that the -dev/lib folder must be added to the pkg-config file, so that libpgcommon, libpgport etc. can be found.

I wonder how this would work before this PR anyway. Currently, those libraries are in the default output, but neither pg_config nor the pkg-config files have any mention of the default output's /lib directory.

When I remove those libraries entirely, then postgresql.pkgs.pg_auto_failover fails to build, because of missing libpgport and libpgcommon. But, even after moving those libs to the -dev output, the build succeeds. The linker flags look like this, though:

...
-L /nix/store/fnqpsn19nlyh45inikngy896fzf92d4z-postgresql-15.6/lib
-L /nix/store/gp2rvnn2xmm6k9iws48f7kcjgjd1wzrw-postgresql-15.6-lib/lib
-L/nix/store/70y8lpggw1jxmkgcmxfpp769z1y2cnpb-libxml2-2.12.5/lib
-L/nix/store/5wzi64qpd6i1zn3bsg9vm0l2l2n85m25-lz4-1.9.4/lib
-L/nix/store/9l0rfic1ax0ywx63qb97wyhycpcmy1cx-zstd-1.5.5/lib
...

No mention of the -dev output anywhere, but it still works fine.

Without knowing exactly what the magic behind the scenes does here, I conclude that this will work just fine without pg_config / pkg-config returning another -dev/lib folder.

@szlend
Copy link
Member

szlend commented Mar 16, 2024

I don't think this libpq -> postgresql_latest.lib top-level attribute will actually work. IIUC, when passing postgresql as a buildInput, it is actually using lib.getDev behind the scenes, to use the dev output of the postgresql package. But this won't work with this kind of libpq package - because lib.getDev postgresql.lib does not return the -dev output, but still only the -lib output. Without any of the headers, pkg-config files and static libraries... linking against libpq will certainly fail.

Yep, I came to the same conclusion a while back.

Of course the fix is simple - just make libpq point to postgresql_latest directly and not the lib output, which will have everything we actually wanted to, now that the outputs are split cleanly.

I don't think this is a great solution either. I would find it pretty surprising if installing libpq included the entire postgresql server. In that case I'd rather just not have a libpq package ta all.

Alternatively I could see libpq be a variant of the posgresql package with a few overrides that make it skip building the server bits. But iirc the package maintainers were against this idea.

One thing that is still missing right now, is that the -dev/lib folder must be added to the pkg-config file, so that libpgcommon, libpgport etc. can be found.

I wonder how this would work before this PR anyway. Currently, those libraries are in the default output, but neither pg_config nor the pkg-config files have any mention of the default output's /lib directory.

This is one of the reason I still think a separate libpq package is the right move. This is just not solvable in any reasonable way with a single package with multiple outputs. pg_config can only refer to one lib, and there are two of them. It's as simple as that.

Copy link
Member

@Ma27 Ma27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel a bit bad, but I found one last thing we could do here (or in a follow-up).

Other than that, it's looking good now, thanks a lot!
Also didn't encounter any issues in the past weeks about my postgresql installation using this patchset on top of master, thanks a lot!

pkgs/servers/sql/postgresql/generic.nix Outdated Show resolved Hide resolved
@wolfgangwalther
Copy link
Contributor Author

I feel a bit bad, but I found one last thing we could do here (or in a follow-up).

No worries, all good!

Also didn't encounter any issues in the past weeks about my postgresql installation using this patchset on top of master

Great, thanks for doing that!

Dynamic modules are technically libraries, but are not used by other packages.
Instead they are loaded by PostgreSQL itself, e.g. as extensions. Those just
increased the size of the lib output without benefit.

This removes the NIX_PGLIBDIR hack introduced in NixOS#17838 and instead makes sure
that pg_config always returns the correct PGLIBDIR. The test for postgis
introduced in the same PR is still passing with the change.
This library is used by other packages, so should be in the lib output.

By removing unused sections, libecpg will not contain any references to other
outputs and thus does not increase the closure for the lib output anymore.
This will also help massively when splitting a dev output later.

As a side-effect, this also unbreaks pkgsMusl.postgresql_12_jit and
pkgsMusl.postgresql_13_jit. For, at least to me, unknown reasons, those build
fine now.
This splits a dev output to make the default output not depend on any
build dependencies anymore. This also avoids removing references from
pgxs' Makefile this way, which should, at least theoretically, be good
to build extensions via pgxs, making sure they use the same tooling.

ecpg is the "embedded SQL C preprocessor", which is certainly a dev
tool.

Most important, for closure size anyway, is to move pg_config to the dev
output, since it retains paths to all the other outputs.

The only thing with references to the dev output remaining is then the
postgres binary itself. It contains all the output paths, because it
shows those in the pg_config system view. There is no other way than
to nuke those references to avoid circular dependencies between outputs
- and blowing up closure size again.
The !isDarwin condition seems to have been put in place only because of the
use of patchelf, which in turn seemed to be necessary because of nuke-refs.

Replacing the big nuke with the more granular remove-references-to allows
enabling this for darwin, too.
This prevents silently ignoring errors from "find".
glibc is not available on darwin anyway and isGnu is just shorter.
Copy link
Member

@Ma27 Ma27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good now, thanks!

@Ma27 Ma27 merged commit 04b4c1e into NixOS:staging Aug 24, 2024
24 of 26 checks passed
@Ma27
Copy link
Member

Ma27 commented Aug 24, 2024

Again, thanks a lot for your hard work!

@wolfgangwalther wolfgangwalther deleted the postgresql-outputs branch August 24, 2024 10:18
wolfgangwalther added a commit to wolfgangwalther/nixpkgs that referenced this pull request Aug 24, 2024
This was supposed to happen in NixOS#294504, but the commit was accidentally
left out when splitting off some libpq-related changes. Originated in
NixOS#179962, by Sandro.

Co-authored-by: Sandro Jäckel <sandro.jaeckel@gmail.com>
Co-authored-by: Wolfgang Walther <walther@technowledgy.de>
@wolfgangwalther
Copy link
Contributor Author

Just realized I lost the commit to make other packages use the -dev output when manually looking for pg_config along the way, when splitting of the "make libpq a package" related changes. I'm working on a PR to fix that.

wolfgangwalther added a commit to wolfgangwalther/nixpkgs that referenced this pull request Aug 24, 2024
This was supposed to happen in NixOS#294504, but the commit was accidentally
left out when splitting off some libpq-related changes. Originated in

Co-authored-by: Sandro Jäckel <sandro.jaeckel@gmail.com>
Co-authored-by: Wolfgang Walther <walther@technowledgy.de>
wolfgangwalther added a commit to wolfgangwalther/nixpkgs that referenced this pull request Aug 24, 2024
This was supposed to happen in NixOS#294504, but the commit was accidentally
left out when splitting off some libpq-related changes. Originated in
NixOS#179962, by Sandro.

Co-authored-by: Sandro Jäckel <sandro.jaeckel@gmail.com>
Co-authored-by: Wolfgang Walther <walther@technowledgy.de>
wolfgangwalther added a commit to wolfgangwalther/nixpkgs that referenced this pull request Aug 24, 2024
This was supposed to happen in NixOS#294504, but the commit was accidentally
left out when splitting off some libpq-related changes. Originated in
NixOS#179962, by Sandro.

Co-authored-by: Sandro Jäckel <sandro.jaeckel@gmail.com>
Co-authored-by: Wolfgang Walther <walther@technowledgy.de>
@trofi
Copy link
Contributor

trofi commented Aug 25, 2024

Bisect says 435f51c postgresql: split dev output broke NixOS manual build in staging as:

$ nix build -f nixos config.system.build.manual.manualHTML -L

nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 128, in _parse_included_blocks
nixos-manual-html>     tokens = self._parse(f.read(), auto_id_prefix=prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 526, in _parse
nixos-manual-html>     tokens = super()._parse(src,auto_id_prefix=auto_id_prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 80, in _parse
nixos-manual-html>     check_structure(self._current_type[-1], tokens)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual_structure.py", line 84, in check_structure
nixos-manual-html>     raise RuntimeError(f"heading in line {token.map[0] + 1} does not have an id")
nixos-manual-html> RuntimeError: heading in line 366 does not have an id
nixos-manual-html> The above exception was the direct cause of the following exception:
nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 128, in _parse_included_blocks
nixos-manual-html>     tokens = self._parse(f.read(), auto_id_prefix=prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 526, in _parse
nixos-manual-html>     tokens = super()._parse(src,auto_id_prefix=auto_id_prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 100, in _parse
nixos-manual-html>     self._parse_included_blocks(token, args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 132, in _parse_included_blocks
nixos-manual-html>     raise RuntimeError(f"processing included file {path} from line {lnum}") from e
nixos-manual-html> RuntimeError: processing included file /nix/store/48631l3hj5l06lygdbjiccwsqq47zmwh-postgresql.md from line 83
nixos-manual-html> The above exception was the direct cause of the following exception:
nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 36, in convert
nixos-manual-html>     tokens = self._parse(infile.read_text())
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 526, in _parse
nixos-manual-html>     tokens = super()._parse(src,auto_id_prefix=auto_id_prefix)
nixos-manual-html>              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 100, in _parse
nixos-manual-html>     self._parse_included_blocks(token, args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 132, in _parse_included_blocks
nixos-manual-html>     raise RuntimeError(f"processing included file {path} from line {lnum}") from e
nixos-manual-html> RuntimeError: processing included file configuration/configuration.md from line 41
nixos-manual-html> The above exception was the direct cause of the following exception:
nixos-manual-html> Traceback (most recent call last):
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/__init__.py", line 49, in main
nixos-manual-html>     manual.run_cli(args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 704, in run_cli
nixos-manual-html>     _run_cli_html(args)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 696, in _run_cli_html
nixos-manual-html>     md.convert(args.infile, args.outfile)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 523, in convert
nixos-manual-html>     super().convert(infile, outfile)
nixos-manual-html>   File "/nix/store/4yyh0fh7h6yhwcgsppdffxfz9q2ismnx-nixos-render-docs-0.0/lib/python3.12/site-packages/nixos_render_docs/manual.py", line 41, in convert
nixos-manual-html>     raise RuntimeError(f"failed to render manual {infile}") from e
nixos-manual-html> RuntimeError: failed to render manual manual.md
nixos-manual-html> error:
nixos-manual-html>      failed to render manual manual.md
nixos-manual-html> caused by:
nixos-manual-html>      processing included file configuration/configuration.md from line 41
nixos-manual-html> caused by:
nixos-manual-html>      processing included file /nix/store/48631l3hj5l06lygdbjiccwsqq47zmwh-postgresql.md from line 83
nixos-manual-html> caused by:
nixos-manual-html>      heading in line 366 does not have an id

@trofi
Copy link
Contributor

trofi commented Aug 25, 2024

Looks like the header needs an anchor. This seems to be enough to workaround build failure:

--- a/nixos/modules/services/databases/postgresql.md
+++ b/nixos/modules/services/databases/postgresql.md
@@ -366 +366 @@ evaluates to `"foobar"`.
-## Notable differences to upstream
+## Notable differences to upstream {#foo}

@trofi
Copy link
Contributor

trofi commented Aug 25, 2024

Proposed the fix as:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants