Use Nix and the Nixpkgs package set to import external dependencies (like system packages) into Bazel hermetically. If the version of any dependency changes, Bazel will correctly rebuild targets, and only those targets that use the external dependencies that changed.
Links:
- Nix + Bazel = fully reproducible, incremental builds (blog post)
- Nix + Bazel (lightning talk)
- nixpkgs_git_repository
- nixpkgs_local_repository
- nixpkgs_package
- nixpkgs_cc_configure
- nixpkgs_cc_configure_deprecated
- nixpkgs_java_configure
- nixpkgs_python_configure
- nixpkgs_sh_posix_configure
- nixpkgs_go_configure
Add the following to your WORKSPACE
file, and select a $COMMIT
accordingly.
http_archive(
name = "io_tweag_rules_nixpkgs",
strip_prefix = "rules_nixpkgs-$COMMIT",
urls = ["https://github.com/tweag/rules_nixpkgs/archive/$COMMIT.tar.gz"],
)
load("@io_tweag_rules_nixpkgs//nixpkgs:repositories.bzl", "rules_nixpkgs_dependencies")
rules_nixpkgs_dependencies()
load("@io_tweag_rules_nixpkgs//nixpkgs:nixpkgs.bzl", "nixpkgs_git_repository", "nixpkgs_package", "nixpkgs_cc_configure")
load("@io_tweag_rules_nixpkgs//nixpkgs:toolchains/go.bzl", "nixpkgs_go_configure") # optional
If you use rules_nixpkgs
to configure a toolchain then you will also need to
configure the build platform to include the
@io_tweag_rules_nixpkgs//nixpkgs/constraints:support_nix
constraint. For
example by adding the following to .bazelrc
:
build --host_platform=@io_tweag_rules_nixpkgs//nixpkgs/platforms:host
nixpkgs_git_repository(
name = "nixpkgs",
revision = "17.09", # Any tag or commit hash
sha256 = "" # optional sha to verify package integrity!
)
nixpkgs_package(
name = "hello",
repositories = { "nixpkgs": "@nixpkgs//:default.nix" }
)
Rules for importing Nixpkgs packages.
nixpkgs_git_repository(name, remote, revision, sha256)
Name a specific revision of Nixpkgs on GitHub or a local checkout.
name |
Name; required
A unique name for this repository. |
remote |
String; optional
The URI of the remote Git repository. This must be a HTTP URL. There is currently no support for authentication. Defaults to upstream nixpkgs. |
revision |
String; required
Git commit hash or tag identifying the version of Nixpkgs to use. |
sha256 |
String; optional
The SHA256 used to verify the integrity of the repository. |
nixpkgs_local_repository(name, nix_file, nix_file_content, nix_file_deps)
Create an external repository representing the content of Nixpkgs, based on a Nix expression stored locally or provided inline. One of nix_file
or nix_file_content
must be provided.
name |
Name; required
A unique name for this repository. |
nix_file |
Label; optional
A file containing an expression for a Nix derivation. |
nix_file_content |
String; optional
An expression for a Nix derivation. |
nix_file_deps |
List of labels; optional
Dependencies of |
nixpkgs_cc_configure(name, attribute_path, nix_file, nix_file_content, nix_file_deps, repositories, repository, nixopts, quiet, fail_not_supported, exec_constraints, target_constraints, register)
Use a CC toolchain from Nixpkgs. No-op if not a nix-based platform.
By default, Bazel auto-configures a CC toolchain from commands (e.g.
gcc
) available in the environment. To make builds more hermetic, use
this rule to specify explicitly which commands the toolchain should use.
Specifically, it builds a Nix derivation that provides the CC toolchain
tools in the bin/
path and constructs a CC toolchain that uses those
tools. Tools that aren't found are replaced by ${coreutils}/bin/false
.
You can inspect the resulting @<name>_info//:CC_TOOLCHAIN_INFO
to see
which tools were discovered.
This rule depends on rules_cc
.
Note:
You need to configure --crosstool_top=@<name>//:toolchain
to activate
this toolchain.
name |
optional.
default is |
attribute_path |
optional.
default is
optional, string, Obtain the toolchain from the Nix expression under this attribute path. Requires |
nix_file |
optional.
default is
optional, Label, Obtain the toolchain from the Nix expression defined in this file. Specify only one of |
nix_file_content |
optional.
default is
optional, string, Obtain the toolchain from the given Nix expression. Specify only one of |
nix_file_deps |
optional.
default is
optional, list of Label, Additional files that the Nix expression depends on. |
repositories |
optional.
default is
dict of Label to string, Provides |
repository |
optional.
default is
Label, Provides |
nixopts |
optional.
default is
optional, list of string, Extra flags to pass when calling Nix. Subject to location expansion, any instance of |
quiet |
optional.
default is
bool, Whether to hide |
fail_not_supported |
optional.
default is
bool, Whether to fail if |
exec_constraints |
optional.
default is
Constraints for the execution platform. |
target_constraints |
optional.
default is
Constraints for the target platform. |
register |
optional.
default is
bool, enabled by default, Whether to register (with |
nixpkgs_cc_configure_deprecated(repository, repositories, nix_file, nix_file_deps, nix_file_content, nixopts)
Use a CC toolchain from Nixpkgs. No-op if not a nix-based platform.
Tells Bazel to use compilers and linkers from Nixpkgs for the CC toolchain.
By default, Bazel auto-configures a CC toolchain from commands available in
the environment (e.g. gcc
). Overriding this autodetection makes builds
more hermetic and is considered a best practice.
nixpkgs_cc_configure(repository = "@nixpkgs//:default.nix")
repository |
optional.
default is
A repository label identifying which Nixpkgs to use.
Equivalent to |
repositories |
optional.
default is
A dictionary mapping Setting it to
for example would replace all instances of Specify one of |
nix_file |
optional.
default is
An expression for a Nix environment derivation.
The environment should expose all the commands that make up a CC
toolchain ( |
nix_file_deps |
optional.
default is
Dependencies of |
nix_file_content |
optional.
default is
An expression for a Nix environment derivation. |
nixopts |
optional.
default is
Options to forward to the nix command. |
nixpkgs_java_configure(name, attribute_path, java_home_path, repository, repositories, nix_file, nix_file_content, nix_file_deps, nixopts, fail_not_supported, quiet, toolchain, toolchain_name, toolchain_version, exec_constraints, target_constraints)
Define a Java runtime provided by nixpkgs.
Creates a nixpkgs_package
for a java_runtime
instance. Optionally,
you can also create & register a Java toolchain. This only works with Bazel >= 5.0
Bazel can use this instance to run JVM binaries and tests, refer to the
Bazel documentation for details.
Add the following to your WORKSPACE
file to import a JDK from nixpkgs:
load("@io_tweag_rules_nixpkgs//nixpkgs:nixpkgs.bzl", "nixpkgs_java_configure")
nixpkgs_java_configure(
attribute_path = "jdk11.home",
repository = "@nixpkgs",
)
Add the following configuration to .bazelrc
to enable this Java runtime:
build --javabase=@nixpkgs_java_runtime//:runtime
build --host_javabase=@nixpkgs_java_runtime//:runtime
# Adjust this to match the Java version provided by this runtime.
# See `bazel query 'kind(java_toolchain, @bazel_tools//tools/jdk:all)'` for available options.
build --java_toolchain=@bazel_tools//tools/jdk:toolchain_java11
build --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java11
Add the following to your WORKSPACE
file to import a JDK from nixpkgs:
load("@io_tweag_rules_nixpkgs//nixpkgs:nixpkgs.bzl", "nixpkgs_java_configure")
nixpkgs_java_configure(
attribute_path = "jdk11.home",
repository = "@nixpkgs",
toolchain = True,
toolchain_name = "nixpkgs_java",
toolchain_version = "11",
)
Add the following configuration to .bazelrc
to enable this Java runtime:
build --host_platform=@io_tweag_rules_nixpkgs//nixpkgs/platforms:host
build --java_runtime_version=nixpkgs_java
build --tool_java_runtime_version=nixpkgs_java
name |
optional.
default is
The name-prefix for the created external repositories. |
attribute_path |
optional.
default is
string, The nixpkgs attribute path for |
java_home_path |
optional.
default is
optional, string, The path to |
repository |
optional.
default is
See |
repositories |
optional.
default is
See |
nix_file |
optional.
default is
optional, Label, Obtain the runtime from the Nix expression defined in this file. Specify only one of |
nix_file_content |
optional.
default is
optional, string, Obtain the runtime from the given Nix expression. Specify only one of |
nix_file_deps |
optional.
default is
See |
nixopts |
optional.
default is
See |
fail_not_supported |
optional.
default is
See |
quiet |
optional.
default is
See |
toolchain |
optional.
default is
Create & register a Bazel toolchain based on the Java runtime. |
toolchain_name |
optional.
default is
The name of the toolchain that can be used in --java_runtime_version. |
toolchain_version |
optional.
default is
The version of the toolchain that can be used in --java_runtime_version. |
exec_constraints |
optional.
default is
Constraints for the execution platform. |
target_constraints |
optional.
default is
Constraints for the target platform. |
nixpkgs_package(name, attribute_path, nix_file, nix_file_deps, nix_file_content, repository, repositories, build_file, build_file_content, nixopts, quiet, fail_not_supported, kwargs)
Make the content of a Nixpkgs package available in the Bazel workspace.
If repositories
is not specified, you must provide a nixpkgs clone in nix_file
or nix_file_content
.
name |
required.
A unique name for this repository. |
attribute_path |
optional.
default is
Select an attribute from the top-level Nix expression being evaluated. The attribute path is a sequence of attribute names separated by dots. |
nix_file |
optional.
default is
A file containing an expression for a Nix derivation. |
nix_file_deps |
optional.
default is
Dependencies of |
nix_file_content |
optional.
default is
An expression for a Nix derivation. |
repository |
optional.
default is
A repository label identifying which Nixpkgs to use. Equivalent to |
repositories |
optional.
default is
A dictionary mapping Setting it to
for example would replace all instances of Specify one of |
build_file |
optional.
default is
The file to use as the BUILD file for this repository. Its contents are copied copied into the file For common use cases we provide filegroups that expose certain files as targets:
If you need different files from the nix package, you can reference them like this:
|
build_file_content |
optional.
default is
Like |
nixopts |
optional.
default is
Extra flags to pass when calling Nix. |
quiet |
optional.
default is
Whether to hide the output of the Nix command. |
fail_not_supported |
optional.
default is
If set to |
kwargs |
optional. |
nixpkgs_python_configure(name, python2_attribute_path, python2_bin_path, python3_attribute_path, python3_bin_path, repository, repositories, nix_file_deps, nixopts, fail_not_supported, quiet, exec_constraints, target_constraints)
Define and register a Python toolchain provided by nixpkgs.
Creates nixpkgs_package
s for Python 2 or 3 py_runtime
instances and a
corresponding py_runtime_pair
and toolchain
. The toolchain is
automatically registered and uses the constraint:
"@io_tweag_rules_nixpkgs//nixpkgs/constraints:support_nix"
name |
optional.
default is
The name-prefix for the created external repositories. |
python2_attribute_path |
optional.
default is
The nixpkgs attribute path for python2. |
python2_bin_path |
optional.
default is
The path to the interpreter within the package. |
python3_attribute_path |
optional.
default is
The nixpkgs attribute path for python3. |
python3_bin_path |
optional.
default is
The path to the interpreter within the package. |
repository |
optional.
default is
See |
repositories |
optional.
default is
See |
nix_file_deps |
optional.
default is
See |
nixopts |
optional.
default is
See |
fail_not_supported |
optional.
default is
See |
quiet |
optional.
default is
See |
exec_constraints |
optional.
default is
Constraints for the execution platform. |
target_constraints |
optional.
default is
Constraints for the target platform. |
nixpkgs_sh_posix_configure(name, packages, kwargs)
Create a POSIX toolchain from nixpkgs.
Loads the given Nix packages, scans them for standard Unix tools, and
generates a corresponding sh_posix_toolchain
.
Make sure to call nixpkgs_sh_posix_configure
before sh_posix_configure
,
if you use both. Otherwise, the local toolchain will always be chosen in
favor of the nixpkgs one.
name |
optional.
default is
Name prefix for the generated repositories. |
packages |
optional.
default is
List of Nix attribute paths to draw Unix tools from. |
kwargs |
optional. |
Rules for importing a Go toolchain from Nixpkgs.
NOTE: The following rules must be loaded from
@io_tweag_rules_nixpkgs//nixpkgs:toolchains/go.bzl
to avoid unnecessary
dependencies on rules_go for those who don't need go toolchain.
io_bazel_rules_go
must be available for loading before loading of
@io_tweag_rules_nixpkgs//nixpkgs:toolchains/go.bzl
.
nixpkgs_go_configure(sdk_name, repository, repositories, nix_file, nix_file_deps, nix_file_content, nixopts, fail_not_supported, quiet)
Use go toolchain from Nixpkgs.
By default rules_go configures the go toolchain to be downloaded as binaries (which doesn't work on NixOS),
there is a way to tell rules_go to look into environment and find local go binary which is not hermetic.
This command allows to setup a hermetic go sdk from Nixpkgs, which should be considered as best practice.
Cross toolchains are declared and registered for each entry in the PLATFORMS
constant in rules_go
.
Note that the nix package must provide a full go sdk at the root of the package instead of in $out/share/go
,
and also provide an empty normal file named ROOT
at the root of package.
nixpkgs_go_configure(repository = "@nixpkgs//:default.nix")
Example (optional nix support when go is a transitive dependency):
# .bazel-lib/nixos-support.bzl
def _has_nix(ctx):
return ctx.which("nix-build") != None
def _gen_imports_impl(ctx):
ctx.file("BUILD", "")
imports_for_nix = """
load("@io_tweag_rules_nixpkgs//nixpkgs:toolchains/go.bzl", "nixpkgs_go_configure")
def fix_go():
nixpkgs_go_configure(repository = "@nixpkgs")
"""
imports_for_non_nix = """
def fix_go():
# if go isn't transitive you'll need to add call to go_register_toolchains here
pass
"""
if _has_nix(ctx):
ctx.file("imports.bzl", imports_for_nix)
else:
ctx.file("imports.bzl", imports_for_non_nix)
_gen_imports = repository_rule(
implementation = _gen_imports_impl,
attrs = dict(),
)
def gen_imports():
_gen_imports(
name = "nixos_support",
)
# WORKSPACE
// ...
http_archive(name = "io_tweag_rules_nixpkgs", ...)
// ...
local_repository(
name = "bazel_lib",
path = ".bazel-lib",
)
load("@bazel_lib//:nixos-support.bzl", "gen_imports")
gen_imports()
load("@nixos_support//:imports.bzl", "fix_go")
fix_go()
sdk_name |
optional.
default is
Go sdk name to pass to rules_go |
repository |
optional.
default is
A repository label identifying which Nixpkgs to use. Equivalent to |
repositories |
optional.
default is
A dictionary mapping Setting it to
for example would replace all instances of Specify one of |
nix_file |
optional.
default is
An expression for a Nix environment derivation. The environment should expose the whole go SDK ( |
nix_file_deps |
optional.
default is
Dependencies of |
nix_file_content |
optional.
default is
An expression for a Nix environment derivation. |
nixopts |
optional.
default is |
fail_not_supported |
optional.
default is
See |
quiet |
optional.
default is
Whether to hide the output of the Nix command. |