Skip to content

Commit

Permalink
Simplify the Nix derivation as much as possible. (#144)
Browse files Browse the repository at this point in the history
### What

The Nix derivation code we have is quite sophisticated, and does things
we don't need.

I want to clean it up so we can reuse it as much as possible in other
repositories to take advantage of the caching (now we have caching
working well) and the small Docker image size.

### How

I have tried to simplify it in a couple of ways:

1. Extracting out the clever Rust cross-compilation stuff into its own
file which doesn't need to be touched very often.
2. Merging what's left of _cargo-build.nix_ and _ndc-agent.nix_.
  • Loading branch information
SamirTalwar committed Nov 6, 2023
1 parent 627b896 commit d780eaf
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 188 deletions.
51 changes: 24 additions & 27 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -27,54 +27,51 @@
overlays = [ rust-overlay.overlays.default ];
};

# Edit ./nix/ndc-agent.nix to adjust library and buildtime
# dependencies or other build configuration for postgres-agent
crateExpression = import ./nix/ndc-agent.nix;

cargoBuild = import ./nix/cargo-build.nix;

binary-name = "ndc-postgres";

package = cargoBuild {
inherit binary-name crateExpression nixpkgs crane rust-overlay localSystem;
rust = import ./nix/rust.nix {
inherit nixpkgs rust-overlay crane localSystem;
};

inherit (package) rustToolchain;
buildPackage = import ./nix/app.nix;
in
{
packages = rec {
packages = {
# a binary for whichever is the local computer
default = package;
default = buildPackage {
rust = import ./nix/rust.nix {
inherit nixpkgs rust-overlay crane localSystem;
};
};

# cross compiler an x86_64 linux binary
x86_64-linux = cargoBuild {
inherit binary-name crateExpression nixpkgs crane rust-overlay localSystem;
crossSystem = "x86_64-linux";
x86_64-linux = buildPackage {
rust = import ./nix/rust.nix {
inherit nixpkgs rust-overlay crane localSystem;
crossSystem = "x86_64-linux";
};
};
# cross compile a aarch64 linux binary
aarch64-linux = cargoBuild {
inherit binary-name crateExpression nixpkgs crane rust-overlay localSystem;
crossSystem = "aarch64-linux";
aarch64-linux = buildPackage {
rust = import ./nix/rust.nix {
inherit nixpkgs rust-overlay crane localSystem;
crossSystem = "aarch64-linux";
};
};

# docker for local system
docker = pkgs.callPackage ./nix/docker.nix {
inherit binary-name;
ndc-agent = default;
package = self.packages.${localSystem}.default;
image-name = "ghcr.io/hasura/ndc-postgres";
tag = "dev";
};
# docker for x86_64-linux
docker-x86_64-linux = pkgs.callPackage ./nix/docker.nix {
inherit binary-name;
ndc-agent = x86_64-linux;
package = self.packages.${localSystem}.x86_64-linux;
architecture = "amd64";
image-name = "ghcr.io/hasura/ndc-postgres-x86_64";
};
# docker for aarch64-linux
docker-aarch64-linux = pkgs.callPackage ./nix/docker.nix {
inherit binary-name;
ndc-agent = aarch64-linux;
package = self.packages.${localSystem}.aarch64-linux;
architecture = "arm64";
image-name = "ghcr.io/hasura/ndc-postgres-aarch64";
};
Expand All @@ -88,7 +85,7 @@

checks = {
# Build the crate as part of `nix flake check`
ndc-postgres = package;
ndc-postgres = self.packages.${localSystem}.default;
};

formatter = pkgs.nixpkgs-fmt;
Expand All @@ -114,7 +111,7 @@
pkgs.rnix-lsp
pkgs.skopeo
pkgs.nodePackages.prettier
rustToolchain
rust.rustToolchain
] ++ (
pkgs.lib.optionals
pkgs.stdenv.isLinux
Expand Down
48 changes: 48 additions & 0 deletions nix/app.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# This is a function that returns a derivation for the compiled Rust project.
{ rust }:
let
inherit (rust) pkgs;

buildArgs = {
pname = "ndc-postgres";

src =
let
isJsonFile = path: _type: builtins.match ".*json" path != null;
isSqlFile = path: _type: builtins.match ".*sql" path != null;
isSourceFile = path: type:
isJsonFile path type
|| isSqlFile path type
|| rust.craneLib.filterCargoSources path type;
in
pkgs.lib.cleanSourceWith { src = rust.craneLib.path ./..; filter = isSourceFile; };

buildInputs = [
pkgs.openssl
] ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin [
pkgs.libiconv
pkgs.darwin.apple_sdk.frameworks.Security
pkgs.darwin.apple_sdk.frameworks.SystemConfiguration
];

nativeBuildInputs = [
pkgs.pkg-config # required for non-static builds
pkgs.protobuf # required by opentelemetry-proto, a dependency of axum-tracing-opentelemetry
];
};

# Build the dependencies first.
cargoArtifacts = rust.craneLib.buildDepsOnly buildArgs;

# Then build the crate.
crate = rust.craneLib.buildPackage
(buildArgs // {
inherit cargoArtifacts;
doCheck = false;
});
in
# Override the derivation to add cross-compilation and static linking environment variables.
crate.overrideAttrs (previous: rust.buildEnv // {
# We also have to override the `cargoArtifacts` derivation with the same changes.
cargoArtifacts = previous.cargoArtifacts.overrideAttrs (previous: rust.buildEnv);
})
86 changes: 0 additions & 86 deletions nix/cargo-build.nix

This file was deleted.

11 changes: 5 additions & 6 deletions nix/docker.nix
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# This is a function that returns a derivation for a docker image.
{ ndc-agent
, binary-name
, dockerTools
{ dockerTools
, lib
, architecture ? null
, package
, image-name
, architecture ? null
, tag ? null # defaults to the output hash
, extraConfig ? { } # see config options at: https://github.com/moby/moby/blob/master/image/spec/v1.2.md#image-json-field-descriptions
}:
Expand All @@ -13,10 +12,10 @@ let
args = {
name = image-name;
created = "now";
contents = [ ndc-agent ];
contents = [ package ];
config = {
Entrypoint = [
"/bin/${binary-name}"
"/bin/${package.pname}"
];
ExposedPorts = { "8100/tcp" = { }; };
} // extraConfig;
Expand Down
69 changes: 0 additions & 69 deletions nix/ndc-agent.nix

This file was deleted.

47 changes: 47 additions & 0 deletions nix/rust.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Sets up our Rust toolchain and Crane for cross-compilation.
# This is mostly a copy of the example provided at:
# https://crane.dev/examples/cross-rust-overlay.html
{ nixpkgs
, rust-overlay
, crane
, localSystem
, crossSystem ? localSystem
}:
let
pkgs = import nixpkgs {
inherit crossSystem localSystem;
overlays = [ rust-overlay.overlays.default ];
};

lib = pkgs.pkgsBuildHost.lib;

# Converts host system string for use in environment variable names
envCase = triple: lib.strings.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] triple);

# `hostPlatform` is the cross-compilation output platform;
# `buildPlatform` is the platform we are compiling on
buildPlatform = pkgs.stdenv.buildPlatform;
hostPlatform = pkgs.stdenv.hostPlatform;

# When possibly cross-compiling we get several versions of nixpkgs of the
# form, `pkgs.pkgs<where it runs><platform it produces outputs for>`. We use
# `pkgs.pkgsBuildHost` to get packages that run at build time (so run on the
# build platform), and that produce outputs for the host platform which is the
# cross-compilation target.
rustBin = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml;
rustToolchain = rustBin.override { targets = [ hostPlatform.config ]; };
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;

buildEnv = {
CARGO_BUILD_TARGET = hostPlatform.config;
"CARGO_TARGET_${envCase hostPlatform.config}_LINKER" = "${pkgs.stdenv.cc.targetPrefix}cc";

# This environment variable may be necessary if any of your dependencies use
# a build-script which invokes the `cc` crate to build some other code. The
# `cc` crate should automatically pick up on our target-specific linker
# above, but this may be necessary if the build script needs to compile and
# run some extra code on the build system.
HOST_CC = "${pkgs.stdenv.cc.nativePrefix}cc";
};
in
{ inherit pkgs rustToolchain craneLib buildEnv; }

0 comments on commit d780eaf

Please sign in to comment.