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

fix: run with 'nix run' #20

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

guibou
Copy link

@guibou guibou commented Sep 6, 2024

The standard nix builds creates a binary which is reproducible with pinned shared libraries in /nix/store as well as a pinned library loader (also located in /nix/store).

However the preFixup phase is replacing the reproducible and pinned library loader by one which is hopefully located in /lib64/ld-linux-x86-64.so.2 (e.g. for x86-64 systems). I don't understand this fix because:

  • It breaks reproducibility and pinning because there is no guarantee that the file in /lib64/ld-linux-x86-64.so.2 exists (e.g. on nixos systems) or that it is compatible (e.g. on system with a more recent libc).
  • It does not bring any other benefit of making the binary self contained because it still depends on a few shared libraries:
	linux-vdso.so.1 (0x00007f95bad0d000)
	libX11.so.6 => /nix/store/44q9wnzpgv77rl0yjszs0bac5apk2c83-libX11-1.8.9/lib/libX11.so.6 (0x00007f95babc2000)
	libpthread.so.0 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libpthread.so.0 (0x00007f95babbd000)
	libresolv.so.2 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libresolv.so.2 (0x00007f95babac000)
	libc.so.6 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libc.so.6 (0x00007f95ba9bf000)
	libxcb.so.1 => /nix/store/inw0qwiz9mq2748g0whfa43q2qs2ic60-libxcb-1.17.0/lib/libxcb.so.1 (0x00007f95ba992000)
	/nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/ld-linux-x86-64.so.2 => /nix/store/wlffq5p6mxxgfap10sav3ij936jzqm59-glibc-2.39-52/lib64/ld-linux-x86-64.so.2 (0x00007f95bad0f000)
	libXau.so.6 => /nix/store/wgzlxm5hzkpfzaa1qjc4pzzc9fhkwf2c-libXau-1.0.11/lib/libXau.so.6 (0x00007f95ba98d000)
	libXdmcp.so.6 => /nix/store/sg6xmva8xipj3mw1ip22n4f6vqmzb47r-libXdmcp-1.1.5/lib/libXdmcp.so.6 (0x00007f95ba985000)

Note that I don't really understand the comment:

Un-Nix the build so it can dlopen() X11 outside of Nix environments.

Alternates solutions:

  • Either build the binary in fully static mode, so there is no shared libraries and library loader.
  • Provide two builds artifacts, one (the default) which does not do the patch and can hence be run directly using nix run and one other which does this patching.

Note that with this commit, users can directly run tsui using nix run 'github:neuralinkcorp/tsui' (once merged).

The standard nix builds creates a binary which is reproducible with
pinned shared libraries in `/nix/store` as well as a pinned library
loader (also located in `/nix/store`).

However the `preFixup` phase is replacing the reproducible and pinned
library loader by one which is hopefully located in
`/lib64/ld-linux-x86-64.so.2` (e.g. for `x86-64` systems). I don't
understand this fix because:

- It breaks reproducibility and pinning because there is no guarantee
  that the file in `/lib64/ld-linux-x86-64.so.2` exists (e.g. on nixos
  systems) or that it is compatible (e.g. on system with a more recent
  libc).
- It does not bring any other benefit of making the binary self
  contained because it still depends on a few shared libraries:

```
	linux-vdso.so.1 (0x00007f95bad0d000)
	libX11.so.6 => /nix/store/44q9wnzpgv77rl0yjszs0bac5apk2c83-libX11-1.8.9/lib/libX11.so.6 (0x00007f95babc2000)
	libpthread.so.0 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libpthread.so.0 (0x00007f95babbd000)
	libresolv.so.2 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libresolv.so.2 (0x00007f95babac000)
	libc.so.6 => /nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/libc.so.6 (0x00007f95ba9bf000)
	libxcb.so.1 => /nix/store/inw0qwiz9mq2748g0whfa43q2qs2ic60-libxcb-1.17.0/lib/libxcb.so.1 (0x00007f95ba992000)
	/nix/store/dbcw19dshdwnxdv5q2g6wldj6syyvq7l-glibc-2.39-52/lib/ld-linux-x86-64.so.2 => /nix/store/wlffq5p6mxxgfap10sav3ij936jzqm59-glibc-2.39-52/lib64/ld-linux-x86-64.so.2 (0x00007f95bad0f000)
	libXau.so.6 => /nix/store/wgzlxm5hzkpfzaa1qjc4pzzc9fhkwf2c-libXau-1.0.11/lib/libXau.so.6 (0x00007f95ba98d000)
	libXdmcp.so.6 => /nix/store/sg6xmva8xipj3mw1ip22n4f6vqmzb47r-libXdmcp-1.1.5/lib/libXdmcp.so.6 (0x00007f95ba985000)
```

