Teach check_tool_requirements to check for edalize versions
This is a patch by @rswarbrick ported from
https://github.com/lowRISC/ibex/pull/774 in order to align the
scripts between Ibex and OT.
Original commit message:
We need this specific edalize version because recent verilators have
got pickier about string parameter passing, breaking the
"MultiplierImplementation" parameter.
As well as teaching check_tool_requirements.py to get the edalize
version from pip3, this patch also does a bit of tidying up, coping
better if tool_requirements.py is missing or malformed.
Original author: Rupert Swarbrick <rswarbrick@lowrisc.org>
Signed-off-by: Philipp Wagner <phw@lowrisc.org>
diff --git a/util/check_tool_requirements.py b/util/check_tool_requirements.py
index 5a59d4c..3c6757d 100755
--- a/util/check_tool_requirements.py
+++ b/util/check_tool_requirements.py
@@ -6,15 +6,50 @@
from distutils.version import StrictVersion
import logging as log
import os
+import re
import subprocess
import sys
# Display INFO log messages and up.
log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")
-# Populate __TOOL_REQUIREMENTS__
-topsrcdir = os.path.join(os.path.dirname(__file__), '..')
-exec(open(os.path.join(topsrcdir, 'tool_requirements.py')).read())
+
+def get_tool_requirements_path():
+ '''Return the path to tool_requirements.py, at the top of the repo'''
+ # top_src_dir is the top of the repository
+ top_src_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),
+ '..'))
+
+ return os.path.join(top_src_dir, 'tool_requirements.py')
+
+
+def read_tool_requirements(path=None):
+ '''Read tool requirements from a Python file'''
+ if path is None:
+ path = get_tool_requirements_path()
+
+ with open(path, 'r') as pyfile:
+ globs = {}
+ exec(pyfile.read(), globs)
+
+ # We expect the exec call to have populated globs with a
+ # __TOOL_REQUIREMENTS__ dictionary.
+ reqs = globs.get('__TOOL_REQUIREMENTS__')
+ if reqs is None:
+ log.error('The Python file at {} did not define '
+ '__TOOL_REQUIREMENTS__.'
+ .format(path))
+ return None
+
+ # reqs should be a dictionary (mapping tool name to minimum version)
+ if not isinstance(reqs, dict):
+ log.error('The Python file at {} defined '
+ '__TOOL_REQUIREMENTS__, but it is not a dict.'
+ .format(path))
+ return None
+
+ return reqs
+
def get_verilator_version():
try:
@@ -32,8 +67,44 @@
log.error(e.stdout)
return None
-def check_version(tool_name, required_version, actual_version):
- if required_version is None or actual_version is None:
+
+def pip3_get_version(tool):
+ '''Run pip3 to find the version of an installed module'''
+ cmd = ['pip3', 'show', tool]
+ try:
+ proc = subprocess.run(cmd,
+ check=True,
+ stderr=subprocess.STDOUT,
+ stdout=subprocess.PIPE,
+ universal_newlines=True)
+ except subprocess.CalledProcessError as err:
+ log.error('pip3 command failed: {}'.format(err))
+ log.error("Failed to get version of {} with pip3: is it installed?"
+ .format(tool))
+ log.error(err.stdout)
+ return None
+
+ version_re = 'Version: (.*)'
+ for line in proc.stdout.splitlines():
+ match = re.match(version_re, line)
+ if match:
+ return match.group(1)
+
+ # If we get here, we never saw a version line.
+ log.error('No output line from running {} started with "Version: ".'
+ .format(cmd))
+ return None
+
+
+def check_version(requirements, tool_name, getter):
+ required_version = requirements.get(tool_name)
+ if required_version is None:
+ log.error('Requirements file does not specify version for {}.'
+ .format(tool_name))
+ return False
+
+ actual_version = getter()
+ if actual_version is None:
return False
if StrictVersion(actual_version) < StrictVersion(required_version):
@@ -47,17 +118,26 @@
def main():
- any_failed = False
+ # Get tool requirements
+ tool_requirements = read_tool_requirements()
+ if tool_requirements is None:
+ return 1
- if not check_version('verilator', __TOOL_REQUIREMENTS__['verilator'],
- get_verilator_version()):
- any_failed = True
+ all_good = True
+ all_good &= check_version(tool_requirements,
+ 'verilator',
+ get_verilator_version)
+ all_good &= check_version(tool_requirements,
+ 'edalize',
+ lambda: pip3_get_version('edalize'))
- if any_failed:
+ if not all_good:
log.error("Tool requirements not fulfilled. "
"Please update the tools and retry.")
return 1
+
return 0
+
if __name__ == "__main__":
sys.exit(main())