Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/source/builder/nix.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Using the kernel builder with Nix

> [!NOTE]
> The [install script](writing-kernels.md#quick-install) automates
> the Nix and kernel-builder setup described below. Use these manual
> instructions if you prefer step-by-step control.
The kernel builder uses Nix for building kernels. You can build or
run the kernels directly if you have Nix installed on your system.
We recommend installing Nix in the following way:
Expand Down
28 changes: 28 additions & 0 deletions docs/source/builder/writing-kernels.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,34 @@ support.

## Setting up environment

### Quick install

The fastest way to get started is to run the install script. This
installs [Determinate Nix](https://docs.determinate.systems/determinate-nix/)
and `kernel-builder` in a single command:

```bash
curl -fsSL https://raw.githubusercontent.com/huggingface/kernels/main/install.sh | bash
```

This will:

1. Install Determinate Nix (if not already installed).
2. Configure the Hugging Face binary cache (to avoid building dependencies from
source).
3. Install `kernel-builder` via `nix profile install`.

To update `kernel-builder` later:

```bash
nix profile upgrade --all
```

For a step-by-step breakdown of what the script does, see
[Using the kernel builder with Nix](nix.md).

### Cloud environment

In the [`terraform`](https://github.com/huggingface/kernels/tree/main/terraform) directory, we provide an
example of programatically spinning up an EC2 instance that is ready
with everything needed for you to start developing and building
Expand Down
150 changes: 150 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/bin/bash
set -euo pipefail

# kernel-builder installer
# Usage: curl -fsSL https://raw.githubusercontent.com/huggingface/kernels/main/install.sh | bash

FLAKE_REF="github:huggingface/kernels"
NIX_PROFILE_SCRIPT="/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"

# --- Colors (respect NO_COLOR) ---

if [ -z "${NO_COLOR:-}" ] && [ -t 1 ]; then
BOLD="\033[1m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
RED="\033[0;31m"
RESET="\033[0m"
else
BOLD=""
GREEN=""
YELLOW=""
RED=""
RESET=""
fi

info() { echo -e "${BOLD}${GREEN}==>${RESET} ${BOLD}$1${RESET}"; }
warn() { echo -e "${BOLD}${YELLOW}warning:${RESET} $1"; }
error() { echo -e "${BOLD}${RED}error:${RESET} $1" >&2; }

# --- macOS: Xcode check ---

check_xcode() {
if [ "$(uname -s)" = "Darwin" ]; then
if ! xcode-select -p &>/dev/null; then
warn "Xcode is not installed. It is required for building Metal kernels."
echo " Install it with: xcode-select --install"
fi
fi
}

# --- Nix ---

find_nix() {
if command -v nix &>/dev/null; then
return 0
elif [ -x "/nix/var/nix/profiles/default/bin/nix" ]; then
export PATH="/nix/var/nix/profiles/default/bin:$PATH"
return 0
fi
return 1
}

install_nix() {
if find_nix; then
info "Nix is already installed: $(nix --version)"
return 0
fi

info "Installing Determinate Nix..."
curl -fsSL https://install.determinate.systems/nix | sh -s -- install --no-confirm

# Source the Nix profile so nix is available in this shell.
if [ -f "$NIX_PROFILE_SCRIPT" ]; then
# shellcheck disable=SC1090
. "$NIX_PROFILE_SCRIPT"
fi

if ! find_nix; then
error "Nix installation completed but 'nix' was not found in PATH."
echo " Try restarting your shell or running:"
echo " . $NIX_PROFILE_SCRIPT"
exit 1
fi

info "Nix installed: $(nix --version)"
}

# --- Binary cache ---

HF_SUBSTITUTER="https://huggingface.cachix.org"
HF_PUBLIC_KEY="huggingface.cachix.org-1:ynTPbLS0W8ofXd9fDjk1KvoFky9K2jhxe6r4nXAkc/o="

configure_cache() {
if sudo nix config show 2>/dev/null | grep -q "huggingface.cachix.org"; then
info "Hugging Face binary cache is already configured"
return 0
fi

info "Configuring Hugging Face binary cache..."

sudo tee -a /etc/nix/nix.custom.conf >/dev/null <<EOF
trusted-users = root $USER
extra-trusted-substituters = $HF_SUBSTITUTER
extra-trusted-public-keys = $HF_PUBLIC_KEY
EOF

sudo systemctl restart nix-daemon 2>/dev/null || sudo pkill -HUP nix-daemon || true
sleep 3
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that systemctl restart might return before the Nix daemon is actually ready to serve requests with the new config — despite blocking on the unit state, the daemon's socket may not be ready yet.

This is needed in order to propagate the substitutes above to Nix config.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe there is a principled way of waiting until the socket is ready?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an onboarding script, I think this is fine to relax a bit of complexity.

info "Binary cache configured"
}

# --- Install kernel-builder ---

install_kernel_builder() {
info "Installing kernel-builder..."

local nix_args=(--accept-flake-config)

# macOS requires relaxed sandboxing to access the Metal compiler.
if [ "$(uname -s)" = "Darwin" ]; then
nix_args+=(--extra-conf "sandbox = relaxed")
fi

nix profile add "${nix_args[@]}" "${FLAKE_REF}#kernel-builder"

# Symlink the kernel-builder binary to /usr/local/bin for easy access
sudo ln -sf "$HOME/.nix-profile/bin/kernel-builder" /usr/local/bin/kernel-builder

info "kernel-builder installed: $(kernel-builder --version)"
}

# --- Main ---

main() {
echo ""
echo -e "${BOLD}kernel-builder installer${RESET}"
echo ""

check_xcode
install_nix
configure_cache
install_kernel_builder

echo ""
echo -e "${BOLD}${GREEN}kernel-builder installed successfully!${RESET}"
echo ""
echo " Next steps:"
echo " 1. Create a new kernel: kernel-builder init my-kernel"
echo " 2. Build your kernel: cd my-kernel && nix run .#build-and-copy -L"
echo " 3. Read the docs: https://huggingface.co/docs/kernels/"
echo ""
echo " To update kernel-builder later:"
echo " nix profile upgrade --all"
echo ""
echo " Note: you may need to restart your shell or run:"
echo " . $NIX_PROFILE_SCRIPT"
echo ""
Comment on lines +145 to +147
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will likely be required since we cant update the users shell from within this bash script install (i think...)

when I tested locally I needed to run . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh since the cli was not found.

another possible idea is that we add a symlink to the profile path into a location that is likely loaded into the users env already. maybe something like

sudo ln -sf "$HOME/.nix-profile/bin/kernel-builder" /usr/local/bin/kernel-builder

although I'm not sure if this a bad practice when it comes to nix profiles. just a thought

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script already sources the Nix profile via find_nix / . "$NIX_PROFILE_SCRIPT" within its own process, so kernel-builder --version works during the script.

I would prefer this to symlinking, though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea sorry I wasn't clear, I meant it is likely required for the user to run, if we don't have some other method to make it available automatically. might be worth exploring the symlink or some other approach.

However if this is too tedious, I also think its okay if we require the user to run . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh for now

}

main
Loading