blob: 3c6757dadbcdda771574b75b0c48f910299aef9c [file] [log] [blame]
Pirmin Vogeled097cc2020-03-09 11:35:21 +01001#!/usr/bin/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
6from distutils.version import StrictVersion
7import logging as log
8import os
Philipp Wagner82ed76e2020-05-26 11:07:48 +01009import re
Pirmin Vogeled097cc2020-03-09 11:35:21 +010010import subprocess
11import sys
12
13# Display INFO log messages and up.
14log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s")
15
Philipp Wagner82ed76e2020-05-26 11:07:48 +010016
17def get_tool_requirements_path():
18 '''Return the path to tool_requirements.py, at the top of the repo'''
19 # top_src_dir is the top of the repository
20 top_src_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),
21 '..'))
22
23 return os.path.join(top_src_dir, 'tool_requirements.py')
24
25
26def read_tool_requirements(path=None):
27 '''Read tool requirements from a Python file'''
28 if path is None:
29 path = get_tool_requirements_path()
30
31 with open(path, 'r') as pyfile:
32 globs = {}
33 exec(pyfile.read(), globs)
34
35 # We expect the exec call to have populated globs with a
36 # __TOOL_REQUIREMENTS__ dictionary.
37 reqs = globs.get('__TOOL_REQUIREMENTS__')
38 if reqs is None:
39 log.error('The Python file at {} did not define '
40 '__TOOL_REQUIREMENTS__.'
41 .format(path))
42 return None
43
44 # reqs should be a dictionary (mapping tool name to minimum version)
45 if not isinstance(reqs, dict):
46 log.error('The Python file at {} defined '
47 '__TOOL_REQUIREMENTS__, but it is not a dict.'
48 .format(path))
49 return None
50
51 return reqs
52
Pirmin Vogeled097cc2020-03-09 11:35:21 +010053
54def get_verilator_version():
55 try:
56 # Note: "verilator" needs to be called through a shell and with all
57 # arguments in a string, as it doesn't have a shebang, but instead
58 # relies on perl magic to parse command line arguments.
59 version_str = subprocess.run('verilator --version', shell=True,
60 check=True, stdout=subprocess.PIPE,
61 stderr=subprocess.STDOUT,
62 universal_newlines=True)
63 return version_str.stdout.split(' ')[1].strip()
64
65 except subprocess.CalledProcessError as e:
66 log.error("Unable to call Verilator to check version: " + str(e))
67 log.error(e.stdout)
68 return None
69
Philipp Wagner82ed76e2020-05-26 11:07:48 +010070
71def pip3_get_version(tool):
72 '''Run pip3 to find the version of an installed module'''
73 cmd = ['pip3', 'show', tool]
74 try:
75 proc = subprocess.run(cmd,
76 check=True,
77 stderr=subprocess.STDOUT,
78 stdout=subprocess.PIPE,
79 universal_newlines=True)
80 except subprocess.CalledProcessError as err:
81 log.error('pip3 command failed: {}'.format(err))
82 log.error("Failed to get version of {} with pip3: is it installed?"
83 .format(tool))
84 log.error(err.stdout)
85 return None
86
87 version_re = 'Version: (.*)'
88 for line in proc.stdout.splitlines():
89 match = re.match(version_re, line)
90 if match:
91 return match.group(1)
92
93 # If we get here, we never saw a version line.
94 log.error('No output line from running {} started with "Version: ".'
95 .format(cmd))
96 return None
97
98
99def check_version(requirements, tool_name, getter):
100 required_version = requirements.get(tool_name)
101 if required_version is None:
102 log.error('Requirements file does not specify version for {}.'
103 .format(tool_name))
104 return False
105
106 actual_version = getter()
107 if actual_version is None:
Pirmin Vogeled097cc2020-03-09 11:35:21 +0100108 return False
109
110 if StrictVersion(actual_version) < StrictVersion(required_version):
111 log.error("%s is too old: found version %s, need at least %s",
112 tool_name, actual_version, required_version)
113 return False
114 else:
115 log.info("Found sufficiently recent version of %s (found %s, need %s)",
116 tool_name, actual_version, required_version)
117 return True
118
119
120def main():
Philipp Wagner82ed76e2020-05-26 11:07:48 +0100121 # Get tool requirements
122 tool_requirements = read_tool_requirements()
123 if tool_requirements is None:
124 return 1
Pirmin Vogeled097cc2020-03-09 11:35:21 +0100125
Philipp Wagner82ed76e2020-05-26 11:07:48 +0100126 all_good = True
127 all_good &= check_version(tool_requirements,
128 'verilator',
129 get_verilator_version)
130 all_good &= check_version(tool_requirements,
131 'edalize',
132 lambda: pip3_get_version('edalize'))
Pirmin Vogeled097cc2020-03-09 11:35:21 +0100133
Philipp Wagner82ed76e2020-05-26 11:07:48 +0100134 if not all_good:
Pirmin Vogeled097cc2020-03-09 11:35:21 +0100135 log.error("Tool requirements not fulfilled. "
136 "Please update the tools and retry.")
137 return 1
Philipp Wagner82ed76e2020-05-26 11:07:48 +0100138
Pirmin Vogeled097cc2020-03-09 11:35:21 +0100139 return 0
140
Philipp Wagner82ed76e2020-05-26 11:07:48 +0100141
Pirmin Vogeled097cc2020-03-09 11:35:21 +0100142if __name__ == "__main__":
143 sys.exit(main())