|
| 1 | +# Copyright 2026 ETH Zurich and University of Bologna. |
| 2 | +# Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | +# SPDX-License-Identifier: Apache-2.0 |
| 4 | +# |
| 5 | +# Philippe Sauter <phsauter@iis.ee.ethz.ch> |
| 6 | +# |
| 7 | +# |
| 8 | +# Digital design image for CIs and headless use based on iic-osic-tools |
| 9 | +# |
| 10 | +# Includes: |
| 11 | +# EDA tools : yosys (+ eqy/sby/mcy/yices2 + slang plugin), |
| 12 | +# slang (standalone SV linter), verilator, OpenROAD, |
| 13 | +# KLayout, RISC-V GNU toolchain |
| 14 | +# Lint/format: black, flake8, isort, mypy (Python) |
| 15 | +# clang-format (C++) |
| 16 | +# slang --lint-only, verilator --lint-only (SystemVerilog) |
| 17 | +# |
| 18 | +# Uses the iic-osic-tools image on Docker Hub as a build-time source |
| 19 | +# Only the tool directories we need are copied into a fresh |
| 20 | +# ubuntu:noble runtime layer, so the final image contains |
| 21 | +# none of the GUI/VNC/desktop stack and only necessary tools. |
| 22 | +# |
| 23 | +# Runtime apt packages are derived automatically: ldd maps each tool |
| 24 | +# binary's shared-library dependency tree back to dpkg package names. |
| 25 | +# Only interpreters and executables (python3, perl, gcc, …) that the |
| 26 | +# tools spawn at runtime still need to be listed explicitly, |
| 27 | +# as they are not shared libraries and ldd cannot see them. |
| 28 | + |
| 29 | +ARG SOURCE_IMAGE=hpretl/iic-osic-tools:2025.12 |
| 30 | +FROM ${SOURCE_IMAGE} AS source |
| 31 | + |
| 32 | +# Derive the needed apt-managed packages |
| 33 | +# 1. Find all executable files and shared libraries of the EDA tools. |
| 34 | +# 2. Run ldd on every found file to enumerate the full dependency tree |
| 35 | +# (discard errors for non-ELF files such as scripts). |
| 36 | +# 3. Keep only paths under /usr/lib or /lib, these are apt-managed. |
| 37 | +# /usr/local is excluded because we copy those libs separately; |
| 38 | +# /foss is excluded because we copy the tool dirs themselves. |
| 39 | +# 4. Map each .so path back to its owning dpkg package and deduplicate. |
| 40 | +RUN find \ |
| 41 | + /foss/tools/yosys \ |
| 42 | + /foss/tools/slang \ |
| 43 | + /foss/tools/verilator \ |
| 44 | + /foss/tools/openroad \ |
| 45 | + /foss/tools/klayout \ |
| 46 | + /foss/tools/riscv-gnu-toolchain/bin \ |
| 47 | + -type f \( -executable -o -name "*.so*" \) \ |
| 48 | + | xargs ldd 2>/dev/null \ |
| 49 | + | awk '/=>/ { print $3 }' \ |
| 50 | + | grep -E '^/(usr/lib|lib)/' \ |
| 51 | + | sort -u \ |
| 52 | + | xargs dpkg -S 2>/dev/null \ |
| 53 | + | cut -d: -f1 \ |
| 54 | + | sort -u \ |
| 55 | + > /tmp/apt-packages.txt |
| 56 | + |
| 57 | +# Record all pip-installed packages as a constraints file. |
| 58 | +# Used in the final stage with --constraint so that any package we |
| 59 | +# choose to install is pinned to exactly the version from this image. |
| 60 | +RUN pip3 freeze > /tmp/pip-constraints.txt |
| 61 | + |
| 62 | +# Base image: defaults to ubuntu:noble but can be overridden at build time. |
| 63 | +# In CI the base is read from the org.opencontainers.image.base.name label |
| 64 | +# of the source image so this image always tracks the same base as iic-osic-tools. |
| 65 | +ARG BASE_IMAGE=ubuntu:noble |
| 66 | +FROM ${BASE_IMAGE} |
| 67 | + |
| 68 | +ENV DEBIAN_FRONTEND=noninteractive \ |
| 69 | + TZ=Europe/Vienna \ |
| 70 | + LC_ALL=en_US.UTF-8 \ |
| 71 | + LANG=en_US.UTF-8 \ |
| 72 | + TOOLS=/foss/tools \ |
| 73 | + PDK_ROOT=/foss/pdks \ |
| 74 | + DESIGNS=/foss/designs \ |
| 75 | + # Disable the PEP 668 "externally managed environment" restriction. |
| 76 | + # In a container this guard is pointless. |
| 77 | + PIP_BREAK_SYSTEM_PACKAGES=1 |
| 78 | + |
| 79 | +COPY --from=source /tmp/apt-packages.txt /tmp/ |
| 80 | +COPY --from=source /tmp/pip-constraints.txt /tmp/ |
| 81 | + |
| 82 | +RUN apt-get update \ |
| 83 | + # Install the shared-library packages derived from the ldd scan. |
| 84 | + && xargs apt-get install -y --no-install-recommends < /tmp/apt-packages.txt \ |
| 85 | + # Install interpreters and tools that the EDA tools invoke at runtime. |
| 86 | + # These are executables (not shared libraries) so ldd cannot find them. |
| 87 | + && apt-get install -y --no-install-recommends \ |
| 88 | + ca-certificates \ |
| 89 | + locales \ |
| 90 | + tzdata \ |
| 91 | + git \ |
| 92 | + wget \ |
| 93 | + curl \ |
| 94 | + python3 \ |
| 95 | + python3-pip \ |
| 96 | + python3-venv \ |
| 97 | + perl \ |
| 98 | + ruby \ |
| 99 | + ruby-irb \ |
| 100 | + tcl \ |
| 101 | + tcllib \ |
| 102 | + gcc \ |
| 103 | + g++ \ |
| 104 | + make \ |
| 105 | + clang-format \ |
| 106 | + && locale-gen en_US.UTF-8 \ |
| 107 | + && rm -rf /var/lib/apt/lists/* /tmp/apt-packages.txt |
| 108 | + |
| 109 | +# OpenROAD depends on several libraries that are not packaged in Ubuntu |
| 110 | +# and are built from source in the base image. |
| 111 | +COPY --from=source /usr/local/lib /usr/local/lib |
| 112 | +RUN ldconfig |
| 113 | + |
| 114 | +ENV HOME=/headless |
| 115 | +RUN mkdir -p ${TOOLS} ${PDK_ROOT} ${DESIGNS} ${HOME} |
| 116 | + |
| 117 | +# Copy tools from iic-osic-tools to this image |
| 118 | +COPY --from=source ${TOOLS}/yosys ${TOOLS}/yosys/ |
| 119 | +COPY --from=source ${TOOLS}/slang ${TOOLS}/slang/ |
| 120 | +COPY --from=source ${TOOLS}/verilator ${TOOLS}/verilator/ |
| 121 | +COPY --from=source ${TOOLS}/riscv-gnu-toolchain ${TOOLS}/riscv-gnu-toolchain/ |
| 122 | +COPY --from=source ${TOOLS}/openroad ${TOOLS}/openroad/ |
| 123 | +COPY --from=source ${TOOLS}/klayout ${TOOLS}/klayout/ |
| 124 | + |
| 125 | +# Unified bin directory with symlinks to all tools |
| 126 | +COPY --from=source ${TOOLS}/bin ${TOOLS}/bin/ |
| 127 | + |
| 128 | +# profile.d: sourced by login shells |
| 129 | +# sets PATH, PYTHONPATH, LD_LIBRARY_PATH. |
| 130 | +COPY --from=source /etc/profile.d/iic-osic-tools-setup.sh \ |
| 131 | + /etc/profile.d/iic-osic-tools-setup.sh |
| 132 | + |
| 133 | +# .bashrc: sourced by interactive shells — re-exports the same env vars |
| 134 | +# and provides all aliases (ll, gss, k, …) and the custom prompt. |
| 135 | +COPY --from=source ${HOME}/.bashrc ${HOME}/.bashrc |
| 136 | + |
| 137 | +# tool version manifest |
| 138 | +COPY --from=source /tool_metadata.yml /tool_metadata.yml |
| 139 | + |
| 140 | +# Default environment setup |
| 141 | + |
| 142 | +ENV RISCV=${TOOLS}/riscv-gnu-toolchain |
| 143 | +ENV PATH=\ |
| 144 | +${TOOLS}/bin:\ |
| 145 | +${TOOLS}/yosys/bin:\ |
| 146 | +${TOOLS}/slang/bin:\ |
| 147 | +${TOOLS}/verilator/bin:\ |
| 148 | +${TOOLS}/riscv-gnu-toolchain/bin:\ |
| 149 | +${TOOLS}/openroad/bin:\ |
| 150 | +${TOOLS}/klayout:\ |
| 151 | +${PATH} |
| 152 | + |
| 153 | +ENV LD_LIBRARY_PATH=${TOOLS}/klayout |
| 154 | + |
| 155 | +# Python paths: |
| 156 | +# - pyosys: the Yosys Python API lives under the yosys share tree |
| 157 | +# - klayout Python module (pymod) for scripting and DRC/LVS |
| 158 | +ENV PYTHONPATH=${TOOLS}/yosys/share/yosys/python3:${TOOLS}/klayout/pymod |
| 159 | + |
| 160 | +# Python tools (linter and formatter) |
| 161 | +RUN pip3 install --no-cache-dir --constraint /tmp/pip-constraints.txt \ |
| 162 | + black \ |
| 163 | + flake8 \ |
| 164 | + isort \ |
| 165 | + mypy \ |
| 166 | + && rm /tmp/pip-constraints.txt |
| 167 | + |
| 168 | +RUN chown -R 1000:1000 ${HOME} ${DESIGNS} |
| 169 | +USER 1000:1000 |
| 170 | +WORKDIR ${DESIGNS} |
0 commit comments