Skip to content

Commit 00bec32

Browse files
[lowrisc] Add a Nix shell for lowrisc internal use
This adds a devShell that employees can use to bootstrap access to non-public EDA tooling. Evaluation will fail without appropriate credentials to fetch the repository 'lowrisc-nix-private'. Disclaimer: EXPERIMENTAL These shells will only be functional in the appropriate restricted environments. This is an experiment at tracking dependencies on proprietary tooling that is less out-of-band compared to simply assuming the underlying environment is pre-populated. For obvious reasons, this will always have much weaker reproducibility guarantees than freely-available software and open-source deps. However we can still lean on Nix to make bootstrapping non-public environments fast, ergonomic and hopefully reproducible within the constricted space. Using a nix flake input that is a private repository, we can effectively pin a version of the private dependencies (hash+timestamp etc) without exposing what they are. As nix is lazily evaluated, these inputs will not attempt to be fetched unless we evaluate an output which depends on them, and hence they should happily co-exist with other flake attributes for most consumers. To avoid the flake.lock in this repository from exposing the transitive deps of the private input, that flake does not track it's inputs in the standard way. Hence, impure evaluation mode is required when using these outputs. e.g. ``` nix develop .#eda_shell_lowrisc nix develop .#eda_shell_lowrisc --command bash -c \ "make -C dv/uvm/core_ibex SIMULATOR=xlm ITERATIONS=4 TEST=riscv_rand_instr_test" ``` Signed-off-by: Harry Callahan <[email protected]>
1 parent 813f510 commit 00bec32

File tree

5 files changed

+187
-20
lines changed

5 files changed

+187
-20
lines changed

dv/uvm/core_ibex/scripts/compile_tb.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ibex_cmd import get_compile_opts
1515
from scripts_lib import run_one
1616
import riscvdv_interface
17+
import nix_lib
1718

1819
import logging
1920
logger = logging.getLogger(__name__)
@@ -112,6 +113,19 @@ def _main() -> int:
112113
logger.warning(f"WARNING: Saw non-zero retcode while compiling testbench : logfile -> {md.tb_build_stdout}")
113114
return retcode
114115

116+
117+
# If in a nix shell, patch the compiled simulation executable to use our chosen shared libraries
118+
if os.getenv("IBEX_NIX_SHELL_LIB") is not None:
119+
if md.simulator == "xlm":
120+
so = md.dir_tb / "xcelium.d" / "run.d" / "librun.so"
121+
122+
# nix_lib.patch_rpath(so) # Doesn't work
123+
nix_lib.patch_dtneeded(so)
124+
125+
# Finally, strip the rpath of unecessary entries
126+
cmd = ["patchelf", str(so), "--shrink-rpath"]
127+
subprocess.check_output(cmd)
128+
115129
return 0
116130

117131

dv/uvm/core_ibex/scripts/nix_lib.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env python3
2+
# Copyright lowRISC contributors.
3+
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
import os
7+
import subprocess
8+
import pathlib3x as pathlib
9+
10+
11+
import logging
12+
logger = logging.getLogger(__name__)
13+
logger.setLevel(logging.INFO)
14+
15+
16+
def patch_rpath(so: pathlib.Path):
17+
"""Patch the rpath of the simulation executable to resolve stdenv.cc correctly."""
18+
nix_gcc_lib_path = os.getenv("IBEX_NIX_SHELL_LIB")
19+
20+
# Get the old rpath
21+
cmd = ["patchelf", "--print-rpath", str(so)]
22+
old_rpath = subprocess.check_output(cmd).decode()
23+
logger.warning(f"Old rpath : {old_rpath}")
24+
25+
# Add the nix gcc lib path to the head of the shared library's RPATH
26+
new_rpath_str = f"{nix_gcc_lib_path}:{old_rpath}"
27+
cmd = ["patchelf", "--set-rpath", new_rpath_str, str(so)]
28+
new_rpath_output = subprocess.check_output(cmd).decode()
29+
logger.warning(f"Output of --set-rpath : {new_rpath_output}")
30+
31+
# Print the new rpath
32+
cmd = ["patchelf", "--print-rpath", str(so)]
33+
new_rpath = subprocess.check_output(cmd).decode()
34+
logger.warning(f"New rpath : {new_rpath}")
35+
36+
def patch_dtneeded(so: pathlib.Path):
37+
"""Patch some stdenv.cc shared library deps of the simulation .so to be static."""
38+
# We need to setup a couple of .so deps to be static, as the 'xrun' utility
39+
# uses it's own search paths when discovering shared-library deps for the librun.so
40+
# when simulating.
41+
nix_gcc_lib_path = os.getenv("IBEX_NIX_SHELL_LIB")
42+
43+
cmd1 = ["patchelf", "--replace-needed", "libstdc++.so.6", f"{nix_gcc_lib_path}/libstdc++.so.6", str(so)]
44+
cmd2 = ["patchelf", "--replace-needed", "libgcc_s.so.1", f"{nix_gcc_lib_path}/libgcc_s.so.1", str(so)]
45+
46+
subprocess.check_output(cmd1)
47+
subprocess.check_output(cmd2)
48+

