Skip to content

Commit f558693

Browse files
authored
add cfg5_ccinfo_rule
Cfg5 ccinfo rule
2 parents f055c17 + d52d481 commit f558693

File tree

7 files changed

+373
-2
lines changed

7 files changed

+373
-2
lines changed

MODULE.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bazel_dep(name = "ape", version = "1.0.0-beta.13")
2+
bazel_dep(name = "rules_dotnet", version = "0.17.5")
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ toolchain_type(
3636

3737
bzl_library(
3838
name = "rules",
39-
srcs = ["rules.bzl"],
39+
srcs = ["rules.bzl", "generate_cc.bzl"],
4040
visibility = ["//visibility:public"],
4141
deps = ["//rules/common:create_davinci_tool_workspace"],
4242
)

rules/cfg5/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,35 @@ Wraps the cfg5_generate_vtt_workspace with the private_is_windows select stateme
152152
A cfg5_generate_vtt_workspace_def rule that contains the actual implementation
153153

154154

155+
## cfg5_generate_rt_workspace_cc
156+
157+
Generates the DaVinciConfigurator 5 config and return a CcInfo containing all generated source files. This means that no output files need to be defined in the target.
158+
159+
Usage in `BUILD.bazel` file:
160+
161+
<pre>
162+
load("@//rules:defs.bzl", "cfg5_generate_rt_workspace_cc")
163+
164+
cfg5_generate_rt_workspace_cc(<a href="#cfg5_generate_rt_workspace_cc-name">name</a>, <a href="#cfg5_generate_rt_workspace_cc-kwargs">kwargs</a>)
165+
</pre>
166+
167+
Wraps the cfg5_generate_rt_workspace_cc with the private_is_windows select statement in place
168+
169+
170+
**ATTRIBUTES**
171+
172+
173+
| Name | Description | Default Value |
174+
| :------------- | :------------- | :------------- |
175+
| <a id="cfg5_generate_rt_workspace_cc-name"></a>name | The unique name of this target | none |
176+
| <a id="cfg5_generate_rt_workspace_cc-kwargs"></a>kwargs | All of the attrs of the cfg5_generate_rt_workspace_cc rule | none |
177+
178+
179+
**RETURNS**
180+
181+
A cfg5_generate_rt_workspace_cc_def rule that contains the actual implementation
182+
183+
155184
# Example usage
156185
The following showcases an example on how to use a rule and toolchain in your Bazel project environment.
157186

rules/cfg5/generate_cc.bzl

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
# MIT License
2+
3+
# Copyright (c) 2025 Vector Group
4+
5+
# Permission is hereby granted, free of charge, to any person obtaining
6+
# a copy of this software and associated documentation files (the
7+
# "Software"), to deal in the Software without restriction, including
8+
# without limitation the rights to use, copy, modify, merge, publish,
9+
# distribute, sublicense, and/or sell copies of the Software, and to
10+
# permit persons to whom the Software is furnished to do so, subject to
11+
# the following conditions:
12+
13+
# The above copyright notice and this permission notice shall be
14+
# included in all copies or substantial portions of the Software.
15+
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
24+
"""Rule to generate DaVinciConfigurator 5 config from Bazel and return CcInfo"""
25+
26+
load("//rules/common:create_davinci_tool_workspace.bzl", "create_davinci_tool_workspace")
27+
# load("//rules/vtt:toolchains.bzl", "generate_tools_vtt")
28+
29+
_CFG5_GENERATE_TEMPLATE_WINDOWS_WORKSPACE = """
30+
$folderPath = '{dpa_folder}'
31+
Get-ChildItem -Path $folderPath -Recurse -File | ForEach-Object {{ $_.IsReadOnly = $false; $_.Attributes = 'Normal'}}
32+
start-process -WorkingDirectory {dpa_folder} -PassThru -NoNewWindow -RedirectStandardOutput {dpa_folder}/daVinciCfg5.log -Wait {cfg5cli_path} -ArgumentList '-p {dpa_path} -g {genargs} --verbose'
33+
"""
34+
35+
_CFG5_GENERATE_TEMPLATE_LINUX_WORKSPACE = """
36+
sudo chmod -R 777 {dpa_folder} &&
37+
{cfg5cli_path} -p {dpa_folder}/{dpa_path} -g {genargs} --verbose > {dpa_folder}/daVinciCfg5.log
38+
"""
39+
40+
EXCLUDED_FILES_GENERIC = ["*.json*", "*.sha512*", "*.rc*", "*.mak*", "*.ORT*", "*.html*", "*.oil*", "*.checksum*", "*.arxml*", "*.versioncollection*", "*.xml*", "*.lsl*", "*.executionResult*"]
41+
EXCLUDED_FILES_VTT = ["vLinkGen_Lcfg.c", "vBrs_Lcfg.c", "BrsTccCfg.h"]
42+
GEN_ARG_VTT = "--genType=VTT"
43+
GEN_ARG_RT = "--genType=REAL"
44+
45+
_FILTER_CMD_LINUX = """
46+
set -e -o pipefail
47+
48+
# Filter generated files to include only needed files
49+
mkdir -p "{headers_dir}"
50+
mkdir -p "{sources_dir}"
51+
52+
{rsync_exe} --log-file="{rsync_log_file_srcs}" --verbose --prune-empty-dirs --archive --itemize-changes --quiet {excluded_files_patterns} --filter "- **/*.h" {generator_output_dir} {sources_dir}
53+
{rsync_exe} --log-file="{rsync_log_file_hdrs}" --verbose --prune-empty-dirs --archive --itemize-changes --quiet {excluded_files_patterns} --filter "- **/*.c" {generator_output_dir} {headers_dir}
54+
"""
55+
56+
_FILTER_CMD_WINDOWS = """
57+
$ErrorActionPreference = 'Stop'
58+
$PSNativeCommandUseErrorActionPreference = $true
59+
60+
try {{
61+
62+
# List of files to ignore
63+
$ignoreList = @({excluded_files})
64+
65+
# Function to check if a file is in the ignore list
66+
function ShouldIgnore {{
67+
param (
68+
[string]$fileName
69+
)
70+
return $ignoreList -contains $fileName
71+
}}
72+
73+
# Create destination folders if they don't exist
74+
if (-not (Test-Path -Path {sources_dir})) {{
75+
New-Item -ItemType Directory -Path {sources_dir}
76+
}}
77+
78+
if (-not (Test-Path -Path {headers_dir})) {{
79+
New-Item -ItemType Directory -Path {headers_dir}
80+
}}
81+
82+
# Move .c and .h files to respective folders
83+
Get-ChildItem -Path {generator_output_dir} -Filter *.c -Recurse | ForEach-Object {{
84+
if (-not (ShouldIgnore -fileName $_.Name)) {{
85+
Move-Item -Path $_.FullName -Destination {sources_dir}
86+
}}
87+
}}
88+
89+
Get-ChildItem -Path {generator_output_dir} -Filter *.h -Recurse | ForEach-Object {{
90+
if (-not (ShouldIgnore -fileName $_.Name)) {{
91+
Move-Item -Path $_.FullName -Destination {headers_dir}
92+
}}
93+
}}
94+
95+
Write-Output "Files have been moved successfully."
96+
}} catch {{
97+
Write-Error "An error occurred: $_"
98+
exit 1
99+
}}
100+
"""
101+
102+
def _cfg5_generate_cc(ctx, dpa_path, dpa_folder, inputs, template, additional_genargs, tools = []):
103+
info = ctx.toolchains["//rules/cfg5:toolchain_type"]
104+
105+
dvcfg5_report_file_name = "DVCfg5ReportFile.xml"
106+
dvcfg5_report_file = ctx.actions.declare_file(ctx.label.name + "/" + dvcfg5_report_file_name)
107+
108+
# Using the gen args to parse the gen_type to use the correct filtering for vtt and rt
109+
# Currently this rule is limited by ONE generation output per vtt and rt as the root level output directory is used
110+
gen_type = GEN_ARG_RT if GEN_ARG_RT in additional_genargs else GEN_ARG_VTT
111+
gen_dir = "GenDataVtt" if gen_type == GEN_ARG_VTT else "GenData"
112+
113+
excluded_files_patterns = EXCLUDED_FILES_GENERIC + EXCLUDED_FILES_VTT if gen_type == GEN_ARG_VTT else EXCLUDED_FILES_GENERIC + ctx.attr.excluded_files
114+
excluded_files_patterns_string = "--filter \"- **/" + "\" --filter \"- **/".join(excluded_files_patterns) + "\""
115+
116+
if "/" in dpa_folder:
117+
dvcfg5_log_file_name = dpa_folder.split("/")[-1] + "/daVinciCfg5.log"
118+
else:
119+
dvcfg5_log_file_name = dpa_folder + "/daVinciCfg5.log"
120+
dvcfg5_log_file = ctx.actions.declare_file(dvcfg5_log_file_name)
121+
122+
dvcfg5_output_dir = ctx.actions.declare_directory(gen_dir)
123+
124+
sources_dir = ctx.actions.declare_directory(ctx.label.name + "/generated_sources")
125+
headers_dir = ctx.actions.declare_directory(ctx.label.name + "/generated_headers")
126+
generate_tools = list(tools)
127+
128+
# TODO Remove for later versions - Check only for backwards compatibility, as the cfg5_files are only for hermitic execution
129+
if info.cfg5_files:
130+
generate_tools.extend(info.cfg5_files)
131+
else:
132+
generate_tools.append(info.cfg5cli_path)
133+
134+
if ctx.attr.private_is_windows:
135+
# For Windows we have to hack the path to the dvcfg5_report_file, because we switch the working directory to the dpa_folder when executing DVCfg5.
136+
# This leads to the problem that the tool saves the report on the wrong place because the output path is relative.
137+
report_file_path = "../" + ctx.label.name + "/" + dvcfg5_report_file.basename
138+
command = template.format(
139+
dpa_path = dpa_path,
140+
dpa_folder = dpa_folder,
141+
cfg5cli_path = info.cfg5cli_path.path,
142+
genargs = " ".join(ctx.attr.genArgs + ["--reportFile=" + report_file_path, "--reportArgs=CreateXmlFile"] + additional_genargs),
143+
)
144+
145+
ctx.actions.run(
146+
mnemonic = "cfg5generate",
147+
executable = "powershell.exe",
148+
tools = generate_tools,
149+
inputs = inputs,
150+
outputs = [dvcfg5_output_dir] + [dvcfg5_report_file, dvcfg5_log_file],
151+
arguments = ["-NoProfile", command],
152+
env = {"OS": "Windows_NT", "windir": "C:\\Windows", "SystemRoot": "C:\\Windows"},
153+
)
154+
155+
filter_cmd_windows = _FILTER_CMD_WINDOWS.format(
156+
generator_output_dir = dvcfg5_output_dir.path,
157+
sources_dir = sources_dir.path,
158+
headers_dir = headers_dir.path,
159+
excluded_files = '"' + '","'.join(EXCLUDED_FILES_VTT) + '"' if gen_type == GEN_ARG_VTT else "",
160+
)
161+
162+
filter_files_powershell_script_file = ctx.actions.declare_file("filter_files.ps1")
163+
ctx.actions.write(
164+
output = filter_files_powershell_script_file,
165+
content = filter_cmd_windows,
166+
is_executable = True,
167+
)
168+
169+
ctx.actions.run(
170+
mnemonic = "cfg5FileFiltering",
171+
executable = "powershell.exe",
172+
inputs = depset([dvcfg5_output_dir]),
173+
tools = depset([filter_files_powershell_script_file]),
174+
outputs = [sources_dir, headers_dir],
175+
arguments = ["-NoProfile", "-NonInteractive", "-WindowStyle", "Hidden", "-File", filter_files_powershell_script_file.path],
176+
)
177+
compilation_context = cc_common.create_compilation_context(
178+
headers = depset(
179+
[headers_dir],
180+
),
181+
includes = depset(
182+
[
183+
headers_dir.path,
184+
],
185+
),
186+
)
187+
188+
else:
189+
command = template.format(
190+
dpa_path = dpa_path,
191+
dpa_folder = dpa_folder,
192+
cfg5cli_path = info.cfg5cli_path.path,
193+
genargs = " ".join(ctx.attr.genArgs + ["--reportFile=" + dvcfg5_report_file.path, "--reportArgs=CreateXmlFile"] + additional_genargs),
194+
)
195+
196+
ctx.actions.run_shell(
197+
mnemonic = "cfg5generate",
198+
tools = generate_tools,
199+
inputs = inputs,
200+
outputs = [dvcfg5_output_dir] + [dvcfg5_report_file, dvcfg5_log_file],
201+
command = command,
202+
)
203+
204+
rsync_log_file_srcs = ctx.actions.declare_file("file_filter_srcs.log")
205+
rsync_log_file_hrds = ctx.actions.declare_file("file_filter_hrds.log")
206+
207+
filter_cmd_linux = _FILTER_CMD_LINUX.format(
208+
generator_output_dir = dvcfg5_output_dir.path,
209+
sources_dir = sources_dir.path,
210+
headers_dir = headers_dir.path,
211+
rsync_exe = ctx.executable.rsync.path,
212+
excluded_files_patterns = excluded_files_patterns_string,
213+
rsync_log_file_srcs = rsync_log_file_srcs.path,
214+
rsync_log_file_hdrs = rsync_log_file_hrds.path,
215+
)
216+
217+
ctx.actions.run_shell(
218+
inputs = depset([dvcfg5_output_dir] + [ctx.executable.rsync]),
219+
outputs = [sources_dir, headers_dir] + [rsync_log_file_srcs, rsync_log_file_hrds],
220+
progress_message = "Filtering files",
221+
command = filter_cmd_linux,
222+
)
223+
224+
compilation_context = cc_common.create_compilation_context(
225+
headers = depset(
226+
[headers_dir],
227+
),
228+
includes = depset(
229+
[
230+
headers_dir.path + "/" + gen_dir,
231+
headers_dir.path + "/" + gen_dir + "/Components",
232+
],
233+
),
234+
)
235+
236+
return [
237+
DefaultInfo(files = depset([sources_dir] + [headers_dir] + [dvcfg5_report_file, dvcfg5_log_file])),
238+
CcInfo(compilation_context = compilation_context),
239+
]
240+
241+
def _cfg5_generate_workspace_cc_impl(ctx, additional_genargs, tools = []):
242+
_cfg_workspace = create_davinci_tool_workspace(ctx, workspace_name = ctx.label.name + "_cfg_workspace", addtional_workspace_files = [ctx.file.dpa_file], is_windows = ctx.attr.private_is_windows, config_files = ctx.files.config_files, config_folders = ctx.attr.config_folders)
243+
244+
dpa_copy = _cfg_workspace.addtional_workspace_files[0]
245+
dpa_path = dpa_copy.basename
246+
dpa_folder = dpa_copy.dirname
247+
inputs = _cfg_workspace.files + _cfg_workspace.addtional_workspace_files
248+
template = _CFG5_GENERATE_TEMPLATE_LINUX_WORKSPACE
249+
if ctx.attr.private_is_windows:
250+
template = _CFG5_GENERATE_TEMPLATE_WINDOWS_WORKSPACE
251+
252+
if ctx.attr.sip:
253+
inputs.extend(ctx.attr.sip.files.to_list())
254+
return _cfg5_generate_cc(ctx, dpa_path, dpa_folder, inputs, template, additional_genargs, tools)
255+
256+
# def _cfg5_generate_vtt_workspace_cc_impl(ctx):
257+
# tools = generate_tools_vtt(ctx)
258+
# return _cfg5_generate_workspace_cc_impl(ctx, ["--genType=VTT", "--buildVTTProject"], tools)
259+
260+
cfg5_generate_workspace_cc_attrs = {
261+
"dpa_file": attr.label(allow_single_file = [".dpa"], doc = "Dpa project file to start the cfg5 with"),
262+
"config_files": attr.label_list(allow_files = True, doc = "Additional configuration files to start the cfg5 with"),
263+
"genArgs": attr.string_list(doc = "The DaVinciCfgCmd argument options"),
264+
"sip": attr.label(doc = "sip location to mark it as a dependency, as it the sip is needed for cfg5 execution"),
265+
"excluded_files": attr.string_list(doc = "(Optional) List of files to exclude from the generated files"),
266+
"private_is_windows": attr.bool(mandatory = True, doc = "Is set automatically to the correct OS value"),
267+
# "A List of the folders where the config files reside, this cannot be detected automatically, as only the current package can be resolved elegantly"
268+
"config_folders": attr.string_list(doc = "(Optional) List of config folders that the path will be checked for in each file to create a nested Config folder structure, default is [\"Config\"]", default = ["Config"]),
269+
"rsync": attr.label(executable = True, cfg = "exec", default = Label("@ape//ape:rsync")),
270+
}
271+
272+
# cfg5_generate_vtt_workspace_cc_def = rule(
273+
# implementation = _cfg5_generate_vtt_workspace_cc_impl,
274+
# attrs = cfg5_generate_workspace_cc_attrs,
275+
# doc = """
276+
# Creates a separate cfg5 workspace containing all the given config files and run the cfg5 in this created directory inside the bazel-bin.
277+
# This rule is wrapped with private_is_windows attribute to separate between OS differences.
278+
# Used specifically for the vtt use case, as this adds the correct vtt flags to the Cfg5 call automatically.
279+
# """,
280+
# toolchains = ["//rules/cfg5:toolchain_type", "//rules/vtt:toolchain_type"],
281+
# )
282+
283+
# def cfg5_generate_vtt_workspace_cc(name, **kwargs):
284+
# """Wraps the cfg5_generate_vtt_workspace_cc with the private_is_windows select statement in place
285+
286+
# Args:
287+
# name: The unique name of this target
288+
# **kwargs: All of the attrs of the cfg5_generate_vtt_workspace_cc rule
289+
290+
# Returns:
291+
# A cfg5_generate_vtt_workspace_cc_def rule that contains the actual implementation
292+
# """
293+
# cfg5_generate_vtt_workspace_cc_def(
294+
# name = name,
295+
# private_is_windows = select({
296+
# "@bazel_tools//src/conditions:host_windows": True,
297+
# "//conditions:default": False,
298+
# }),
299+
# **kwargs
300+
# )
301+
302+
def _cfg5_generate_rt_workspace_cc_impl(ctx):
303+
return _cfg5_generate_workspace_cc_impl(ctx, ["--genType=REAL"])
304+
305+
cfg5_generate_rt_workspace_cc_def = rule(
306+
implementation = _cfg5_generate_rt_workspace_cc_impl,
307+
attrs = cfg5_generate_workspace_cc_attrs,
308+
doc = """
309+
Creates a separate cfg5 workspace containing all the given config files and run the cfg5 in this created directory inside the bazel-bin.
310+
This rule is wrapped with private_is_windows attribute to separate between OS differences.
311+
Used specifically for the rt use case, as this adds the correct rt flags to the Cfg5 call automatically.
312+
""",
313+
toolchains = ["//rules/cfg5:toolchain_type"],
314+
)
315+
316+
def cfg5_generate_rt_workspace_cc(name, **kwargs):
317+
"""Wraps the cfg5_generate_rt_workspace_cc with the private_is_windows select statement in place
318+
319+
Args:
320+
name: The unique name of this target
321+
**kwargs: All of the attrs of the cfg5_generate_rt_workspace_cc rule
322+
323+
Returns:
324+
A cfg5_generate_rt_workspace_cc_def rule that contains the actual implementation
325+
"""
326+
cfg5_generate_rt_workspace_cc_def(
327+
name = name,
328+
private_is_windows = select({
329+
"@bazel_tools//src/conditions:host_windows": True,
330+
"//conditions:default": False,
331+
}),
332+
**kwargs
333+
)

0 commit comments

Comments
 (0)