Skip to content
Snippets Groups Projects
Unverified Commit 14b94a66 authored by Mohamed Gaber's avatar Mohamed Gaber Committed by GitHub
Browse files

Migrate Build System to Match OpenLane 2 (#2115)

+ Repository is now a Nix flake
~ Change all invocations of `openroad -python` to use `run_odbpy_script` for consistency
~ Change build system from ad-hoc to Nix, still producing a Docker image as a final result
~ Update KLayout scripts to use `klayout-pymod` or properly parse commandline arguments
~ `open_pdks` -> `bdc9412` to match OpenLane 2
- Remove local installer; `nix run .` will run OpenLane natively
parent 337ffbf4
No related branches found
No related tags found
No related merge requests found
Showing
with 164 additions and 1101 deletions
......@@ -21,40 +21,33 @@ runs:
using: "composite"
steps:
- uses: actions/checkout@v2
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
- uses: docker/setup-buildx-action@v2
- uses: ./.github/actions/set_env_variables
- name: Check If Going To Push An Image To Docker
shell: bash
run: |
export PUSHING=$(ruby -e 'if ("${{ github.event_name }}" != "pull_request" && "${{ inputs.dockerhub_user }}" != ""); print(1) else print(0) end')
echo "PUSHING=$PUSHING" >> $GITHUB_ENV
- name: Login to DockerHub
if: ${{ env.PUSHING == '1' }}
uses: docker/login-action@v1
with:
username: ${{ inputs.dockerhub_user }}
password: ${{ inputs.dockerhub_password }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- uses: DeterminateSystems/nix-installer-action@main
with:
extra-conf: |
extra-substituters = https://openlane.cachix.org
extra-trusted-public-keys = openlane.cachix.org-1:qqdwh+QMNGmZAuyeQJTH9ErW57OWSvdtuwfBKdS254E=
- name: Docker Build
shell: bash
run: |
export BUILD_IF_CANT_PULL=1
export BUILD_COMMAND="docker build"
if [ "$PUSHING" = "1" ]; then
export BUILD_IF_CANT_PULL_THEN_PUSH=1
export BUILD_COMMAND="docker buildx build --load --cache-from=type=gha --cache-to=type=gha,scope=${{ github.workflow }}}"
fi
export BUILD_ARCH=${{ inputs.arch }}
cd docker/ && make merge
make -C docker
- name: Export Docker Image
shell: bash
run: docker save -o /tmp/image-${{ inputs.arch }}.tar ${{ env.OPENLANE_IMAGE_NAME }}-${{ inputs.arch }}
run: |
docker save -o /tmp/image-${{ inputs.arch }}.tar efabless/openlane:current-${{ inputs.arch }}
- name: Upload Docker Image
uses: actions/upload-artifact@v2
......
......@@ -14,7 +14,3 @@ runs:
- name: Export Branch Name
shell: bash
run: echo "BRANCH_NAME=${GITHUB_REF##*/}" >> $GITHUB_ENV
- name: Export Temp Image Name
shell: bash
run: echo "OPENLANE_IMAGE_NAME=openlane:intermediate" >> $GITHUB_ENV
......@@ -123,10 +123,6 @@ if os.getenv("GITHUB_ACTIONS") != "true":
print('Environment variables required: "PDK_ROOT"')
exit(os.EX_CONFIG)
if os.getenv("OPENLANE_IMAGE_NAME") is None:
print('Environment variables required: "OPENLANE_IMAGE_NAME"')
exit(os.EX_CONFIG)
origin = os.getenv("REPO_URL")
repo = Repo("Openlane", origin)
......@@ -136,7 +132,6 @@ gh = SimpleNamespace(
"run_id": os.getenv("GITHUB_RUN_ID"),
"origin": origin,
"branch": os.getenv("BRANCH_NAME"),
"image": os.getenv("OPENLANE_IMAGE_NAME"),
"root": os.getenv("GITHUB_WORKSPACE"),
"pdk_root": os.getenv("PDK_ROOT"),
"pdk": os.getenv("PDK"),
......
......@@ -53,7 +53,7 @@ docker_command = [
f"PDK_ROOT={gh.pdk_root}",
"-e",
f"PDK={gh.pdk}",
gh.image,
"efabless/openlane:current-amd64",
"bash",
"-c",
shlex.join(
......
......@@ -172,7 +172,9 @@ jobs:
run: python3 -m pip install pyyaml
- name: Run Issue Regression Test
run: cd ${GITHUB_WORKSPACE}/ && make run_issue_regression ISSUE_REGRESSION_DESIGN=${{ matrix.test }}
run: |
OPENLANE_IMAGE_NAME=efabless/openlane:current\
make run_issue_regression ISSUE_REGRESSION_DESIGN=${{ matrix.test }}
- name: Upload Logs
if: ${{ always() }}
......@@ -231,7 +233,7 @@ jobs:
- name: Run Test
run: |
OPENLANE_IMAGE_NAME=$OPENLANE_IMAGE_NAME-amd64\
OPENLANE_IMAGE_NAME=efabless/openlane:current-amd64\
python3 ${GITHUB_WORKSPACE}/.github/scripts/run_tests.py ${{ matrix.design.name }}
- name: Escape Design Name
......@@ -267,6 +269,16 @@ jobs:
with:
fetch-depth: 0
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
- name: Set up environment variables
uses: ./.github/actions/set_env_variables
......@@ -355,7 +367,7 @@ jobs:
run: |
for tag in $TAG_LIST; do
for arch in amd64 arm64v8; do
docker image tag ${{ env.OPENLANE_IMAGE_NAME }}-$arch ${{ vars.DOCKER_IMAGE }}:$tag-$arch
docker image tag efabless/openlane:current-$arch ${{ vars.DOCKER_IMAGE }}:$tag-$arch
docker push ${{ vars.DOCKER_IMAGE }}:$tag-$arch
done
docker manifest create ${{ vars.DOCKER_IMAGE }}:$tag\
......
name: Tool Updater
on:
# Runs every day at midnight UTC
schedule:
- cron: "0 0 * * *"
# Manual Dispatch
workflow_dispatch:
jobs:
create-cid-tools-branches:
runs-on: ubuntu-20.04
strategy:
matrix:
tools: [magic, netgen, yosys, openroad_app, verilator]
steps:
- uses: actions/checkout@v2
with:
ref: ${{ vars.MAIN_BRANCH }}
- name: Set up environment variables
uses: ./.github/actions/set_env_variables
- name: Export TOOL Name
run: echo "TOOL=${{ matrix.tools }}" >> $GITHUB_ENV
- name: Update TOOL
run: cd ${GITHUB_WORKSPACE}/ && python3 ${GITHUB_WORKSPACE}/.github/scripts/update_tools.py ${{ env.TOOL }}
- name: Create Pull Request
if: ${{ env.NO_UPDATE != '1' }}
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.MY_TOKEN }}
title: "[BOT] Update ${{ env.TOOL }}"
author: ${{ vars.BOT_AUTHOR_LINE }}
committer: ${{ vars.BOT_AUTHOR_LINE }}
body: |
This is an automated PR.
See the individual commits for details.
commit-message: |
[BOT] Update ${{ env.TOOL }}
${{ env.TOOL }} -> ${{ env.TOOL_COMMIT_HASH }}
branch: ${{ matrix.tools }}-update-branch
push-to-fork: ${{ vars.FORK_NAME }}
delete-branch: true
create-cid-pdk-branch:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
with:
ref: ${{ vars.MAIN_BRANCH }}
- name: Set up environment variables
uses: ./.github/actions/set_env_variables
- name: Update PDK
run: python3 ${GITHUB_WORKSPACE}/.github/scripts/update_tools.py open_pdks
- name: Create Pull Request
if: ${{ env.NO_UPDATE != '1' }}
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.MY_TOKEN }}
title: "[BOT] Update PDK"
author: ${{ vars.BOT_AUTHOR_LINE }}
committer: ${{ vars.BOT_AUTHOR_LINE }}
body: |
This is an automated PR.
See the individual commits for details.
commit-message: |
[BOT] Update PDK
sky130 -> ${{ env.SKY130_COMMIT_HASH }}
open_pdks -> ${{ env.OPEN_PDKS_COMMIT_HASH }}
base: ${{ env.BRANCH_NAME }}
branch: pdk-update-branch
push-to-fork: ${{ vars.FORK_NAME }}
delete-branch: true
......@@ -54,7 +54,6 @@ FASTEST_TEST_SET_TAG ?= FASTEST_TEST_SET
EXTENDED_TEST_SET_TAG ?= EXTENDED_TEST_SET
PRINT_REM_DESIGNS_TIME ?= 0
SKYWATER_COMMIT ?= $(shell $(PYTHON_BIN) ./dependencies/tool.py sky130 -f commit)
OPEN_PDKS_COMMIT ?= $(shell $(PYTHON_BIN) ./dependencies/tool.py open_pdks -f commit)
export PDK_ROOT ?= $(HOME)/.volare
......@@ -114,8 +113,9 @@ ENV_COMMAND = $(ENV_START) $(OPENLANE_IMAGE_NAME)-$(DOCKER_ARCH)
all: get-openlane pdk
.PHONY: openlane
openlane: venv/created
@PYTHON_BIN=$(PWD)/venv/bin/$(PYTHON_BIN) $(MAKE) -C docker openlane
openlane:
@$(MAKE) -C docker openlane
docker tag efabless/openlane:current-$(DOCKER_ARCH) $(OPENLANE_IMAGE_NAME)-$(DOCKER_ARCH)
.PHONY: openlane-and-push-tools
openlane-and-push-tools: venv/created
......
<h1 align="center">OpenLane</h1>
<p align="center">
<a href="https://colab.research.google.com/github/chipsalliance/silicon-notebooks/blob/main/digital-inverter-openlane.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"></a>
<a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="License: Apache 2.0"/></a>
<img src="https://github.com/efabless/volare/actions/workflows/ci.yml/badge.svg?branch=main" alt="GitHub Actions Status Badge" />
<a href="https://openlane.readthedocs.io/"><img src="https://readthedocs.org/projects/openlane/badge/?version=latest" alt="Documentation Build Status Badge"/></a>
<a href="https://invite.skywater.tools"><img src="https://img.shields.io/badge/Community-Open%20Source%20Silicon%20Slack-ff69b4?logo=slack" alt="Invite to the Open Source Silicon Slack"/></a>
<a href="https://github.com/psf/black"><img src="https://img.shields.io/badge/python%20code%20style-black-000000.svg" alt="Python Code Style: black"/></a>
<a href="https://open-source-silicon.dev"><img src="https://img.shields.io/badge/Community-Open%20Source%20Silicon%20Slack-ff69b4?logo=slack" alt="Invite to the Open Source Silicon Slack"/></a>
<a href="https://nixos.org/"><img src="https://img.shields.io/static/v1?logo=nixos&logoColor=white&label=&message=Built%20with%20Nix&color=41439a" alt="Built with Nix"/></a>
</p>
OpenLane is an automated RTL to GDSII flow based on several components including OpenROAD, Yosys, Magic, Netgen, CVC, SPEF-Extractor, KLayout and a number of custom scripts for design exploration and optimization. The flow performs all ASIC implementation steps from RTL all the way down to GDSII.
......
# Copyright 2024 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
{
lib,
libparse,
stdenv,
python3,
makeWrapper,
ncurses,
coreutils-full,
gnugrep,
gnused,
gnutar,
gzip,
git,
bash,
klayout-pymod,
yosys,
opensta,
openroad,
klayout,
netgen,
magic,
verilog,
verilator,
tclFull,
}:
let
pyenv = (python3.withPackages (ps: with ps; [
libparse
click
pyyaml
XlsxWriter
klayout-pymod
]));
pyenv-sitepackages = "${pyenv}/${pyenv.sitePackages}";
in
stdenv.mkDerivation rec {
name = "openlane1";
src = [
./flow.tcl
./scripts
./configuration
./dependencies
];
unpackPhase = ''
echo $src
for file in $src; do
BASENAME=$(python3 -c "import os; print('$file'.split('-', maxsplit=1)[1], end='$EMPTY')")
cp -r $file $PWD/$BASENAME
done
ls -lah
'';
passthru = {
pyenv = pyenv;
};
includedTools = [
yosys
opensta
openroad
klayout
netgen
magic
verilog
verilator
tclFull
];
propagatedBuildInputs = includedTools ++ [
pyenv
ncurses
coreutils-full
gnugrep
gnused
bash
gnutar
gzip
git
];
nativeBuildInputs = [makeWrapper];
installPhase = ''
mkdir -p $out/bin
cp -r * $out/bin
wrapProgram $out/bin/flow.tcl\
--set PATH ${lib.makeBinPath (propagatedBuildInputs)}\
--set PYTHONPATH ${pyenv-sitepackages}
'';
doCheck = true;
computed_PATH = lib.makeBinPath (propagatedBuildInputs);
meta = with lib; {
description = "RTL-to-GDSII flow for application-specific integrated circuits (ASIC)s";
homepage = "https://efabless.com/openlane";
mainProgram = "flow.tcl";
license = licenses.asl20;
platforms = platforms.linux ++ platforms.darwin;
};
}
https://aur.archlinux.org/tcllib.git
autoconf
bison
cairo
clang
curl
eigen
flex
gawk
gcc
gdb
gettext
git
graphviz
help2man
klayout
libffi
libsm
libx11
make
ncurses
neovim
ninja
patch
pcre2
python
python-pip
readline
spdlog
strace
swig
tcl
tcsh
texinfo
tk
wget
xdot
xorg-server-xvfb
zlib
devtoolset-8
devtoolset-8-libatomic-devel
Xvfb
autoconf
automake
bison
boost169-devel
boost169-static
bzip2
cairo
cairo-devel
clang
csh
curl
flex
gawk
gcc
gdb
gettext
gettext-devel
git
glibc-static
graphviz
help2man
libcurl-devel
libSM
libX11-devel
libXext
libXft
libffi
libffi-devel
libgomp
libjpeg-turbo-devel
libstdc++
libstdc++-static
libxml2-devel
libxslt-devel
make
mesa-libGLU-devel
ncurses-devel
ninja-build
patch
pcre-devel
python36-devel
python36-libs
qt5-qtbase-devel
qt5-qtmultimedia-devel
qt5-qtxmlpatterns-devel
qt5-qtsvg-devel
qt5-qttools-devel
readline-devel
ruby-devel
strace
spdlog-devel
swig3
tcl
tcl-devel
tcl-tclreadline-devel
tcllib
tclx
texinfo
tk
tk-devel
vim-common
wget
which
zlib-devel
zlib-static
https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
centos-release-scl
\ No newline at end of file
alsa-lib
cairo
gdb
gettext
git
libffi
libgomp
libjpeg
libSM
libXcursor
libXext
libXft
libXinerama
libXrandr
libyaml
make
mesa-libGLU
patch
pciutils
pciutils-libs
perl
perl-Switch
python36
python36-pip
python36-tkinter
qt
qt5-qtbase
qt5-qtimageformats
qt5-qtmultimedia
qt5-qtxmlpatterns
qt5-qtsvg
qt5-qttools
qt5-qttools-libs-designer
qt5-qttools-libs-designercomponents
qt5-qttools-libs-help
qt-settings
qt-x11
ruby
rubygem-io-console
rubygem-json
rubygem-psych
rubygem-rdoc
rubygems
ruby-irb
ruby-libs
strace
tcl
tcllib
tcl-tclreadline-devel
tclx
tk
wget
which
Xvfb
zlib
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2022 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Gets a hash of the current dependency set of a certain operating system.
"""
import os
import sys
import glob
import hashlib
__dir__ = os.path.dirname(os.path.abspath(__file__))
def main(argv):
if len(argv) != 2:
print(f"Usage: {argv[0]} <operating system>", file=sys.stderr)
exit(64)
os = argv[1]
if os not in ["macos", "centos-7", "ubuntu-20.04", "arch"]:
print(f"Unknown operating system pick '{os}'.")
exit(64)
files = glob.glob(f"{__dir__}/python/*")
files += glob.glob(f"{__dir__}/{os}/*")
files.sort()
content = ""
for file in files:
content += open(file).read()
hash = hashlib.sha256(content.encode("utf-8")).hexdigest()
print(hash, end="")
if __name__ == "__main__":
main(sys.argv)
#!/usr/bin/env python3
# Copyright 2021 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
import os
import sys
import uuid
import tempfile
import pathlib
import textwrap
import subprocess
from os.path import join, abspath, dirname, exists, realpath
from typing import Tuple, Union, List
openlane_dir = dirname(dirname(abspath(__file__)))
is_root = os.geteuid() == 0
class chdir(object):
def __init__(self, path):
self.path = path
self.previous = None
def __enter__(self):
self.previous = os.getcwd()
os.chdir(self.path)
def __exit__(self, exc_type, exc_value, traceback):
os.chdir(self.previous)
if exc_type is not None:
raise exc_value
def sh(*args: Tuple[str], root: Union[bool, str] = False, **kwargs):
"""
args: shell arguments to run
root:
if False, the command will be executed as-is
if True, if the user is not root, "sudo" will be added to the command
if "retry", the command will be executed as-is first, and if it fails,
it is retried as root.
"""
args = list(args)
if root and not is_root:
args = ["sudo"] + args
try:
subprocess.run(
args,
check=True,
stderr=subprocess.PIPE if root == "retry" else None,
**kwargs,
)
except subprocess.CalledProcessError as e:
if root == "retry":
args = ["sudo"] + args
subprocess.run(args, check=True, **kwargs)
else:
raise e
def download(url: str, ext: str) -> str:
path = f"/tmp/{uuid.uuid4()}.{ext}"
print(f"{url} -> {path}")
target = open(path, "wb")
sh("curl", "-L", url, stdout=target)
target.close()
return path
# Installer Class
class Installer(object):
def __init__(self):
self.envs: List[Tuple[str, str]] = []
def input_options(self, env: str, msg: str, options: List[str]) -> str:
value = None
env_value = os.getenv(env)
if env_value is not None and env_value.lower() in options:
value = env_value
else:
options_pretty = [] + options
options_pretty[0] = f"{options[0].upper()}"
value = input(f"{msg} [{'/'.join(options_pretty)}] > ")
if value == "":
value = options[0]
while value.lower() not in options:
value = input(f"Invalid input {value.lower()}, please retry: ")
value = value.lower()
self.envs.append((env, value))
return value
def input_default(self, env: str, msg: str, default: str) -> str:
value = None
env_value = os.getenv(env)
if env_value is not None:
value = env_value
else:
value = input(f"{msg} [{default}] > ")
if value == "":
value = default
self.envs.append((env, value))
return value
def run(self):
from dependencies.tool import Tool
from dependencies.get_tag import NoGitException, get_tag
from dependencies.env_info import OSInfo
try:
import venv
except ImportError:
print(
"Python venv does not appear to be installed, and is required for local installations.",
file=sys.stderr,
)
try:
ol_version = get_tag()
except NoGitException:
print(
"Installing OpenLane locally requires a Git repository.",
file=sys.stderr,
)
exit(-1)
tools = Tool.from_metadata_yaml(open("./dependencies/tool_metadata.yml").read())
print(
textwrap.dedent(
"""\
OpenLane Local Installer
Copyright 2021-2022 Efabless Corporation. Available under the Apache License,
Version 2.0.
Ctrl+C at any time to quit.
Make sure you read the documentation in ./docs/source/getting_started/installation_local.md
"""
)
)
print(
"[ALERT] The local installer is no longer actively supported.\nSee https://github.com/The-OpenROAD-Project/OpenLane/issues/1300 for more info."
)
install_dir = realpath("./install")
sh("mkdir", "-p", install_dir, root="retry")
home_perms = os.stat(os.getenv("HOME"))
sh(
"chown",
"-R",
"%i:%i" % (home_perms.st_uid, home_perms.st_gid),
install_dir,
root="retry",
)
os_list = ["other", "ubuntu-20.04", "centos-7", "arch", "macos"]
# Try to determine user's OS
def set_default_os(x):
os_list.insert(0, os_list.pop(os_list.index(x)))
os_info = OSInfo.get()
if os_info.distro == "macOS":
set_default_os("macos")
if os_info.distro == "centos" and os_info.distro_version == "7":
set_default_os("centos-7")
if os_info.distro == "ubuntu" and os_info.distro_version == "20.04":
set_default_os("ubuntu-20.04")
if os_info.distro in ["manjaro", "arch"]:
set_default_os("arch")
os_pick = self.input_options(
"OS", "Which UNIX/Unix-like OS are you using?", os_list
)
gcc_bin = os.getenv("CC") or "gcc"
gxx_bin = os.getenv("CXX") or "g++"
try:
if os_pick not in [
"centos-7",
"macos",
]: # The reason we ignore centos 7 and macos is that we're going to just use devtoolset-8/brew gcc anyway.
all_output = ""
try:
gcc_ver_output = subprocess.run(
[gcc_bin, "--version"], stdout=subprocess.PIPE
)
all_output += gcc_ver_output.stdout.decode("utf8")
gx_ver_output = subprocess.run(
[gxx_bin, "--version"], stdout=subprocess.PIPE
)
all_output += gx_ver_output.stdout.decode("utf8")
except Exception:
pass
if "clang" in all_output:
print(
textwrap.dedent(
f"""\
We've detected that you're using Clang as your default C or C++ compiler.
Unfortunately, Clang is not compatible with some of the tools being
installed.
You may continue this installation at your own risk, but we recommend
installing GCC.
You can specify a compiler to use explicitly by invoking this script as
follows, for example:
CC=/usr/local/bin/gcc-8 CXX=/usr/local/bin/g++-8 python3 {__file__}
"""
)
)
input(
"Press return if you understand the risk and wish to continue anyways >"
)
except FileNotFoundError as e:
print(e, "(set as either CC or CXX)")
exit(os.EX_CONFIG)
install_packages = "no"
if os_pick != "other":
install_packages = self.input_options(
"INSTALL_PACKAGES",
"Do you want to install dependencies using your package manager?",
["no", "yes"],
)
if install_packages != "no":
def cat_all(dir):
result = ""
for file in os.listdir(dir):
result += open(join(dir, file)).read()
result += "\n"
return result
if os_pick == "macos":
brew_packages = (
cat_all(join(openlane_dir, "dependencies", "macos"))
.strip()
.split("\n")
)
sh("brew", "install", *brew_packages)
if os_pick == "centos-7":
yum_packages = (
cat_all(join(openlane_dir, "dependencies", "centos-7"))
.strip()
.split("\n")
)
sh("yum", "install", "-y", *yum_packages, root="retry")
if os_pick == "arch":
raw = (
cat_all(join(openlane_dir, "dependencies", "arch"))
.strip()
.split("\n")
)
arch_packages = []
aur_packages = []
for entry in raw:
if entry.strip() == "":
continue
if entry.startswith("https://"):
aur_packages.append(entry)
else:
arch_packages.append(entry)
sh(
"pacman",
"-S",
"--noconfirm",
"--needed",
*arch_packages,
root="retry",
)
temp_dir = tempfile.gettempdir()
oaur_path = os.path.join(temp_dir, "openlane_aur")
pathlib.Path(oaur_path).mkdir(parents=True, exist_ok=True)
with chdir(oaur_path):
for package in aur_packages:
sh("rm", "-rf", "current")
sh("git", "clone", package, "current")
with chdir("current"):
sh("makepkg", "-si", "--noconfirm")
if os_pick == "ubuntu-20.04":
raw = (
cat_all(join(openlane_dir, "dependencies", "ubuntu-20.04"))
.strip()
.split("\n")
)
apt_packages = []
apt_debs = []
for entry in raw:
if entry.strip() == "":
continue
if entry.startswith("https://"):
apt_debs.append(entry)
else:
apt_packages.append(entry)
sh("apt-get", "update", root="retry")
sh("apt-get", "install", "-y", "curl", root="retry")
for deb in apt_debs:
path = download(deb, "deb")
sh("apt-get", "install", "-y", "-f", path, root="retry")
sh("apt-get", "install", "-y", *apt_packages, root="retry")
print("To re-run with the same options: ")
print(f"{' '.join(['%s=%s' % env for env in self.envs])} python3 {__file__}")
run_env = os.environ.copy()
run_env["PREFIX"] = install_dir
run_env["PATH"] = f"{install_dir}/bin:{os.getenv('PATH')}"
path_elements = ["$OL_INSTALL_DIR/venv/bin", "$OL_INSTALL_DIR/bin"]
if os_pick == "centos-7":
run_env["CC"] = "/opt/rh/devtoolset-8/root/usr/bin/gcc"
run_env["CXX"] = "/opt/rh/devtoolset-8/root/usr/bin/g++"
run_env["PATH"] = f"/opt/rh/devtoolset-8/root/usr/bin:{os.getenv('PATH')}"
run_env[
"LD_LIBRARY_PATH"
] = f"/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:/opt/rh/devtoolset-8/root/usr/lib64/dyninst:/opt/rh/devtoolset-8/root/usr/lib/dyninst:/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:{os.getenv('LD_LIBRARY_PATH')}"
run_env[
"CMAKE_INCLUDE_PATH"
] = f"/usr/include/boost169:{os.getenv('CMAKE_INCLUDE_PATH')}"
run_env[
"CMAKE_LIBRARY_PATH"
] = f"/lib64/boost169:{os.getenv('CMAKE_LIBRARY_PATH')}"
elif os_pick == "macos":
def get_prefix(tool):
return (
subprocess.check_output(["brew", "--prefix", tool])
.decode("utf8")
.strip()
)
klayout_app_path = self.input_default(
"KLAYOUT_MAC_APP",
"Please input the path to klayout.app (0.27.3 or later): ",
"/Applications/klayout.app",
)
klayout_path_element = join(klayout_app_path, "Contents", "MacOS")
run_env["CC"] = f"{get_prefix('gcc')}/bin/gcc-11"
run_env["CXX"] = f"{get_prefix('gcc')}/bin/g++-11"
run_env[
"PATH"
] = f"{get_prefix('swig@3')}/bin:{get_prefix('bison')}/bin:{get_prefix('flex')}/bin:{get_prefix('gnu-which')}/bin:{os.getenv('PATH')}"
run_env[
"MAGIC_CONFIG_OPTS"
] = f"--with-tcl={get_prefix('tcl-tk')} --with-tk={get_prefix('tcl-tk')}"
run_env["READLINE_CXXFLAGS"] = f"CXXFLAGS=-L{get_prefix('readline')}/lib"
path_elements.append(f"{klayout_path_element}")
path_elements.append(f"{get_prefix('gnu-sed')}/libexec/gnubin")
path_elements.append(f"{get_prefix('bash')}/bin")
else:
run_env["CC"] = gcc_bin
self.envs.append(("CC", gcc_bin))
run_env["CXX"] = gxx_bin
self.envs.append(("CXX", gxx_bin))
def copy(f):
sh("rm", "-rf", f)
sh("cp", "-r", join(openlane_dir, f), f)
def install():
print("Copying files...")
for folder in ["bin", "lib", "share", "build", "dependencies"]:
sh("mkdir", "-p", folder)
print("Building Python virtual environment...")
venv_builder = venv.EnvBuilder(clear=True, with_pip=True)
venv_builder.create("./venv")
pip_install_cmd = "python3 -m pip install --upgrade"
subprocess.run(
[
"bash",
"-c",
f"""
source ./venv/bin/activate
{pip_install_cmd} -r ../dependencies/python/precompile_time.txt
{pip_install_cmd} -r ../dependencies/python/compile_time.txt
{pip_install_cmd} -r ../dependencies/python/run_time.txt
pip3 install --upgrade volare
mkdir -p ./pdks
volare enable --pdk-root ./pdks {tools['open_pdks'].commit}
""",
]
)
print("Building dependencies...")
with chdir("build"):
for folder in ["repos", "versions"]:
sh("mkdir", "-p", folder)
skip_tools = re.compile(os.getenv("SKIP_TOOLS") or "Unmatchable")
tool_queue = list(tools.values()).copy()
print(tool_queue)
def pop():
return tool_queue.pop(0) if len(tool_queue) else None
installed = set()
tool = pop()
while tool is not None:
if not (tool.in_install and (skip_tools.match(tool.name) is None)):
tool = pop()
continue
# if len(tool.dependencies):
# dependencies = set(tool.dependencies)
# if not dependencies.issubset(installed):
# tool_queue.append(tool)
# tool = pop()
# continue
installed_version = ""
version_path = f"versions/{tool.name}"
try:
installed_version = open(version_path).read()
except Exception:
pass
if (
installed_version == tool.version_string
and os.getenv("FORCE_REINSTALL") != "1"
):
print(f"{tool.version_string} already installed, skipping...")
else:
print(f"Installing {tool.name}...")
with chdir("repos"):
if not exists(tool.name):
sh("git", "clone", tool.repo, tool.name)
with chdir(tool.name):
sh("git", "fetch")
sh("git", "checkout", tool.commit)
sh("git", "submodule", "update", "--init")
subprocess.run(
[
"bash",
"-c",
f"""\
set -e
source {install_dir}/venv/bin/activate
{tool.build_script}
""",
],
env=run_env,
check=True,
)
with open(version_path, "w") as f:
f.write(tool.version_string)
installed.add(tool.name)
tool = pop()
path_elements.reverse()
with open("env.tcl", "w") as f:
f.write(
textwrap.dedent(
f"""\
set OL_INSTALL_DIR [file dirname [file normalize [info script]]]
set ::env(OPENLANE_LOCAL_INSTALL) 1
set ::env(OL_INSTALL_DIR) "$OL_INSTALL_DIR"
set ::env(PATH) "{":".join(path_elements)}:$::env(PATH)"
set ::env(VIRTUAL_ENV) "$OL_INSTALL_DIR/venv"
if {{ ![info exists ::env(PDK_ROOT) ]}} {{
set ::env(PDK_ROOT) "$OL_INSTALL_DIR/pdks"
}}
"""
)
)
with open("installed_version", "w") as f:
f.write(ol_version)
with chdir(install_dir):
install()
print("Done.")
print(
"To invoke Openlane from now on, invoke ./flow.tcl from the OpenLane root without the Makefile."
)
autoconf
automake
bash
bison
boost
bzip2
cairo
curl
eigen
flex
gawk
gcc@11
gdb
gettext
graphviz
libSM
libX11
libXext
libXft
libffi
libjpeg
libomp
libxml2
libxslt
make
mesa-glu
ncurses
ninja
patchutils
pcre
python
readline
spdlog
swig@3
tcl-tk
vim
wget
gnu-which
xdot
zlib
- name: magic
repo: https://github.com/rtimothyedwards/magic
commit: 0afe4d87d4aacfbbb2659129a1858a22d216a920
build: |
./configure --prefix=$PREFIX $MAGIC_CONFIG_OPTS
make clean
make database/database.h
make -j$(nproc)
make install
- name: netgen
repo: https://github.com/rtimothyedwards/netgen
commit: 87d8759a6980d297edcb9be6f8661867e4726f9a
build: |
./configure --prefix=$PREFIX $MAGIC_CONFIG_OPTS
make clean
make -j$(nproc)
make install
- name: padring
repo: https://github.com/donn/padring
commit: b2a64abcc8561d758c0bcb3945117dcb13bd9dca
build: |
bash ./bootstrap.sh
cd build
ninja clean
ninja
cp padring $PREFIX/bin
- name: vlogtoverilog
repo: https://github.com/RTimothyEdwards/qflow
commit: a550469b63e910ede6e3022e2886bca96462c540
build: |
# Note that vlogtoverilog is part of the qflow repository.
./configure
cd src
make clean
make -j$(nproc) vlog2Verilog
cp vlog2Verilog $PREFIX/bin
- name: verilator
repo: https://github.com/verilator/verilator
commit: 67dfa37c560385827218350ea936eb1baf604240
build: |
autoconf
./configure --prefix=$PREFIX
make
make install
- name: yosys
repo: https://github.com/YosysHQ/yosys
commit: 4a1b5599258881f579a2d95274754bcd8fc171bd
build: |
make clean
make PREFIX=$PREFIX config-gcc
make PREFIX=$PREFIX -j$(nproc)
make PREFIX=$PREFIX install
- name: klayout
repo: https://github.com/KLayout/klayout
commit: 44a2aa9ca17c2b1c154f9c410ded063de9ed3e12
in_install: false
- name: openroad_app
repo: https://github.com/The-OpenROAD-Project/OpenROAD
commit: da0053d7b0014ab9c87ea148875ff6c2a0f9b658
in_install: false
- name: git
repo: https://github.com/git/git
commit: e9d7761bb94f20acc98824275e317fa82436c25d
in_install: false
- name: open_pdks
repo: https://github.com/RTimothyEdwards/open_pdks
commit: cd1748bb197f9b7af62a54507de6624e30363943
in_install: false
pdk: true
commit: bdc9412b3e468c102d01b7cf6337be06ec6e9c9a
xvfb
autoconf
autopoint
bison
bzip2
libcairo-dev
clang
csh
curl
flex
gawk
gcc
gdb
gettext
git
graphviz
help2man
libeigen3-dev
libsm-dev
libx11-dev
libffi-dev
libgomp1
libjpeg9-dev
libxml2-dev
libxslt-dev
libffi-dev
libspdlog-dev
make
ncurses-dev
ninja-build
patch
libpcre2-dev
python3
python3-pip
python3-dev
python3-tk
libreadline-dev
strace
swig
tcl-dev
tk-dev
tcllib
tclx8.4-dev
texinfo
neovim
wget
xdot
zlib1g
......@@ -148,90 +148,12 @@ def verify_versions(
print(traceback.format_exc(), file=report_file)
raise Exception("Failed to compare PDKs.")
if not no_tools:
installed = os.getenv("OPENLANE_LOCAL_INSTALL") == "1"
environment_manifest = None
if installed:
# 3a. Compare with installed versions
installed_versions_path = join(
os.environ["OL_INSTALL_DIR"], "build", "versions"
)
environment_manifest = []
for tool in os.listdir(installed_versions_path):
protocol, url, commit = (
open(join(installed_versions_path, tool)).read().split(":")
)
repo = f"{protocol}:{url}"
environment_manifest.append(
{"name": tool, "repo": repo, "commit": commit}
)
else:
# 3b. Compare Container And Installation Manifests
try:
container_manifest_path = join("/", "tool_metadata.yml")
environment_manifest = yaml.safe_load(open(container_manifest_path))
except FileNotFoundError:
raise Exception(
"Container manifest not found. What this likely means is that the container is severely out of date."
)
tool_set_flow = (
set([element["name"] for element in manifest]) - pdk_manifest_names
)
tool_set_container = (
set([element["name"] for element in environment_manifest])
- pdk_manifest_names
)
unmatched_tools_flow = tool_set_flow - tool_set_container
for tool in unmatched_tools_flow:
tool_object = manifest_dict[tool]
if (
tool_object.get("in_container") is not None
and not tool_object["in_container"]
):
continue
if (
installed
and tool_object.get("in_install") is not None
and not tool_object["in_install"]
):
continue
print(
f"Tool {tool} is required by the flow scripts being used, but appears to not be installed in the environment.",
file=report_file,
)
mismatches = True
unmatched_tools_container = tool_set_container - tool_set_flow
for tool in unmatched_tools_container:
print(
f"Tool {tool} is installed in the environment, but has no corresponding entry in the flow scripts.",
file=report_file,
)
mismatches = True
for tool in environment_manifest:
if tool["name"] in pdk_manifest_names:
continue # PDK Stuff Already Checked
flow_script_counterpart = manifest_dict.get(tool["name"])
if flow_script_counterpart is None:
continue
container_commit = tool["commit"]
flow_script_commit = flow_script_counterpart["commit"]
if container_commit != flow_script_commit:
print(
f"The version of {tool['name']} installed in the environment does not match the one required by the OpenLane flow scripts (installed: {container_commit}, expected: {flow_script_commit})",
file=report_file,
)
mismatches = True
return mismatches
if __name__ == "__main__":
try:
no_tools = False
no_tools = True
no_pdks = False
mismatches = sys.argv[1]
if mismatches == "none":
......
......@@ -2,4 +2,10 @@ build/
logs/
*/fetch_submodules_from_tarballs.py
*/utils.py
/base/
\ No newline at end of file
/base/
tar/
/openlane/
ol2_hash
/openlane2
/result
/git_version
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment