switch from conda to nix for tooling

This commit is contained in:
Jesse Cirimelli-Low 2026-04-30 12:00:56 -07:00
parent 2780fda35c
commit ddac4254ec
17 changed files with 178 additions and 177 deletions

View File

@ -19,31 +19,30 @@ jobs:
run: |
rm -rf ~/.local/lib/python3.8/site-packages/openram*
make library
- name: Build conda
run: |
./install_conda.sh
- name: PDK Install
run: |
export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology"
export PDK_ROOT="${{ github.workspace }}/pdk"
nix --extra-experimental-features 'nix-command flakes' develop --command bash -lc '
export OPENRAM_HOME="${{ github.workspace }}/compiler";
export OPENRAM_TECH="${{ github.workspace }}/technology";
export PDK_ROOT="${{ github.workspace }}/pdk";
# Add make targets to install PDKs of all technologies that need it
make sky130-pdk
make sky130-pdk;
make sky130-install
- name: Regress
run: |
export OPENRAM_HOME="${{ github.workspace }}/compiler"
export OPENRAM_TECH="${{ github.workspace }}/technology"
export PDK_ROOT="${{ github.workspace }}/pdk"
export FREEPDK45="~/FreePDK45"
nix --extra-experimental-features 'nix-command flakes' develop --command bash -lc '
export OPENRAM_HOME="${{ github.workspace }}/compiler";
export OPENRAM_TECH="${{ github.workspace }}/technology";
export PDK_ROOT="${{ github.workspace }}/pdk";
export FREEPDK45="~/FreePDK45";
# KLAYOUT_PATH breaks klayout installation. Unset it for now...
unset KLAYOUT_PATH
unset KLAYOUT_PATH;
#cd $OPENRAM_HOME/.. && make pdk && make install
#export OPENRAM_TMP="${{ github.workspace }}/scn4me_subm_temp"
#python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 12 -t scn4m_subm
#$OPENRAM_HOME/tests/regress.py -j 24 -t scn4m_subm
cd $OPENRAM_HOME/tests
make clean
cd $OPENRAM_HOME/tests;
make clean;
make -k -j 48
- name: Archive
if: ${{ failure() }}

1
.gitignore vendored
View File

@ -19,7 +19,6 @@ compiler/tests/results/
open_pdks/
dist/
openram.egg-info/
miniconda/
sky130A
sky130B
gf180mcuA

View File

