|
| 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