Skip to content

Commit 3df5bee

Browse files
committed
Updated Verilator to not reply on system python
1 parent 33c4b6f commit 3df5bee

File tree

9 files changed

+388
-47
lines changed

9 files changed

+388
-47
lines changed

.bazelrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,14 @@ test:ciremotebuild --tls_client_certificate=/root/.ssh/buildbuddy-cert.pem
3737
test:ciremotebuild --tls_client_key=/root/.ssh/buildbuddy-key.pem
3838
test:ciremotebuild --build_metadata=VISIBILITY=PUBLIC
3939
test:ciremotebuild --remote_timeout=3600
40+
41+
###############################################################################
42+
## User flags
43+
###############################################################################
44+
# Optionally allow users to define custom flags when developing new features.
45+
# https://bazel.build/configure/best-practices#bazelrc-file
46+
#
47+
# Note: This line should always be last in this file to ensure consistent behavior
48+
# with flags defined in this file.
49+
#
50+
try-import %workspace$/user.bazelrc

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
bazel-*/
22
bazel-*
3+
user.bazelrc
34
MODULE.bazel
45
MODULE.bazel.lock
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
load("@rules_python//python:defs.bzl", "py_binary")
2+
3+
py_binary(
4+
name = "verilator_astgen",
5+
srcs = ["verilator_astgen.py"],
6+
visibility = ["@verilator//:__pkg__"],
7+
)
8+
9+
py_binary(
10+
name = "verilator_flexfix",
11+
srcs = ["verilator_flexfix.py"],
12+
visibility = ["@verilator//:__pkg__"],
13+
)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""A process wrapper for running Verilator's astgen tool in a Bazel action."""
2+
3+
import argparse
4+
import shutil
5+
import subprocess
6+
import sys
7+
from pathlib import Path
8+
9+
10+
def parse_args() -> argparse.Namespace:
11+
"""Parse command line arguments"""
12+
parser = argparse.ArgumentParser()
13+
14+
parser.add_argument(
15+
"--src",
16+
dest="srcs",
17+
type=Path,
18+
action="append",
19+
required=True,
20+
help="Sources that need to appear in include paths.",
21+
)
22+
23+
parser.add_argument(
24+
"--out",
25+
dest="outputs",
26+
type=Path,
27+
action="append",
28+
required=True,
29+
help="The expected output files.",
30+
)
31+
32+
parser.add_argument(
33+
"--astgen", type=Path, required=True, help="The path to the astgen tool."
34+
)
35+
36+
parser.add_argument(
37+
"astgen_args",
38+
nargs="*",
39+
help="Remaining args to forward to astgen.",
40+
)
41+
42+
return parser.parse_args()
43+
44+
45+
def main() -> None:
46+
"""The main entrypoint"""
47+
args = parse_args()
48+
49+
includes = []
50+
for parent in set(path.parent for path in args.srcs):
51+
includes.extend(["-I", str(parent)])
52+
53+
result = subprocess.run(
54+
[sys.executable, str(args.astgen)] + includes + args.astgen_args,
55+
check=False,
56+
stderr=subprocess.STDOUT,
57+
stdout=subprocess.PIPE,
58+
encoding="utf-8",
59+
)
60+
61+
if result.returncode:
62+
print(result.stdout, file=sys.stderr)
63+
sys.exit(result.returncode)
64+
65+
for out in args.outputs:
66+
shutil.copyfile(out.name, out)
67+
68+
69+
if __name__ == "__main__":
70+
main()
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""A process wrapper for running Verilator's flexfix tool in a Bazel action."""
2+
3+
import argparse
4+
import subprocess
5+
import sys
6+
from pathlib import Path
7+
8+
9+
def parse_args() -> argparse.Namespace:
10+
"""Parse command line arguments"""
11+
parser = argparse.ArgumentParser()
12+
13+
parser.add_argument(
14+
"--flexfix",
15+
type=Path,
16+
required=True,
17+
help="The path to `flexfix`.",
18+
)
19+
20+
parser.add_argument(
21+
"--src",
22+
type=Path,
23+
required=True,
24+
help="The input source file to pass to `flexfix`",
25+
)
26+
27+
parser.add_argument(
28+
"--output",
29+
type=Path,
30+
required=True,
31+
help="The path to the output file the action must produce.",
32+
)
33+
34+
parser.add_argument(
35+
dest="flexfix_args",
36+
nargs="*",
37+
help="Additional args to be passed to `flexfix`.",
38+
)
39+
40+
return parser.parse_args()
41+
42+
43+
def main() -> None:
44+
"""The main entrypoint"""
45+
args = parse_args()
46+
47+
with args.src.open() as handle:
48+
result = subprocess.run(
49+
[sys.executable, args.flexfix] + args.flexfix_args,
50+
stdin=handle,
51+
check=False,
52+
stderr=subprocess.STDOUT,
53+
stdout=subprocess.PIPE,
54+
encoding="utf-8",
55+
)
56+
57+
if result.returncode:
58+
print(result.stdout, file=sys.stderr)
59+
sys.exit(result.returncode)
60+
61+
args.output.write_text(result.stdout, encoding="utf-8")
62+
63+
64+
if __name__ == "__main__":
65+
main()
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
"""Utility rules used to compile Verilator"""
2+
3+
def _verilator_astgen_impl(ctx):
4+
args = ctx.actions.args()
5+
args.add("--astgen", ctx.file.astgen)
6+
args.add_all(ctx.files.srcs, format_each = "--src=%s")
7+
args.add_all(ctx.outputs.outs, format_each = "--out=%s")
8+
args.add("--")
9+
args.add_all(ctx.attr.args)
10+
11+
ctx.actions.run(
12+
executable = ctx.executable._process_wrapper,
13+
mnemonic = "VerilatorASTgen",
14+
arguments = [args],
15+
inputs = ctx.files.srcs,
16+
outputs = ctx.outputs.outs,
17+
tools = [ctx.file.astgen],
18+
)
19+
20+
return [DefaultInfo(
21+
files = depset(ctx.outputs.outs),
22+
)]
23+
24+
verilator_astgen = rule(
25+
doc = "Run Verilator's `astgen` tool and collect the requested outputs.",
26+
implementation = _verilator_astgen_impl,
27+
attrs = {
28+
"args": attr.string_list(
29+
doc = "The command line arugments for `astgen`.",
30+
),
31+
"astgen": attr.label(
32+
doc = "The path to the `astgen` tool.",
33+
allow_single_file = True,
34+
mandatory = True,
35+
),
36+
"outs": attr.output_list(
37+
doc = "The output sources generated by `astgen`.",
38+
allow_empty = False,
39+
mandatory = True,
40+
),
41+
"srcs": attr.label_list(
42+
doc = "Input sources for `astgen`.",
43+
allow_files = True,
44+
),
45+
"_process_wrapper": attr.label(
46+
cfg = "exec",
47+
executable = True,
48+
default = Label("//dependency_support/verilator/private:verilator_astgen"),
49+
),
50+
},
51+
)
52+
53+
def _is_expandable(value):
54+
for prefix in ("$(execpath", "$(location"):
55+
if prefix in value:
56+
return True
57+
58+
return False
59+
60+
def _verilator_bisonpre_impl(ctx):
61+
data = [ctx.attr.bisonpre] + ctx.attr.srcs + ctx.attr.tools
62+
args = [
63+
ctx.expand_location(a, data) if _is_expandable(a) else a
64+
for a in ctx.attr.args
65+
]
66+
envs = {
67+
# Expand $(location) / $(locations) in the values.
68+
k: ctx.expand_location(v, data) if _is_expandable(v) else v
69+
for k, v in ctx.attr.env.items()
70+
}
71+
ctx.actions.run(
72+
outputs = ctx.outputs.outs,
73+
inputs = ctx.files.srcs,
74+
tools = [ctx.executable.bisonpre] + ctx.files.tools,
75+
executable = ctx.executable.bisonpre,
76+
arguments = args,
77+
mnemonic = "VerilatorBisonPre",
78+
use_default_shell_env = False,
79+
env = envs,
80+
)
81+
return DefaultInfo(
82+
files = depset(ctx.outputs.outs),
83+
runfiles = ctx.runfiles(files = ctx.outputs.outs),
84+
)
85+
86+
verilator_bisonpre = rule(
87+
doc = "Run Verilator's `bisonpre` tool and collect the requested outputs.",
88+
implementation = _verilator_bisonpre_impl,
89+
attrs = {
90+
"args": attr.string_list(
91+
doc = "Command line arguments of the `bisonpre`",
92+
),
93+
"bisonpre": attr.label(
94+
doc = "The path to the `bisonpre` tool.",
95+
executable = True,
96+
mandatory = True,
97+
cfg = "exec",
98+
),
99+
"env": attr.string_dict(
100+
doc = "Environment variables of the action.",
101+
),
102+
"outs": attr.output_list(
103+
mandatory = True,
104+
doc = "Output files generated by the action.",
105+
),
106+
"srcs": attr.label_list(
107+
allow_files = True,
108+
doc = "Additional inputs of the action.",
109+
),
110+
"tools": attr.label_list(
111+
allow_files = True,
112+
cfg = "exec",
113+
doc = "Additional tools of the action.",
114+
),
115+
},
116+
)
117+
118+
def _verilator_flexfix_impl(ctx):
119+
args = ctx.actions.args()
120+
args.add("--flexfix", ctx.file.flexfix)
121+
args.add("--src", ctx.file.src)
122+
args.add("--output", ctx.outputs.out)
123+
args.add("--")
124+
args.add_all(ctx.attr.args)
125+
126+
ctx.actions.run(
127+
executable = ctx.executable._process_wrapper,
128+
mnemonic = "VerilatorFlexFix",
129+
outputs = [ctx.outputs.out],
130+
inputs = [ctx.file.src],
131+
tools = [ctx.file.flexfix],
132+
arguments = [args],
133+
)
134+
135+
return [DefaultInfo(
136+
files = depset([ctx.outputs.out]),
137+
)]
138+
139+
verilator_flexfix = rule(
140+
doc = "Run Verilator's `flexfix` tool and collect the requested outputs.",
141+
implementation = _verilator_flexfix_impl,
142+
attrs = {
143+
"args": attr.string_list(
144+
doc = "The command line arugments for `flexfix`.",
145+
),
146+
"flexfix": attr.label(
147+
doc = "The path to the `flexfix` tool.",
148+
cfg = "exec",
149+
allow_single_file = True,
150+
mandatory = True,
151+
),
152+
"out": attr.output(
153+
doc = "The output source generated by `flexfix`.",
154+
mandatory = True,
155+
),
156+
"src": attr.label(
157+
doc = "The source file to pass to `flexfix`.",
158+
mandatory = True,
159+
allow_single_file = True,
160+
),
161+
"_process_wrapper": attr.label(
162+
cfg = "exec",
163+
executable = True,
164+
default = Label("//dependency_support/verilator/private:verilator_flexfix"),
165+
),
166+
},
167+
)

0 commit comments

Comments
 (0)