@ -2,7 +2,6 @@ include Makefile
include openram.mk
include setpaths.sh
include requirements.txt
include install_conda.sh
include docker/*
recursive-include compiler *
recursive-include technology *

View File

@ -57,8 +57,8 @@ INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_
INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130
INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS))
# If conda is installed, we will use ciel from there
CONDA_DIR := $(wildcard $(TOP_DIR)/miniconda)
# If nix is available, run ciel via nix develop
NIX_BIN := $(shell command -v nix 2>/dev/null)
check-pdk-root:
ifndef PDK_ROOT
@ -102,23 +102,21 @@ sky130-install: $(SRAM_LIB_DIR)
sky130-pdk: $(SKY130_PDKS_DIR)
@echo "Installing SKY130 via ciel..."
ifeq ($(CONDA_DIR),)
ifeq ($(NIX_BIN),)
ciel enable --pdk sky130 $(SKY130_CIEL)
else
source $(TOP_DIR)/miniconda/bin/activate && \
ciel enable --pdk sky130 $(SKY130_CIEL) && \
conda deactivate
nix --extra-experimental-features 'nix-command flakes' develop --command \
ciel enable --pdk sky130 $(SKY130_CIEL)
endif
.PHONY: sky130-pdk
gf180mcu-pdk:
@echo "Installing GF180 via ciel..."
ifeq ($(CONDA_DIR),)
ifeq ($(NIX_BIN),)
ciel enable --pdk gf180mcu $(GF180_CIEL)
else
source $(TOP_DIR)/miniconda/bin/activate && \
ciel enable --pdk gf180mcu $(GF180_CIEL) && \
conda deactivate
nix --extra-experimental-features 'nix-command flakes' develop --command \
ciel enable --pdk gf180mcu $(GF180_CIEL)
endif
.PHONY: gf180mcu-pdk

View File

@ -23,22 +23,11 @@ if "OPENRAM_HOME" not in os.environ.keys():
__path__.insert(0, OPENRAM_HOME)
# Find the conda installer script
if os.path.exists(OPENRAM_HOME + "/install_conda.sh"):
CONDA_INSTALLER = OPENRAM_HOME + "/install_conda.sh"
CONDA_HOME = OPENRAM_HOME + "/miniconda"
elif os.path.exists(OPENRAM_HOME + "/../install_conda.sh"):
CONDA_INSTALLER = OPENRAM_HOME + "/../install_conda.sh"
CONDA_HOME = os.path.abspath(OPENRAM_HOME + "/../miniconda")
# Override CONDA_HOME if it's set as an environment variable
if "CONDA_HOME" in os.environ.keys():
CONDA_HOME = os.environ["CONDA_HOME"]
# Add CONDA_HOME to environment variables just in case
try:
os.environ["CONDA_HOME"] = CONDA_HOME
except:
from openram import debug
debug.warning("Couldn't find conda setup directory.")
# Nix toolchain root (flake location)
NIX_HOME = os.path.abspath(OPENRAM_HOME + "/..")
if "NIX_HOME" in os.environ.keys():
NIX_HOME = os.environ["NIX_HOME"]
os.environ["NIX_HOME"] = NIX_HOME
# Import everything in globals.py

View File

@ -12,6 +12,7 @@ simulations as well.
"""
import os
import shlex
import subprocess
import numpy as np
from openram import debug
@ -406,11 +407,15 @@ class stimuli():
spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w')
spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w')
# Wrap the command with conda activate & conda deactivate
# Run spice in the Nix devShell when Nix-managed tools are enabled.
# FIXME: Should use verify/run_script.py here but run_script doesn't return
# the return code of the subprocess. File names might also mismatch.
from openram import CONDA_HOME
cmd = "/bin/bash -c 'source {0}/bin/activate && {1} && conda deactivate'".format(CONDA_HOME, cmd)
if OPTS.use_nix:
cmd = (
"nix --extra-experimental-features 'nix-command flakes' "
"develop --command /bin/bash -lc {0}"
.format(shlex.quote(cmd))
)
debug.info(2, cmd)
proc = subprocess.run(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True)

View File

@ -188,7 +188,7 @@ def init_openram(config_file, is_unit_test=False):
read_config(config_file, is_unit_test)
install_conda()
install_nix()
import_tech()
@ -209,17 +209,40 @@ def init_openram(config_file, is_unit_test=False):
from openram import verify
def install_conda():
""" Setup conda for default tools. """
def install_nix():
"""Initialize Nix-based toolchain dependencies."""
# Don't setup conda if not used
if not OPTS.use_conda or OPTS.is_unit_test:
# Don't setup tools during unit tests.
if OPTS.is_unit_test:
return
debug.info(1, "Creating conda setup...");
if not OPTS.use_nix or OPTS.is_unit_test:
return
from openram import CONDA_INSTALLER
subprocess.call(CONDA_INSTALLER)
debug.info(1, "Bootstrapping toolchain with Nix...")
nix_exe = shutil.which("nix")
if nix_exe is None:
debug.error("Nix is required for automatic tool setup, but 'nix' was not found in PATH.", -1)
repo_root = os.path.abspath(os.path.join(OPENRAM_HOME, ".."))
flake_file = os.path.join(repo_root, "flake.nix")
if not os.path.exists(flake_file):
debug.error("Expected Nix flake at {} for tool setup.".format(flake_file), -1)
# Trigger materialization/build of the devShell dependencies once.
# Environment activation still happens outside OpenRAM via `nix develop`.
cmd = [
nix_exe,
"--extra-experimental-features", "nix-command flakes",
"develop",
"--command", "true",
]
result = subprocess.call(cmd, cwd=repo_root)
if result != 0:
debug.error("Failed to initialize Nix toolchain (nix develop returned {}).".format(result), -1)
return
def setup_bitcell():
@ -446,14 +469,7 @@ def find_exe(check_exe):
Check if the binary exists in any path dir and return the full path.
"""
# Search for conda setup if used
if OPTS.use_conda:
from openram import CONDA_HOME
search_path = "{0}/bin{1}{2}".format(CONDA_HOME,
os.pathsep,
os.environ["PATH"])
else:
search_path = os.environ["PATH"]
search_path = os.environ["PATH"]
# Check if the preferred spice option exists in the path
for path in search_path.split(os.pathsep):

View File

@ -151,9 +151,9 @@ class options(optparse.Values):
###################
# Top process that was ran (openram, memchar, memfunc)
top_process = None
# Use conda to install the default tools
# (existing tools will be used if disabled)
use_conda = True
# Use Nix to initialize the default open-source toolchain.
# If disabled, OpenRAM uses whatever tools are already in PATH.
use_nix = True
# Variable to select the variant of spice
spice_name = None
# The spice executable being used which is derived from the user PATH.

View File

@ -29,26 +29,21 @@ def run_script(cell_name, script="lvs"):
scriptpath = '{0}run_{1}.sh'.format(OPTS.openram_temp, script)
# Wrap with conda activate & conda deactivate
if OPTS.use_conda:
from openram import CONDA_HOME
with open(scriptpath, "r") as f:
script_content = f.readlines()
with open(scriptpath, "w") as f:
# First line is shebang
f.write(script_content[0])
# Activate conda using the activate script
f.write("source {}/bin/activate\n".format(CONDA_HOME))
for line in script_content[1:]:
f.write(line)
# Deactivate conda at the end
f.write("conda deactivate\n")
debug.info(2, "Starting {}".format(scriptpath))
start = time.time()
with open(outfile, 'wb') as fo, open(errfile, 'wb') as fe:
if OPTS.use_nix:
p_cmd = [
"nix",
"--extra-experimental-features", "nix-command flakes",
"develop",
"--command",
scriptpath,
]
else:
p_cmd = [scriptpath]
p = subprocess.Popen(
[scriptpath], stdout=fo, stderr=fe, cwd=OPTS.openram_temp)
p_cmd, stdout=fo, stderr=fe, cwd=OPTS.openram_temp)
if echo_cmd_output:
tailo = subprocess.Popen([

View File

@ -7,8 +7,8 @@ This page shows the basic setup for using OpenRAM to generate an SRAM.
## Table of Contents
1. [Dependencies](#dependencies)
1. [Anaconda](#anaconda)
1. [Docker](#docker-deprecated-use-anaconda-instead)
1. [Nix](#nix)
1. [Docker](#docker-deprecated-use-nix-instead)
1. [Environment](#environment)
1. [Sky130 Setup](#sky130-setup)
@ -20,51 +20,25 @@ In general, the OpenRAM compiler has very few dependencies:
+ Make
+ Python 3.5 or higher
+ Various Python packages (pip install -r requirements.txt)
+ Anaconda
+ Nix
## Anaconda
We use Anaconda package manager to install the tools used by OpenRAM. This way,
you don't have to worry about updating/installing these tools. OpenRAM installs
Anaconda silently in the background (without affecting any existing Anaconda
setup you have).
## Nix
OpenRAM uses Nix to provide the external toolchain (layout tools, simulators,
etc.) needed for SRAM generation.
You don't have to manually activate/deactivate the Anaconda environment. OpenRAM
automatically manages this before and after running the tools.
OpenRAM uses Anaconda by default, but you can turn this feature off by setting
`use_conda = False` in your config file. Then, OpenRAM will use the tools you
have installed on your system.
You can also tell OpenRAM where Anaconda should be installed or which Anaconda
setup it should use. You can set the `$CONDA_HOME` variable like this:
Enter the Nix development environment with:
```
export CONDA_HOME="/path/to/conda/setup"
nix develop
```
> **Note**: If you want to install Anaconda without running OpenRAM (for example
> to run unit tests, which do not install Anaconda), you can run:
> ```
> ./install_conda.sh
> ```
Within the devShell, required executables are available on `PATH`
> **Note**: You can uninstall OpenRAM's Anaconda installation by simply deleting
> the folder Anaconda is installed to. You can run:
> ```
> rm -rf miniconda
> ```
OpenRAM uses the `use_nix` option (enabled by default) to initialize Nix-based
tool dependencies via `nix develop`.
> **Note**: You can change a tool's version with the following commands:
> ```
> source ./miniconda/bin/activate
> conda uninstall <tool>
> conda install -y -c vlsida-eda <tool>=<version>
> ```
## Docker (deprecated, use Anaconda instead)
## Docker (deprecated, use Nix instead)
We have a [docker setup](../../docker) to run OpenRAM. To use this, you should
run:
```
@ -124,12 +98,11 @@ make sky130-pdk
This will use ciel to get the PDK.
> **Note**: If you don't have Magic installed, you need to install and activate
> the conda environment before running this command. You can run:
> **Note**: If you don't have Magic installed, enter the OpenRAM Nix devShell
> first (it provides Magic and other tools via `PATH`):
>
> ```
> ./install_conda.sh
> source miniconda/bin/activate
> nix develop
> ```
Then you must also install the [Sky130] SRAM build space with the appropriate

View File

@ -61,10 +61,9 @@ make -j 3
```
The `-j` can run with 3 threads. By default, this will run in all technologies.
> **Note**: If you have not run openram before running unit tests, the conda
> environment will not be installed. You can install it by running
> `OpenRAM/install_conda.sh` (see [Basic Setup](basic_setup.md#anaconda) for
> more details).
> **Note**: The external EDA toolchain is provided by the Nix devShell.
> If you run unit tests without being in a Nix environment, enter it first:
> `nix develop` (see [Basic Setup](basic_setup.md#nix) for more details).
To run a specific test in all technologies:
```

View File

@ -40,7 +40,7 @@ In general, the OpenRAM compiler has very few dependencies:
+ Make
+ Python 3.5 or higher
+ Various Python packages (pip install -r requirements.txt)
+ Anaconda
+ Nix
Commercial tools (optional):
* Spice Simulator

View File

@ -11,7 +11,7 @@ In this section, the detailed usage of using OpenRAM framework will be demonstra
>
> Before you go through, make sure that environment of Sky130 has been already set up.
1. Activate miniconda
1. Enter the Nix devShell
2. Edit the sram configuration file
@ -19,11 +19,11 @@ In this section, the detailed usage of using OpenRAM framework will be demonstra
4. Check the results
#### Activate miniconda
#### Enter Nix devShell
```bash
cd OpenRAM/
source ./miniconda/bin/activate
nix develop
```
#### Modified the sram configuration

27
flake.lock Normal file
View File

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1777270315,
"narHash": "sha256-yKB4G6cKsQsWN7M6rZGk6gkJPDNPIzT05y4qzRyCDlI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6368eda62c9775c38ef7f714b2555a741c20c72d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

48
flake.nix Normal file
View File

@ -0,0 +1,48 @@
{
description = "OpenRAM development environment (Nix)";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs = { self, nixpkgs }:
let
systems = [ "x86_64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
in
{
devShells = forAllSystems (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
default = pkgs.mkShell {
packages = [
# EDA / verification tools
pkgs.klayout
pkgs.magic-vlsi
# Use the LVS-focused netgen package; the generic netgen package
# may require a local build that can fail on some hosts.
pkgs.netgen-vlsi
pkgs.ngspice
pkgs.iverilog
pkgs.xyce
pkgs.xyce-parallel
pkgs.trilinos
pkgs.trilinos-mpi
# Dev conveniences
pkgs.git
pkgs.gnumake
pkgs.curl
];
shellHook = ''
export OPENRAM_USE_CONDA=0
echo "OpenRAM: using tools from Nix devShell"
'';
};
});
};
}

View File

@ -1,46 +0,0 @@
#!/bin/bash
#CONDA_INSTALLER_URL="https://repo.anaconda.com/miniconda/Miniconda3-py313_25.11.1-1-Linux-x86_64.sh"
#CONDA_INSTALLER_FILE="miniconda_installer_py313.sh"
CONDA_INSTALLER_URL="https://repo.anaconda.com/miniconda/Miniconda3-py38_23.11.0-2-Linux-x86_64.sh"
CONDA_INSTALLER_FILE="miniconda_installer_py38.sh"
CONDA_HOME="${CONDA_HOME:-miniconda}"
# The tool name format is "<tool>=<version>".
# If you want to use the latest version, just use "<tool>".
TOOLS=""
TOOLS+="klayout=0.28.3 "
TOOLS+="magic=8.3.587 "
TOOLS+="netgen=1.5.286 "
TOOLS+="ngspice=26 "
TOOLS+="trilinos=12.12.1=1 "
TOOLS+="xyce=7.4"
# Install miniconda if not already installed
if [[ ! -d "${CONDA_HOME}/bin" ]]
then
curl -s -o ${CONDA_INSTALLER_FILE} ${CONDA_INSTALLER_URL}
/bin/bash ${CONDA_INSTALLER_FILE} -b -p ${CONDA_HOME}
rm ${CONDA_INSTALLER_FILE}
source ${CONDA_HOME}/bin/activate
# Prioritize channels to prevent version conflicts
conda config --add channels conda-forge
conda config --add channels vlsida-eda
#conda install -q -y -c conda-forge trilinos
# Install rest of the tools from vlsida-eda
for tool in ${TOOLS}
do
conda install -q -y -c vlsida-eda ${tool}
done
# Install iverilog from conda-eda
conda install -q -y -c litex-hub iverilog
# Install required Python packages
# (This step isn't required but used to prevent possible issues)
python3 -m pip install -r requirements.txt --ignore-installed
conda deactivate
fi

View File

@ -11,7 +11,7 @@ from setuptools import setup, find_namespace_packages
# Include these folder from the root of repo as submodules
include = ["compiler", "docker", "technology", "macros"]
# Exclude files/folders with these words
exclude = ["docs", "images", "miniconda"]
exclude = ["docs", "images"]
# Find all modules inside the 'compiler' folder