Description
Specification
Being inspired by Golang and other products like airplane.dev... etc. I can see that statically linked CLI executables is far easier to distribute. For example in https://github.com/airplanedev/cli/releases/tag/v0.3.201 you can just download the executable, and immediately run it on NixOS without problems:
»» ~/Projects/airplane
♖ file airplane
airplane: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=Y7wWH3mifiqz5aem5Cxt/7sovkpNEjt7IJRP97P-1/CWBYjxSmrDYD9oEeD2kS/4L0HFVWRnfaSbHYuxre4, stripped
»» ~/Projects/airplane
♖ ldd ./airplane
not a dynamic executable
»» ~/Projects/airplane
♜ ./airplane
Airplane CLI
One thing that would make it easier, is that we would be able to run polykey
on NixOS and other Linux distributions far more easily.
Right now when we produce the Linux release of the CLI executable, we have to use steam-run
on NixOS to run it because it uses the precompiled nodejs from https://github.com/yao-pkg/pkg-fetch and https://github.com/yao-pkg/pkg, which is a dynamically linked nodejs that refers to the standard Linux FHS location for the link loader, which is not the same location as it is on NixOS.
We also saw recently that due to the latest release of rocksdb, it didn't work on an older version of Ubuntu because it didn't have the latest C++ libraries.
We can sidestep all of this by statically building a binary. In fact pkg does support this. However it mentions this:
Note that fully static Node binaries are not capable of loading native bindings, so you may not use Node bindings with linuxstatic.
And our libraries that are native like js-db
, js-quic
... etc are all loaded using the dynamic link loader which relies on require
or process.dlopen
.
So we need to figure out how to produce statically linkable object files from js-db
for example, and have that be consumed by Polykey-CLI to statically compile with the nodejs static. I'm not even sure if this is in fact possible, without also bringing in the compilation process of nodejs itself in PK-CLI somehow (right now we don't compile nodejs, it's just assumed to exist in binary form when we build the binary).
I raised a question about this in yao-pkg/pkg#12.
Additional context
- The
steam-run
package from NixOS simulates a FHS, but it's possible it's overkill, since you can actually simulate an FHS using nix-shell- https://jorel.dev/NixOS4Noobs/fhs.html#declaring-a-fhs-environment-for-use-in-the-nix-shell-wip
- https://ryantm.github.io/nixpkgs/builders/special/fhs-environments/
- https://discourse.nixos.org/t/flakes-way-of-creating-a-fhs-environment/20821
- But of course this would not matter if we were to create statically compiled binaries instead
- Bun (which I prefer over deno for node compatibility) supports
build --compile
and a native FFI, however that's a major overhaul, I'm not even sure if it does a full static build, no docs on this. - https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/web/nodejs/nodejs.nix - this is how Nixpkgs compiles nodejs from scratch - we could take this and customise it to take shared objects to incorporate into the final static build
- Initiative: Single Executable Application nodejs/single-executable#75 - discussions on node's native single file executable work
- CLI commands are slow to start #102 - Issues with slow startup of the Polykey CLI
- https://github.com/MatrixAI/Polykey-Enterprise/pull/20#issuecomment-2104409697 and https://github.com/MatrixAI/Polykey-Enterprise/pull/20#issuecomment-2104556833 - discussions on deno utilisation and how it works
- Unable to patch executable produced by
deno compile
and use it in Nix. REPL starts instead of program. denoland/deno#19961 (comment) - Resolution of the mystery of how to patch deno compiled binaries - Migrate to ESM (and get dynamic await) TypeScript-Demo-Lib#32 - ESM migration is necessary for optimal esbuild treeshaking - less relevant to static linking, but general performance increase too
Tasks
- Investigate static compilation using
pkg
- compiled nodejs from source, along with bringing in static binaries - Make sure the virtual filesystem that pkg needs to use still works
- Incorporate it into the nix process, the ci process, and distribution process
- Test that it works, and make sure we try to squeeze it down
- Test what "static" compilation means in the case of MacOS and Windows