portable server with embedded for musl has different feature
This commit is contained in:
35
packaging/musl/README.md
Normal file
35
packaging/musl/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Portable Linux server build
|
||||
|
||||
This build produces one `x86_64` Linux server executable with embedded
|
||||
PostgreSQL. The Rust program is statically linked against musl. PostgreSQL is
|
||||
compiled against musl without optional host-library dependencies and is stored
|
||||
inside the executable by `postgresql_embedded`.
|
||||
|
||||
PostgreSQL itself remains dynamically loadable so the `btree_gist` extension
|
||||
used by the migrations works. Its musl loader is included in the embedded
|
||||
archive, and static launcher executables invoke every PostgreSQL tool through
|
||||
that loader. Neither glibc, musl, PostgreSQL nor timezone data needs to be
|
||||
installed on the target machine.
|
||||
|
||||
Build directly through the repository's Nix flake:
|
||||
|
||||
```sh
|
||||
nix build '.?submodules=1#portable-server'
|
||||
```
|
||||
|
||||
The `submodules=1` flag includes the workspace's nested Rust repositories. The
|
||||
artifact is available as `result/bin/server`. The derivation initializes a
|
||||
temporary cluster, creates `btree_gist`, sets the timezone to `UTC`, and checks
|
||||
that the final Rust executable has no ELF interpreter.
|
||||
|
||||
The resulting executable is intended for 64-bit Linux kernels. Run it normally:
|
||||
|
||||
```sh
|
||||
./result/bin/server server
|
||||
```
|
||||
|
||||
Use the external PostgreSQL build on NixOS when preferred:
|
||||
|
||||
```sh
|
||||
cargo build --release --package server --no-default-features
|
||||
```
|
||||
171
packaging/musl/default.nix
Normal file
171
packaging/musl/default.nix
Normal file
@@ -0,0 +1,171 @@
|
||||
{ pkgs, source, version }:
|
||||
|
||||
let
|
||||
muslPkgs = pkgs.pkgsMusl;
|
||||
postgresqlVersion = "17.10";
|
||||
postgresqlArchiveVersion = "17.10.0";
|
||||
archiveName = "postgresql-${postgresqlArchiveVersion}-x86_64-unknown-linux-musl.tar.gz";
|
||||
|
||||
bootstrapInput = pname: inputs:
|
||||
pkgs.lib.findFirst
|
||||
(input: (input.pname or "") == pname)
|
||||
(throw "Nixpkgs does not expose ${pname} for the musl toolchain")
|
||||
inputs;
|
||||
bootstrapRustPlatform = muslPkgs.makeRustPlatform {
|
||||
rustc = bootstrapInput
|
||||
"rustc-bootstrap"
|
||||
muslPkgs.rustc-unwrapped.nativeBuildInputs;
|
||||
cargo = bootstrapInput
|
||||
"cargo-bootstrap"
|
||||
muslPkgs.cargo.nativeBuildInputs;
|
||||
};
|
||||
|
||||
staticOpenSSL = muslPkgs.openssl.overrideAttrs (old: {
|
||||
configureFlags =
|
||||
builtins.filter (flag: flag != "shared") old.configureFlags
|
||||
++ [ "no-shared" ];
|
||||
doCheck = false;
|
||||
});
|
||||
|
||||
postgresqlSource = pkgs.fetchurl {
|
||||
url = "https://ftp.postgresql.org/pub/source/v${postgresqlVersion}/postgresql-${postgresqlVersion}.tar.bz2";
|
||||
hash = "sha256-B4oDUW3NvbcF/sr0Feo9E6lWxYnkbwn+1ooG+wBZjJA=";
|
||||
};
|
||||
|
||||
postgresqlArchive = muslPkgs.stdenv.mkDerivation {
|
||||
pname = "komp-ac-postgresql-musl";
|
||||
version = postgresqlArchiveVersion;
|
||||
src = postgresqlSource;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.bison
|
||||
pkgs.file
|
||||
pkgs.flex
|
||||
pkgs.gnutar
|
||||
pkgs.gzip
|
||||
pkgs.perl
|
||||
];
|
||||
|
||||
configurePhase = ''
|
||||
runHook preConfigure
|
||||
./configure \
|
||||
--prefix="$out/postgresql" \
|
||||
--disable-nls \
|
||||
--without-gssapi \
|
||||
--without-icu \
|
||||
--without-ldap \
|
||||
--without-libxml \
|
||||
--without-libxslt \
|
||||
--without-llvm \
|
||||
--without-lz4 \
|
||||
--without-openssl \
|
||||
--without-pam \
|
||||
--without-readline \
|
||||
--without-systemd \
|
||||
--without-zlib \
|
||||
--without-zstd
|
||||
runHook postConfigure
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
make -j"$NIX_BUILD_CORES"
|
||||
make -C contrib/btree_gist -j"$NIX_BUILD_CORES"
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
make install-strip
|
||||
make -C contrib/btree_gist install
|
||||
|
||||
"$CC" -static -Os -s -Wall -Wextra -Werror \
|
||||
-o postgresql-launcher \
|
||||
${./postgresql-launcher.c}
|
||||
|
||||
mkdir -p "$out/postgresql/libexec"
|
||||
for tool in "$out"/postgresql/bin/*; do
|
||||
toolName="''${tool##*/}"
|
||||
mv "$tool" "$out/postgresql/libexec/$toolName"
|
||||
cp postgresql-launcher "$out/postgresql/bin/$toolName"
|
||||
done
|
||||
cp ${muslPkgs.musl}/lib/ld-musl-x86_64.so.1 \
|
||||
"$out/postgresql/lib/ld-musl-x86_64.so.1"
|
||||
|
||||
file "$out/postgresql/bin/postgres" | grep -q 'statically linked'
|
||||
"$out/postgresql/bin/postgres" --version
|
||||
|
||||
mkdir postgresql-data postgresql-socket
|
||||
"$out/postgresql/bin/initdb" \
|
||||
--auth=trust \
|
||||
--no-locale \
|
||||
-D "$PWD/postgresql-data"
|
||||
"$out/postgresql/bin/pg_ctl" \
|
||||
-D "$PWD/postgresql-data" \
|
||||
-l "$PWD/postgresql.log" \
|
||||
-o "-k $PWD/postgresql-socket -p 55432" \
|
||||
-w start
|
||||
"$out/postgresql/bin/psql" \
|
||||
-h "$PWD/postgresql-socket" \
|
||||
-p 55432 \
|
||||
-d postgres \
|
||||
-c "CREATE EXTENSION btree_gist; SET TIME ZONE 'UTC';"
|
||||
"$out/postgresql/bin/pg_ctl" \
|
||||
-D "$PWD/postgresql-data" \
|
||||
-m fast \
|
||||
-w stop
|
||||
|
||||
tar -C "$out" -czf "$out/${archiveName}" postgresql
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
dontPatchELF = true;
|
||||
dontStrip = true;
|
||||
};
|
||||
in
|
||||
bootstrapRustPlatform.buildRustPackage {
|
||||
pname = "komp-ac-server-portable";
|
||||
inherit version source;
|
||||
src = source;
|
||||
|
||||
cargoLock.lockFile = ../../Cargo.lock;
|
||||
cargoBuildFlags = [
|
||||
"--package"
|
||||
"server"
|
||||
"--no-default-features"
|
||||
"--features"
|
||||
"portable-postgres"
|
||||
];
|
||||
auditable = false;
|
||||
doCheck = false;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.binutils
|
||||
pkgs.cmake
|
||||
pkgs.file
|
||||
pkgs.pkg-config
|
||||
pkgs.protobuf
|
||||
];
|
||||
buildInputs = [ staticOpenSSL ];
|
||||
|
||||
OPENSSL_STATIC = "1";
|
||||
OPENSSL_LIB_DIR = "${staticOpenSSL.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${staticOpenSSL.dev}/include";
|
||||
POSTGRESQL_VERSION = "=${postgresqlArchiveVersion}";
|
||||
KOMP_AC_POSTGRESQL_ARCHIVE = "${postgresqlArchive}/${archiveName}";
|
||||
KOMP_AC_POSTGRESQL_VERSION = postgresqlArchiveVersion;
|
||||
SQLX_OFFLINE = "true";
|
||||
RUSTFLAGS = "-Ctarget-feature=+crt-static";
|
||||
|
||||
postInstall = ''
|
||||
file "$out/bin/server" | grep -q 'statically linked'
|
||||
! readelf -l "$out/bin/server" | grep -q 'Requesting program interpreter'
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Portable komp_ac server with embedded musl PostgreSQL";
|
||||
license = pkgs.lib.licenses.agpl3Plus;
|
||||
platforms = [ "x86_64-linux" ];
|
||||
mainProgram = "server";
|
||||
};
|
||||
}
|
||||
92
packaging/musl/postgresql-launcher.c
Normal file
92
packaging/musl/postgresql-launcher.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void fail(const char *message)
|
||||
{
|
||||
fprintf(stderr, "embedded PostgreSQL launcher: %s\n", message);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
static void join_path(char *destination, size_t capacity, const char *left, const char *right)
|
||||
{
|
||||
int length = snprintf(destination, capacity, "%s/%s", left, right);
|
||||
if (length < 0 || (size_t) length >= capacity)
|
||||
fail("installation path is too long");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char executable[PATH_MAX];
|
||||
ssize_t executable_length = readlink("/proc/self/exe", executable, sizeof(executable) - 1);
|
||||
if (executable_length < 0) {
|
||||
perror("embedded PostgreSQL launcher: /proc/self/exe");
|
||||
return 127;
|
||||
}
|
||||
executable[executable_length] = '\0';
|
||||
|
||||
char *tool = strrchr(executable, '/');
|
||||
if (tool == NULL || tool[1] == '\0')
|
||||
fail("cannot determine the requested PostgreSQL tool");
|
||||
tool++;
|
||||
|
||||
char root[PATH_MAX];
|
||||
if ((size_t) executable_length >= sizeof(root))
|
||||
fail("installation path is too long");
|
||||
memcpy(root, executable, (size_t) executable_length + 1);
|
||||
|
||||
char *bin_separator = strrchr(root, '/');
|
||||
if (bin_separator == NULL)
|
||||
fail("cannot determine the PostgreSQL installation directory");
|
||||
*bin_separator = '\0';
|
||||
char *root_separator = strrchr(root, '/');
|
||||
if (root_separator == NULL)
|
||||
fail("cannot determine the PostgreSQL installation directory");
|
||||
*root_separator = '\0';
|
||||
|
||||
char loader[PATH_MAX];
|
||||
char library_path[PATH_MAX];
|
||||
char real_tool[PATH_MAX];
|
||||
join_path(loader, sizeof(loader), root, "lib/ld-musl-x86_64.so.1");
|
||||
join_path(library_path, sizeof(library_path), root, "lib");
|
||||
|
||||
char real_tool_relative[PATH_MAX];
|
||||
int relative_length = snprintf(
|
||||
real_tool_relative,
|
||||
sizeof(real_tool_relative),
|
||||
"libexec/%s",
|
||||
tool
|
||||
);
|
||||
if (relative_length < 0 || (size_t) relative_length >= sizeof(real_tool_relative))
|
||||
fail("tool path is too long");
|
||||
join_path(real_tool, sizeof(real_tool), root, real_tool_relative);
|
||||
|
||||
char **loader_argv = calloc((size_t) argc + 6, sizeof(char *));
|
||||
if (loader_argv == NULL) {
|
||||
perror("embedded PostgreSQL launcher: calloc");
|
||||
return 127;
|
||||
}
|
||||
|
||||
loader_argv[0] = loader;
|
||||
loader_argv[1] = "--library-path";
|
||||
loader_argv[2] = library_path;
|
||||
loader_argv[3] = "--argv0";
|
||||
loader_argv[4] = executable;
|
||||
loader_argv[5] = real_tool;
|
||||
for (int index = 1; index < argc; index++)
|
||||
loader_argv[index + 5] = argv[index];
|
||||
|
||||
execv(loader, loader_argv);
|
||||
fprintf(
|
||||
stderr,
|
||||
"embedded PostgreSQL launcher: cannot execute %s: %s\n",
|
||||
real_tool,
|
||||
strerror(errno)
|
||||
);
|
||||
return 127;
|
||||
}
|
||||
Reference in New Issue
Block a user