Skip to content

Commit fe8d3c2

Browse files
committed
Improve python dependency handling in cocotb_test rule.
The changes introduced in this commit add dependencies of the scripts included in the test_module attribute. Previously if the py_library target was used instead of the python source file, its dependencies were not included in the Bazel sandbox during testing. Internal-tag: [#46586] Signed-off-by: Robert Winkler <[email protected]>
1 parent 297848f commit fe8d3c2

File tree

1 file changed

+73
-33
lines changed

1 file changed

+73
-33
lines changed

cocotb/cocotb.bzl

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
load("//verilog:providers.bzl", "VerilogInfo")
1818
load("@rules_python//python:defs.bzl", "PyInfo")
1919

20+
## Helpers for parsing arguments
21+
2022
def _list_to_argstring(data, argname, attr = None, operation = None):
2123
result = " --{}".format(argname) if data else ""
2224
for value in data:
@@ -45,6 +47,8 @@ def _remove_duplicates_from_list(data):
4547
result.append(e)
4648
return result
4749

50+
# Helpers for collecting information from context
51+
4852
def _collect_verilog_files(ctx):
4953
transitive_srcs_list = [
5054
dep
@@ -59,21 +63,67 @@ def _collect_verilog_files(ctx):
5963
verilog_info_struct.srcs
6064
for verilog_info_struct in transitive_srcs_depset.to_list()
6165
]
62-
verilog_files = depset(
66+
67+
return depset(
6368
[src for sub_tuple in verilog_srcs for src in sub_tuple] +
6469
ctx.files.verilog_sources,
6570
)
66-
return verilog_files.to_list()
6771

6872
def _collect_vhdl_files(ctx):
69-
return ctx.files.vhdl_sources
73+
return depset(direct = ctx.files.vhdl_sources)
7074

71-
def _cocotb_test_impl(ctx):
72-
# prepare arguments for the test command
73-
vhdl_files = _collect_vhdl_files(ctx)
74-
vhdl_sources_args = _files_to_argstring(vhdl_files, "vhdl_sources")
75+
def _collect_python_transitive_imports(ctx):
76+
all_imports = []
77+
for attr in [ctx.attr.deps, ctx.attr.test_module]:
78+
imports = depset(transitive = [
79+
dep[PyInfo].imports
80+
for dep in attr
81+
if PyInfo in dep
82+
])
83+
all_imports.append(imports)
84+
return depset(transitive = all_imports)
85+
86+
def _collect_python_direct_imports(ctx):
87+
return depset(direct = [module.dirname for module in ctx.files.test_module])
88+
89+
def _collect_transitive_files(ctx):
90+
py_toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime
91+
return depset(
92+
direct = [py_toolchain.interpreter],
93+
transitive = [dep[PyInfo].transitive_sources for dep in ctx.attr.deps] +
94+
[dep[PyInfo].transitive_sources for dep in ctx.attr.test_module if PyInfo in dep] +
95+
[ctx.attr.cocotb_wrapper[PyInfo].transitive_sources] +
96+
[py_toolchain.files],
97+
)
98+
99+
def _collect_transitive_runfiles(ctx):
100+
return ctx.runfiles().merge_all(
101+
[dep.default_runfiles for dep in ctx.attr.deps] +
102+
[dep.default_runfiles for dep in ctx.attr.test_module] +
103+
[dep.default_runfiles for dep in ctx.attr.sim],
104+
)
105+
106+
# Helpers for preparing tests script
107+
108+
def _get_pythonpath_to_set(ctx):
109+
direct_imports_list = _collect_python_direct_imports(ctx).to_list()
110+
111+
transitive_imports = _collect_python_transitive_imports(ctx)
112+
prefixed_transitive_imports_list = [
113+
"external/" + path
114+
for path in transitive_imports.to_list()
115+
]
116+
117+
pypath = ":".join(prefixed_transitive_imports_list + direct_imports_list)
118+
return pypath
75119

76-
verilog_files = _collect_verilog_files(ctx)
120+
def _get_path_to_set(ctx):
121+
sim_paths = _remove_duplicates_from_list([dep.label.workspace_root for dep in ctx.attr.sim])
122+
path = ":".join(["$PWD/" + str(p) for p in sim_paths])
123+
return path
124+
125+
def _get_test_command(ctx, verilog_files, vhdl_files):
126+
vhdl_sources_args = _files_to_argstring(vhdl_files, "vhdl_sources")
77127
verilog_sources_args = _files_to_argstring(verilog_files, "verilog_sources")
78128

79129
includes_args = _list_to_argstring(ctx.attr.includes, "includes")
@@ -86,21 +136,14 @@ def _cocotb_test_impl(ctx):
86136

87137
defines_args = _dict_to_argstring(ctx.attr.defines, "defines")
88138
parameters_args = _dict_to_argstring(ctx.attr.parameters, "parameters")
89-
90139
verbose_args = " --verbose" if ctx.attr.verbose else ""
91140
waves_args = " --waves" if ctx.attr.waves else ""
92141
seed_args = " --seed {}".format(ctx.attr.seed) if ctx.attr.seed != "" else ""
93142

94143
test_module_args = _pymodules_to_argstring(ctx.files.test_module, "test_module")
95144

96-
# define a script and a command
97-
runner_script = ctx.actions.declare_file("cocotb_runner.sh")
98-
99-
sim_paths = _remove_duplicates_from_list([dep.label.workspace_root for dep in ctx.attr.sim])
100-
path = ":".join(["$PWD/" + str(p) for p in sim_paths])
101-
102145
command = (
103-
"PATH={}:$PATH ".format(path) +
146+
"PATH={}:$PATH ".format(_get_path_to_set(ctx)) +
104147
"python {}".format(ctx.executable.cocotb_wrapper.short_path) +
105148
" --sim {}".format(ctx.attr.sim_name) +
106149
" --hdl_library {}".format(ctx.attr.hdl_library) +
@@ -123,33 +166,30 @@ def _cocotb_test_impl(ctx):
123166
test_module_args
124167
)
125168

126-
ctx.actions.write(output = runner_script, content = command)
169+
def _cocotb_test_impl(ctx):
170+
verilog_files = _collect_verilog_files(ctx).to_list()
171+
vhdl_files = _collect_vhdl_files(ctx).to_list()
127172

128-
# specify dependencies for the script
129-
py_toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime
130-
transitive_files = depset(
131-
direct = [py_toolchain.interpreter],
132-
transitive = [dep[PyInfo].transitive_sources for dep in ctx.attr.deps] +
133-
[ctx.attr.cocotb_wrapper[PyInfo].transitive_sources] +
134-
[py_toolchain.files],
173+
# create test script
174+
runner_script = ctx.actions.declare_file("cocotb_runner.sh")
175+
ctx.actions.write(
176+
output = runner_script,
177+
content = _get_test_command(ctx, verilog_files, vhdl_files),
135178
)
136179

180+
# specify dependencies for the script
137181
runfiles = ctx.runfiles(
138182
files = ctx.files.cocotb_wrapper +
139183
verilog_files +
140184
vhdl_files +
141185
ctx.files.test_module,
142-
transitive_files = transitive_files,
143-
).merge_all(
144-
[dep.default_runfiles for dep in ctx.attr.deps] +
145-
[dep.default_runfiles for dep in ctx.attr.test_module] +
146-
[dep.default_runfiles for dep in ctx.attr.sim],
186+
transitive_files = _collect_transitive_files(ctx),
187+
).merge(
188+
_collect_transitive_runfiles(ctx),
147189
)
148190

149-
# specify pythonpath for the script
150-
test_module_paths = _remove_duplicates_from_list([module.dirname for module in ctx.files.test_module])
151-
pypath = ":".join([str(p) for p in test_module_paths])
152-
env = {"PYTHONPATH": pypath}
191+
# specify PYTHONPATH for the script
192+
env = {"PYTHONPATH": _get_pythonpath_to_set(ctx)}
153193

154194
# return the information about testing script and its dependencies
155195
return [

0 commit comments

Comments
 (0)