mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-06 07:26:43 -04:00
Add a nix flake (#3422)
# Description of Changes Recently, my hacked-together env stopped working, probably due to our switching linkers. This pushed me to write a proper Nix packaging for SpacetimeDB, complete with flake and development environment. Some things I haven't been able to figure out (or in some cases, just haven't bothered with): - Unreal. - C# WASI SDK. - Exposing Git commit hash for `spacetime --version`. - Making the Rust SDK's reauth test work. This test tries to write a file in the home directory, which is inaccessible in the Nix sandbox. # API and ABI breaking changes It's a new thing we have to maintain if we're exposing it to users, but I need to maintain it anyways to be able to develop Spacetime, so... # Expected complexity level and risk 1 # Testing - [x] Ran `nix flake check` locally. - [x] Ran `nix build` locally and then did `spacetime start`, got an apparently-responsive SpacetimeDB. - [x] Ran `nix develop` locally, then `cargo build` and `cargo test` in the dev shell. --------- Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Directory environment using https://direnv.net/ and https://github.com/nix-community/nix-direnv.
|
||||
use flake
|
||||
@@ -220,3 +220,6 @@ new.json
|
||||
|
||||
# Test data
|
||||
!crates/core/testdata/
|
||||
|
||||
# Symlinked output from `nix build`
|
||||
result
|
||||
|
||||
@@ -353,3 +353,8 @@ result_large_err = "allow"
|
||||
# version of temporal_rs, but I'm not holding my breath.
|
||||
timezone_provider = { git = "https://github.com/boa-dev/temporal", tag = "v0.0.11" }
|
||||
temporal_rs = { git = "https://github.com/boa-dev/temporal", tag = "v0.0.11" }
|
||||
|
||||
[workspace.metadata]
|
||||
# This silences a warning in our Nix flake, which otherwise would be upset that our call to `crateNameFromCargoToml`
|
||||
# is running against a file that doesn't have a name in it.
|
||||
crane.name = "spacetimedb"
|
||||
|
||||
Generated
+98
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1759893430,
|
||||
"narHash": "sha256-yAy4otLYm9iZ+NtQwTMEbqHwswSFUbhn7x826RR6djw=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "1979a2524cb8c801520bd94c38bb3d5692419d93",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1760596604,
|
||||
"narHash": "sha256-J/i5K6AAz/y5dBePHQOuzC7MbhyTOKsd/GLezSbEFiM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3cbe716e2346710d6e1f7c559363d14e11c32a43",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1760582142,
|
||||
"narHash": "sha256-RSLRjAoS75szOc9fFzRi9/jzPbYsiqPISSLZTloaKtM=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "9ea094253b9389ba7dd4f18637f66b5824276d1d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
# crane is a framework for building Rust projects in Nix,
|
||||
# which we prefer over alternatives because it better handles multi-crate workspaces.
|
||||
crane.url = "github:ipetkov/crane";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
# rust-overlay provides more and more recent builds of the rust toolchain
|
||||
# than are available in nixpkgs.
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, crane, flake-utils, rust-overlay, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [(import rust-overlay)];
|
||||
};
|
||||
|
||||
inherit (pkgs) lib;
|
||||
|
||||
librusty_v8 = if pkgs.stdenv.isDarwin then
|
||||
# Building on MacOS, we've seen errors building rusty_v8 with a local RUSTY_V8_ARCHIVE:
|
||||
# https://github.com/clockworklabs/SpacetimeDB/pull/3422#issuecomment-3416972711 .
|
||||
# For now, error on MacOS (darwin) targets.
|
||||
builtins.abort ''
|
||||
This flake doesn't work on MacOS due to some quirk of compiling rusty-v8 against a precompiled V8 archive.
|
||||
If you can get a build working on MacOS under Nix, please submit a PR to https://github.com/clockworklabs/SpacetimeDB/pulls.
|
||||
See https://github.com/clockworklabs/SpacetimeDB/pull/3422 for more details.
|
||||
''
|
||||
# We fetch a precompiled v8 binary.
|
||||
# The rusty_v8 build.rs normally tries to download v8 artifacts during compilation,
|
||||
# but the Nix build sandbox doesn't give it network access.
|
||||
# Instead, download the archive in a Nix-friendly way with a recorded sha.
|
||||
else (pkgs.callPackage ./librusty_v8.nix {});
|
||||
|
||||
# The Rust toolchain that we actually build with.
|
||||
rustStable = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||
|
||||
# An additional Rust toolchain we put in our devShell for rust-analyzer.
|
||||
rustNightly = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.rust-analyzer);
|
||||
|
||||
version = (craneLib.crateNameFromCargoToml { inherit src; }).version;
|
||||
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain rustStable;
|
||||
|
||||
# We don't use craneLib.cleanCargoSource here because we have a lot of non-Rust files in our repo.
|
||||
# I (pgoldman 2025-10-17) am too lazy to properly compose together source cleaners appropriately.
|
||||
src = lib.cleanSource ./.;
|
||||
|
||||
# Arguments we'll pass to all of our derivations.
|
||||
commonArgs = {
|
||||
inherit src;
|
||||
strictDeps = true;
|
||||
# nativeBuildInputs are tools that are required to run during the build.
|
||||
# Usually this is stuff like programming language interpreters for build scripts.
|
||||
# In cross-compilation, these will be packages for the host machine's architecture.
|
||||
nativeBuildInputs = [
|
||||
pkgs.perl
|
||||
pkgs.python3
|
||||
pkgs.cmake
|
||||
pkgs.git
|
||||
pkgs.pkg-config
|
||||
];
|
||||
# buildInputs are libraries that wind up in the target build.
|
||||
# In cross-compilation, these will be packages for the target machine's architecture.
|
||||
buildInputs = [
|
||||
pkgs.openssl
|
||||
];
|
||||
# Add MacOS specific dependencies to either nativeBuildInputs or buildInputs with the following snippet:
|
||||
# ++ lib.optionals pkgs.stdenv.isDarwin [
|
||||
# pkgs.whateverPackage
|
||||
# ];
|
||||
|
||||
# Include our precompiled V8.
|
||||
RUSTY_V8_ARCHIVE = librusty_v8;
|
||||
};
|
||||
|
||||
# Build a separate derivation containing our dependencies,
|
||||
# which can be cached and shared between `-cli` and `-standalone`.
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
|
||||
individualCrateArgs = commonArgs // {
|
||||
inherit cargoArtifacts version;
|
||||
# We disable tests since we'll run them all in the checks target
|
||||
doCheck = false;
|
||||
};
|
||||
|
||||
makeSpacetimePackage = name: craneLib.buildPackage (individualCrateArgs // {
|
||||
pname = name;
|
||||
cargoExtraArgs = "-p ${name}";
|
||||
});
|
||||
|
||||
spacetimedb-cli = makeSpacetimePackage "spacetimedb-cli";
|
||||
|
||||
spacetimedb-standalone = makeSpacetimePackage "spacetimedb-standalone";
|
||||
|
||||
# I've chosen not to package spacetimedb-update, since it won't work on Nix systems anyways.
|
||||
|
||||
# Combine -standalone and -cli into a single derivation, with -cli named as spacetime.
|
||||
# It would be nice to use `symlinkJoin` here, but our re-exec machinery to have -cli call into -standalone
|
||||
# misbehaves when the two binaries are neighboring symlinks to real files in different directories.
|
||||
# So we just copy them.
|
||||
spacetime = pkgs.runCommand "spacetime-${version}" {} ''
|
||||
mkdir -p $out/bin
|
||||
|
||||
cp ${spacetimedb-cli}/bin/spacetimedb-cli $out/bin/spacetime
|
||||
cp ${spacetimedb-standalone}/bin/spacetimedb-standalone $out/bin/spacetimedb-standalone
|
||||
'';
|
||||
in
|
||||
{
|
||||
checks = {
|
||||
inherit spacetimedb-cli spacetimedb-standalone;
|
||||
|
||||
workspace-clippy = craneLib.cargoClippy (commonArgs // {
|
||||
inherit cargoArtifacts;
|
||||
cargoClippyExtraArgs = "--all-targets -- --deny warnings";
|
||||
});
|
||||
|
||||
workspace-fmt = craneLib.cargoFmt {
|
||||
inherit src;
|
||||
};
|
||||
|
||||
workspace-test = craneLib.cargoTest (commonArgs // {
|
||||
inherit cargoArtifacts;
|
||||
partitions = 1;
|
||||
partitionType = "count";
|
||||
# I (pgoldman 2025-10-17) have not figured out a sensible packaging of Unreal or of the .NET WASI SDK.
|
||||
# The SDK reauth tests attempt to create files in the home directory, which the nix sandbox disallows.
|
||||
cargoTestExtraArgs = "--workspace -- --skip unreal --skip csharp --skip reauth";
|
||||
});
|
||||
|
||||
# TODO: Also run smoketests.
|
||||
};
|
||||
|
||||
packages = {
|
||||
inherit spacetimedb-cli spacetimedb-standalone spacetime;
|
||||
default = spacetime;
|
||||
};
|
||||
|
||||
devShells.default = craneLib.devShell {
|
||||
checks = self.checks.${system};
|
||||
|
||||
inputsFrom = [ spacetimedb-standalone spacetimedb-cli ];
|
||||
|
||||
# Required to make jemalloc_tikv_sys build in local development, otherwise you get:
|
||||
# /nix/store/0zv32kh0zb4s1v4ld6mc99vmzydj9nm9-glibc-2.40-66-dev/include/features.h:422:4: warning: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Wcpp]
|
||||
# 422 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O)
|
||||
# | ^~~~~~~
|
||||
# In file included from /nix/store/0zv32kh0zb4s1v4ld6mc99vmzydj9nm9-glibc-2.40-66-dev/include/bits/libc-header-start.h:33,
|
||||
# from /nix/store/0zv32kh0zb4s1v4ld6mc99vmzydj9nm9-glibc-2.40-66-dev/include/math.h:27,
|
||||
# from include/jemalloc/internal/jemalloc_internal_decls.h:4,
|
||||
# from include/jemalloc/internal/jemalloc_preamble.h:5,
|
||||
# from src/pac.c:1:
|
||||
CFLAGS = "-O";
|
||||
|
||||
packages = [rustStable rustNightly cargoArtifacts];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Fetches a pre-built v8 build from GitHub.
|
||||
#
|
||||
# rusty_v8 is a bad citizen: it attempts to download a binary within its build.rs.
|
||||
# When running in the Nix sandbox, this download fails, so the crate cannot build.
|
||||
# We instead download the archive ahead of time using a Nix-friendly fetcher function,
|
||||
# and in our flake.nix we'll reference it in an appropriate env var so the crate build finds it.
|
||||
#
|
||||
# From https://github.com/msfjarvis/crane_rusty_v8/blob/4e076af4edb396d9d9398013d4393ec8da49c841/librusty_v8.nix
|
||||
# modified for our desired version
|
||||
{
|
||||
rust,
|
||||
stdenv,
|
||||
fetchurl,
|
||||
}: let
|
||||
arch = rust.toRustTarget stdenv.hostPlatform;
|
||||
fetch_librusty_v8 = args:
|
||||
fetchurl {
|
||||
name = "librusty_v8-${args.version}";
|
||||
url = "https://github.com/denoland/rusty_v8/releases/download/v${args.version}/librusty_v8_release_${arch}.a.gz";
|
||||
sha256 = args.shas.${stdenv.hostPlatform.system};
|
||||
meta = {inherit (args) version;};
|
||||
};
|
||||
in
|
||||
fetch_librusty_v8 {
|
||||
version = "140.2.0";
|
||||
shas = {
|
||||
x86_64-linux = "sha256-r3qrYDVaT4Z6udC6YuQG1BKqrsQc7IhuACDCTbr083U=";
|
||||
# I (pgoldman 2025-10-17) only use x86_64-linux, so I haven't filled in these hashes.
|
||||
# If you use one of these platforms, run the build and wait for it to fail,
|
||||
# copy the detected sha256 from the error message in here, then re-run.
|
||||
aarch64-linux = "0000000000000000000000000000000000000000000000000000";
|
||||
x86_64-darwin = "0000000000000000000000000000000000000000000000000000";
|
||||
aarch64-darwin = "sha256-eZ2l9ovI2divQake+Z4/Ofcl5QwJ+Y/ql2Dymisx1oA=";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
//! This isn't a real library, it only exists for tests/test.rs!
|
||||
//!
|
||||
//! I (pgoldman 2025-10-16) found that I needed to create an empty lib.rs in this crate
|
||||
//! in order to make Crane (the Nix toolchain for building Rust crates I'm using) happy.
|
||||
Reference in New Issue
Block a user