1717load ("//verilog:providers.bzl" , "VerilogInfo" )
1818load ("@rules_python//python:defs.bzl" , "PyInfo" )
1919
20+ ## Helpers for parsing arguments
21+
2022def _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+
4852def _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
6872def _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,32 @@ def _cocotb_test_impl(ctx):
123166 test_module_args
124167 )
125168
126- ctx . actions . write ( output = runner_script , content = command )
169+ return command
127170
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 ],
171+ def _cocotb_test_impl (ctx ):
172+ verilog_files = _collect_verilog_files (ctx ).to_list ()
173+ vhdl_files = _collect_vhdl_files (ctx ).to_list ()
174+
175+ # create test script
176+ runner_script = ctx .actions .declare_file ("cocotb_runner.sh" )
177+ ctx .actions .write (
178+ output = runner_script ,
179+ content = _get_test_command (ctx , verilog_files , vhdl_files ),
135180 )
136181
182+ # specify dependencies for the script
137183 runfiles = ctx .runfiles (
138184 files = ctx .files .cocotb_wrapper +
139185 verilog_files +
140186 vhdl_files +
141187 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 ],
188+ transitive_files = _collect_transitive_files (ctx ),
189+ ).merge (
190+ _collect_transitive_runfiles (ctx ),
147191 )
148192
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 }
193+ # specify PYTHONPATH for the script
194+ env = {"PYTHONPATH" : _get_pythonpath_to_set (ctx )}
153195
154196 # return the information about testing script and its dependencies
155197 return [
0 commit comments