Note that I don't really understand the comment:

> Un-Nix the build so it can dlopen() X11 outside of Nix environments.

Alternates solutions:

- Either build the binary in fully static mode, so there is no shared
  libraries and library loader.
- Provide two builds artifacts, one (the default) which does not do the
  patch and can hence be run directly using `nix run` and one other
  which does this patching.

Note that with this commit, users can directly run `tsui` using `nix run
'github:neuralinkcorp/tsui'` (once merged).
@guibou guibou mentioned this pull request Sep 6, 2024
@kognise
Copy link
Member

kognise commented Sep 6, 2024

Hey! Thanks for the PR and for starting a discussion on this. I definitely want tsui to be easy to run on NixOS, if only because the build system is already flake-based and so there isn't much other work required.

You're right that the flake.nix is currently a little wonky in the context of running it on Nix systems. This is because we're actually primarily using Nix as a build system for the distributable binaries. They need to be able to run on non-Nix systems, which is why we have to patch the interp to one that real systems will actually have. The downside of this is that now, despite having a Nix flake, it doesn't actually support NixOS without FHS :)

Why not build the binary statically? The main dependency we care about here is X, which is used for the clipboard copying support. It probably isn't a great idea to statically link X into the binary.

I think there are two useful things that can both be done here:

  1. What you suggested is definitely the right path for a NixOS-friendly build: "Provide two builds artifacts, one (the default) which does not do the patch and can hence be run directly using nix run and one other which does this patching."
  2. Potentially rewrite clipboard_linux.c to dynamically load X. This would probably make the binary more portable. I think we tried this earlier and had some issues with getting the binary to work on Wayland systems when built with Nix, but those issues can probably be fixed.

Neither of these are truthfully my top priority at the moment, but if you are interested in either I will eagerly review and merge the changes!

- `nix run .#` (or `nix run 'github:neuralinkcorp/tsui') still works
- `nix build .#tsui_no_nix_ld` builds a version with the dynamic loader
  hack (e.g. what was the default).
- (bonus): `nix bundle` builds a local `tsui` auto-extractable self
  contained archive which should (in theory, perfect world, ...) be able
  to be relocated in another system without nix.
@guibou
Copy link
Author

guibou commented Sep 8, 2024

Hi @kognise, thank you for your detailed answer! It is highly appreciated. (To be honest, I was expecting this MR and discussion to stale for years and was just publishing it in order to keep track and give visibility and a partial solution to the "I want to run that NOW on nixos" question).

Why not build the binary statically? The main dependency we care about here is X, which is used for the clipboard copying support. It probably isn't a great idea to statically link X into the binary.

Because of the licence or because you want the "self contained executable" to be able to use the "runtime" system X libraries versus the "buildtime" ones?

If that's about the licenses, my understanding is that with these MIT (-like) licences, you should be good.

If that's about the runtime vs buildtime, I think (but it should be confirmed) that X is perfectly able to work with some libraries discrepancy because it should only be an entrypoint for the X protocol (a bit like libc fopen is internally using the stable kernel API).

Anyway, I've added a commit to the MR which implements point 1: it provides two build artifacts:

  • #tsui (which is also the default): no hack, works on nixos
  • #tsui_no_nix_ld (naming is difficult, I'm open to suggestions) which restores the behavior you had previously

So could be the best of both world. I set the "no-hack" as default so it allows users to run tsui from anywhere without really bothering, the variant with the hack being more of a dev specific entrypoint. Feel free to suggest a switch here.

I've also added a nix bundle command. In theory it could create a self-extracting self-contained bundle which can be easy to relocate on any other computer. Try it with nix bundle, and the result is in ./tsui. I said in theory, because that's not a simple task, but I had success with this multiples times on some complex programs. (tl;dr; the archive contains a copy of /nix/store with all the dependencies, it self extracts itself on a temporary filesystem namespace and runs). Other flavor of bundle are accessible, more here: https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-bundle

The current point of this MR is that:

  • (positive) It does not add much complexity (from my PoV)
  • (positive) It allows direct run on nixos using nix run github:neuralinkcorp/tsui
  • (positive) it proposes another deployment strategy with nix bundle
  • (negative) It changes your workflow, if you want the "hacked" binary, you need to run nix build .#tsui_no_nix_ld.

Tell me what to do next, in the meantime, enjoy your sunday ;)

@ndom91
Copy link

ndom91 commented Sep 14, 2024

This fixed the installation for me btw. Before and after updating my flake input to guibou's fork (thanks btw!):

image

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

Successfully merging this pull request may close these issues.

3 participants