flake.lock

Lines changed: 53 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
# The input 'lowrisc-nix' contains some common dependencies that can be used
66
# by lowRISC projects. There is also an associated public binary cache.
77
lowrisc-nix.url = "github:lowRISC/lowrisc-nix";
8+
# The input 'lowrisc-nix-private' is access-controlled.
9+
# Outputs which depend on this input are for internal use only, and will fail
10+
# to evaluate without the appropriate credentials.
11+
# All outputs which depend on this input are suffixed '_lowrisc'
12+
lowrisc-nix-private.url = "git+ssh://[email protected]/lowRISC/lowrisc-nix-private.git";
813

914
nixpkgs.follows = "lowrisc-nix/nixpkgs";
1015
flake-utils.follows = "lowrisc-nix/flake-utils";
@@ -29,6 +34,13 @@
2934
};
3035
};
3136

37+
# This import creates internal-use only outputs, which build on
38+
# input attributes that cannot be fetched without appropriate credentials.
39+
lr = import ./nix/lowrisc.nix {
40+
inherit inputs pkgs system;
41+
extraDependencies = sim_shared_lib_deps;
42+
};
43+
3244
################
3345
# DEPENDENCIES #
3446
################
@@ -101,6 +113,16 @@
101113
'';
102114
};
103115

116+
# This shell uses mkShellNoCC as the stdenv CC can interfere with EDA tools.
117+
eda_shell = pkgs.lib.makeOverridable pkgs.mkShellNoCC {
118+
name = "ibex-devshell-eda";
119+
buildInputs = ibex_runtime_deps;
120+
nativeBuildInputs = ibex_project_deps;
121+
shellHook = ''
122+
${ibex_profile_common}
123+
'';
124+
};
125+
104126
syn_shell = shell.override (prev: {
105127
name = "ibex-devshell-synthesis";
106128
nativeBuildInputs = prev.nativeBuildInputs ++ ibex_syn.deps;
@@ -110,9 +132,9 @@
110132
in {
111133
devShells.${system} = {
112134
default = inputs.self.devShells.${system}.shell;
113-
114135
inherit shell;
136+
inherit eda_shell;
115137
inherit syn_shell;
116-
};
138+
} // lr.devShells;
117139
};
118140
}

nix/lowrisc.nix

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright lowRISC Contributors.
2+
# Licensed under the MIT License, see LICENSE for details.
3+
# SPDX-License-Identifier: MIT
4+
{
5+
inputs,
6+
pkgs,
7+
system,
8+
extraDependencies,
9+
...
10+
}: let
11+
12+
# Proprietary EDA deps
13+
# These dependencies are behind the 'lowrisc-nix-private' repository, which is access-controlled.
14+
lowriscEdaDeps = (
15+
map (pkg: pkg.override {
16+
# The 'extraDependencies' argument can be used to add deps to the wrapped environments the
17+
# EDA tools run inside. Just adding the deps to the devShell environments is not sufficient, as
18+
# the EDA tool wrappers end up shadowing the same paths with their own wrappers, and hence cannot
19+
# see the additional deps.
20+
inherit extraDependencies;
21+
})
22+
(with inputs.lowrisc-nix-private.packages.${system}; [vcs xcelium])
23+
);
24+
25+
lowriscProfile = ''
26+
# Xcelium
27+
# When building the simulation executable with the EDA tooling wrapped in an FHSenv, we are
28+
# depending on the stdenv.cc. Therefore, the appropriate shared libraries need to be
29+
# located at runtime for these executables to run. The rpath is not set correctly for us to
30+
# discover the correct libraries, and it does not appear to matter as when invoking the simulator
31+
# the search paths of the xrun utility are used, not those of the librun.so library.
32+
# However, setting the DT_NEEDED paths to be static/absolute does resolve correctly.
33+
# Therefore, pass the correct search paths into the build here, and patchelf the librun.so object
34+
# to setup DT_NEEDED correctly (in compile_tb.py) for the appropriate libs (libstdc++ / libgcc_s)
35+
export IBEX_NIX_SHELL_LIB=${pkgs.stdenv.cc.cc.lib}/lib
36+
'';
37+
38+
eda_shell_lowrisc = inputs.self.devShells.${system}.eda_shell.override (prev: {
39+
name = "ibex-devshell-eda-lowrisc";
40+
nativeBuildInputs = prev.nativeBuildInputs ++ lowriscEdaDeps;
41+
shellHook = prev.shellHook + lowriscProfile;
42+
});
43+
44+
in rec {
45+
devShells = {
46+
inherit eda_shell_lowrisc;
47+
};
48+
}

0 commit comments

Comments
 (0)