diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4836f91915..3791b1563a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -95,6 +95,10 @@ tools/ @DataDog/apm-common-components-core windows/ @DataDog/libdatadog-core fuzz/ @DataDog/chaos-platform +# Nix +*.nix @DataDog/nix-guild @DataDog/apm-common-components-core +flake.* @DataDog/nix-guild @DataDog/apm-common-components-core + # Specific overrides (must come after their general patterns above) bin_tests/tests/test_the_tests.rs @DataDog/libdatadog-core bin_tests/src/bin/test_the_tests.rs @DataDog/libdatadog-core @@ -105,3 +109,4 @@ libdd-data-pipeline/tests/test_trace_exporter_otlp_export.rs @DataDog/apm-sdk-ca libdd-trace-utils/src/otlp_encoder/ @DataDog/apm-sdk-capabilities-rust datadog-sidecar/src/service/ffe_exposures_flusher.rs @DataDog/libdatadog-php @DataDog/libdatadog-apm @DataDog/feature-flagging-and-experimentation-sdk datadog-sidecar/src/service/ffe_metrics_flusher.rs @DataDog/libdatadog-php @DataDog/libdatadog-apm @DataDog/feature-flagging-and-experimentation-sdk +.github/workflows/nix.yml @DataDog/nix-guild @DataDog/apm-common-components-core diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000000..9c8b92dbe8 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,86 @@ +name: Test Nix + +on: # yamllint disable-line rule:truthy + push: + branches: + - main + - mq-working-branch-* + # Also run on PRs that touch the devshell or what it reads. Paths mirror the + # Nix CODEOWNERS entries, plus the toolchain files (read by the flake) and + # this workflow itself. + pull_request: + paths: + - "*.nix" + - "flake.*" + - "rust-toolchain.toml" + - "nightly-toolchain.toml" + - ".github/workflows/nix.yml" + +# Default permissions for all jobs +permissions: {} + +concurrency: + group: ci-${{ github.ref == 'refs/heads/main' && github.run_id || github.ref }}-nix + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + strategy: + fail-fast: false + matrix: + platform: + - os: darwin + cpu: arm64 + base: macos-15 # always arm64-darwin + - os: linux + cpu: x86_64 + base: ubuntu-24.04 # always x86_64-linux-gnu + - os: linux + cpu: aarch64 + base: ubuntu-24.04-arm # always aarch64-linux-gnu + + name: Test Nix (${{ matrix.platform.cpu }}-${{ matrix.platform.os }}) + runs-on: ${{ matrix.platform.base }} + + permissions: + contents: read + + steps: + - name: Check CPU arch + run: | + test "$(uname -m)" = "${{ matrix.platform.cpu }}" + - name: Free Disk Space (Linux only) + if: runner.os == 'Linux' + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # 1.3.1 + with: + tool-cache: true + android: true + dotnet: true + haskell: true + large-packages: false + docker-images: false + swap-storage: false + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: cachix/install-nix-action@ab739621df7a23f52766f9ccc97f38da6b7af14f # v31.10.5 + - name: Print toolchain versions + run: | + nix develop --command rustc --version + nix develop --command cargo --version + nix develop --command cbindgen --version + - name: Check nightly formatter toolchain + run: nix develop .#nightly --command cargo fmt --version + - name: Build workspace + run: nix develop --command cargo build --workspace --exclude builder + + complete: + name: Nix (complete) + runs-on: ubuntu-24.04 + needs: + - test + steps: + - run: echo "DONE!" diff --git a/README.md b/README.md index a82e33abe0..1336400045 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,52 @@ We provide two Dev Container configurations: The container includes all necessary dependencies for building and testing `libdatadog`. +#### Nix development shell + +The Nix flake provides a reproducible, pinned shell with Rust, `cbindgen`, and native build tools. + +This works natively under both Linux and Darwin. + +##### Prerequisite: install Nix + +This one-liner installs Nix isolated in `/nix`: + +```bash +curl --proto '=https' --tlsv1.2 --location https://nixos.org/nix/install | sh -s -- --daemon +``` + +Enable the modern CLI and flakes in `/etc/nix/nix.conf`: + +```bash +echo "experimental-features = nix-command flakes" | sudo tee -a /etc/nix/nix.conf +``` + +See the [Nix manual](https://nix.dev/manual/nix/2.28/installation/index.html) for more information. + +##### Spawn an interactive shell + +Spawn a shell with an environment set up to expose the tooling: + +```bash +nix develop +``` + +Note: legacy `nix-shell` and `nix-build` are also available via the `flake-compat` shims. + +##### Run commands + +Alternatively, run individual commands: + +```bash +nix develop --command cargo build --workspace --exclude builder +nix develop .#nightly --command cargo fmt --all -- --check +``` + +##### Debugging CI failures + +- Reproduce the Nix CI build with `nix develop --command cargo build --workspace --exclude builder`. +- After an MSRV or nightly bump, update `rust-toolchain.toml` or `nightly-toolchain.toml`, then refresh `flake.lock` with `nix flake update`. + #### Docker container A dockerfile is provided to run tests in a Ubuntu linux environment. This is particularly useful for running and debugging linux-only tests on macOS. diff --git a/default.nix b/default.nix new file mode 100644 index 0000000000..c84e9b9227 --- /dev/null +++ b/default.nix @@ -0,0 +1,14 @@ +# Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/ +# SPDX-License-Identifier: Apache-2.0 + +# flake-compat shim for usage without flakes +(import + ( + let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in + fetchTarball { + url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; + } + ) + { src = ./.; } +).defaultNix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..354ed9fc75 --- /dev/null +++ b/flake.lock @@ -0,0 +1,97 @@ +{ + "nodes": { + "flake-compat": { + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "revCount": 69, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" + } + }, + "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": 1778075060, + "narHash": "sha256-92Rkn1l444SJcZ/W34ZimhmzA38wUoW4UOehHHjxTCI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d8176a9b6c86c609774bc698d9c5ee8649089c98", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "release-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1781580018, + "narHash": "sha256-BlTedbM77FmesD2ZqR73vhFy+y77UrhefV7IYw1pDsk=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "8bceba21a1ebea535c27c4dc723a0d5a4db9e386", + "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 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000..fc9fc420e6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,62 @@ +# Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/ +# SPDX-License-Identifier: Apache-2.0 + +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/release-25.11"; + + # cross-platform convenience + flake-utils.url = "github:numtide/flake-utils"; + + # backwards compatibility with nix-build and nix-shell + flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"; + + # pinned, exact upstream Rust toolchains + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, flake-utils, flake-compat, rust-overlay }: + # resolve for all platforms in turn + flake-utils.lib.eachDefaultSystem (system: + let + # packages for this system platform, with the rust-overlay applied + pkgs = import nixpkgs { + inherit system; + overlays = [ (import rust-overlay) ]; + }; + + # A devshell for a given Rust toolchain (read from a toolchain file via + # rust-overlay), with the rest of the build dependencies. + mkDevShell = rust: pkgs.stdenv.mkDerivation { + name = "libdatadog-devshell"; + + # The stdenv cc-wrapper injects -D_FORTIFY_SOURCE, which glibc rejects + # when compiling without optimization. Some build scripts (e.g. + # spawn_worker's trampoline.c) compile C at -O0 with -Werror, so the + # resulting fortify #warning becomes a hard error. Disable fortify + # hardening in the shell so those builds succeed. + hardeningDisable = [ "fortify" "fortify3" ]; + + nativeBuildInputs = [ + rust # rustc + cargo + rustfmt + clippy, pinned via toolchain file + pkgs.rust-cbindgen + pkgs.cmake + pkgs.autoconf + pkgs.automake + pkgs.libtool + ]; + }; + in { + # Default: the pinned stable toolchain (single source of truth is + # ./rust-toolchain.toml), matching CI and rustup. + devShells.default = mkDevShell (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml); + + # Nightly toolchain (./nightly-toolchain.toml) for the jobs that + # genuinely need a nightly compiler. Use with `nix develop .#nightly`. + devShells.nightly = mkDevShell (pkgs.rust-bin.fromRustupToolchainFile ./nightly-toolchain.toml); + } + ); +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000..f13c5a6659 --- /dev/null +++ b/shell.nix @@ -0,0 +1,14 @@ +# Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/ +# SPDX-License-Identifier: Apache-2.0 + +# flake-compat shim for usage without flakes +(import + ( + let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in + fetchTarball { + url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; + } + ) + { src = ./.; } +).shellNix