External dependencies
You can make dependencies from the Nix package repository available to ll_*
targets in a hermetic, reproducible manner.
A word of caution
The external dependency mechanism in rules_ll
lets you import external
dependencies, but it globally affects all ll_*
compile commands.
Any change to an external dependency invalidates all caches and causes a full rebuild of all toolchains.
Example
The llShell
wrapper exposes an env
attribute that you can use to set the
LL_CFLAGS
and LL_LDFLAGS
environment variables. Since rules_ll
uses the
clang-linker-wrapper
as its linking tool you don't need to add -Wl,...
to
flags in LL_LDFLAGS
. Don't use spaces in these flags and separate different
flags with colons.
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
# Substitute <version> with the current version of rules_ll.
rules_ll.url = "github:eomii/rules_ll/<version>";
};
outputs =
{ self
, nixpkgs
, flake-utils
, rules_ll
, ...
} @ inputs:
flake-utils.lib.eachSystem [
"x86_64-linux"
]
(system:
let
pkgs = import nixpkgs { inherit system; };
openssl_static = (pkgs.openssl.override { static = true; });
llShell = rules_ll.lib.${system}.llShell;
in
{
devShells = {
default = llShell {
unfree = true; # Optionally enable CUDA toolchains.
packages = [ ];
env = {
LL_CFLAGS = "-I${openssl_static.dev}/include";
LL_LDFLAGS = "-L${openssl_static.out}/lib";
};
};
};
});
}
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
# Substitute <version> with the current version of rules_ll.
rules_ll.url = "github:eomii/rules_ll/<version>";
};
outputs =
{ self
, nixpkgs
, flake-utils
, rules_ll
, ...
} @ inputs:
flake-utils.lib.eachSystem [
"x86_64-linux"
]
(system:
let
pkgs = import nixpkgs { inherit system; };
openssl_static = (pkgs.openssl.override { static = true; });
llShell = rules_ll.lib.${system}.llShell;
in
{
devShells = {
default = llShell {
unfree = true; # Optionally enable CUDA toolchains.
packages = [ ];
env = {
LL_CFLAGS = "-I${openssl_dynamic.dev}/include";
LL_LDFLAGS = "-L${openssl_dynamic.out}/lib:-rpath=${openssl_dynamic.out}/lib";
};
};
};
});
}
You can see the values of LL_CFLAGS
and LL_LDFLAGS
by printing them like any
other environment variable:
echo $LL_CFLAGS
# -I/nix/store/<...>-openssl-<version>-dev/include
echo $LL_LDFLAGS
# -L/nix/store/<...>-openssl-<version>/lib
echo $LL_CFLAGS
# -I/nix/store/<...>-openssl-<version>-dev/include
echo $LL_LDFLAGS
# -L/nix/store/<...>-openssl-<version>/lib:-rpath=/nix/store/<...>-openssl-<version>/lib
You can now add the library via link_flags
or shared_object_link_flags
:
load("@rules_ll//ll:defs.bzl", "ll_binary")
ll_binary(
name = "my_externally_dependent_executable",
srcs = ["main.cpp"],
link_flags = [
"-lcrypto", # Default linkage as set in the flake.
# "-l:libcrypto.a", # Explicit static linkage.
# "-l:libcrypto.so", # Explicit dynamic linkage.
],
)
Keep in mind that LL_CFLAGS
and LL_LDFLAGS
globally affect ll_*
targets:
- Every compile action can see all headers in
LL_CFLAGS
. If two dependencies contain headers with the same name your builds might break with confusing errors. If you suspect a wrong header inclusion you can add-H
to thecompile_flags
attribute of your target to print the full inclusion chain. - Referencing paths to non-nix dependencies in these flags breaks the hermeticity and reproducibility of the build.
- Referencing paths that contain headers supplied by
rules_ll
itself such as/usr/include
or${pkgs.libcxx}/include
overrides parts of the internalll_*
toolchains and breaks allll_*
targets. - Link actions add all
-rpath
values fromLL_LDFLAGS
to every target even if the target doesn't actually link the corresponding library. This affectsll_binary
,ll_test
andll_library
withemit = ["shared_object"]
.