| # Copyright 2024 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| |
| """KiCad Bazel Rules.""" |
| |
| load("@bazel_skylib//rules:native_binary.bzl", "native_test") |
| load("@rules_pkg//pkg:mappings.bzl", "pkg_files") |
| load("@rules_pkg//pkg:zip.bzl", "pkg_zip") |
| |
| def kicad_project(name, project, sym_lib_table, fp_lib_table, schematic_root, schematic_srcs, data, pcb, pcb_design_rules, pcb_layers): |
| """Top level kicad project macro. |
| |
| Runs the following macros: |
| |
| - kicad_schematic_pdf: Exports the schematic PDF using |
| https://docs.kicad.org/8.0/en/cli/cli.html#schematic_pdf_export |
| - kicad_schematic_test: Runs the schematic electrical rules check using |
| https://docs.kicad.org/8.0/en/cli/cli.html#schematic_erc |
| - kicad_pcb_drc_test: Runs the pcb design rules check using |
| https://docs.kicad.org/8.0/en/cli/cli.html#pcb_drc |
| - kicad_pcb_export: Generates gerber layer files using: |
| https://docs.kicad.org/8.0/en/cli/cli.html#pcb_gerber_export_multiple_layers_per_file |
| |
| Args: |
| name: Name for this build rule. |
| project: The .kicad_pro file for this project. |
| sym_lib_table: The kicad symbol library table file. |
| fp_lib_table: The kicad footprint library table file. |
| schematic_root: Top level schematic .kicad_sch file. |
| schematic_srcs: List of additional .kicad_sch files. |
| data: List of symbols, footprints, and step files. |
| pcb: The .kicad_pcb file. |
| pcb_layers: A list of layers to be exported. |
| pcb_design_rules: A .kicad_dru file. |
| """ |
| kicad_schematic_pdf( |
| name = name + "_sch", |
| root = schematic_root, |
| srcs = schematic_srcs, |
| data = data + [project, sym_lib_table], |
| ) |
| kicad_schematic_test( |
| name = name + "_erc_test", |
| root = schematic_root, |
| srcs = schematic_srcs, |
| data = data + [project, sym_lib_table], |
| ) |
| kicad_pcb_drc_test( |
| name = name + "_drc_test", |
| pcb = pcb, |
| data = data + [project, pcb_design_rules, fp_lib_table], |
| ) |
| kicad_pcb_export( |
| name = name + "_pcb_export", |
| pcb = pcb, |
| data = data + [project], |
| layer_list = pcb_layers, |
| ) |
| pkg_files( |
| name = name + "_fabrication_output_files", |
| srcs = [ |
| ":" + name + "_pcb_export", |
| ], |
| prefix = "fabrication_outputs", |
| ) |
| pkg_zip( |
| name = name + "_fabrication_output_zip", |
| out = "fabrication_outputs.zip", |
| srcs = [ |
| ":" + name + "_fabrication_output_files", |
| ], |
| ) |
| |
| def kicad_schematic_test(name, root, srcs, data): |
| args = ["sch", "erc", "--exit-code-violations", "$(rootpath " + root + " )"] |
| |
| native_test( |
| name = name, |
| src = str(Label("//build:kicad_cli_test")), |
| args = args, |
| data = srcs + data + [root], |
| # Note: out is mandatory in older bazel-skylib versions. |
| out = name + ".exe", |
| ) |
| |
| def kicad_pcb_drc_test(name, pcb, data): |
| args = ["pcb", "drc", "--exit-code-violations", "$(rootpath " + pcb + " )"] |
| |
| native_test( |
| name = name, |
| src = str(Label("//build:kicad_cli_test")), |
| args = args, |
| data = data + [pcb], |
| # Note: out is mandatory in older bazel-skylib versions. |
| out = name + ".exe", |
| ) |
| |
| def _kicad_schematic_pdf_impl(ctx): |
| pdf_file = ctx.actions.declare_file(ctx.label.name + ".pdf") |
| |
| args = ["sch", "export", "pdf", "--output", pdf_file.path, ctx.file.root.path] |
| |
| ctx.actions.run( |
| inputs = ctx.files.srcs + [ctx.file.root], |
| outputs = [pdf_file], |
| arguments = args, |
| use_default_shell_env = True, |
| progress_message = "running ERC on %s" % ctx.attr.name, |
| executable = ctx.executable._kicad_cli, |
| ) |
| |
| return [ |
| DefaultInfo(files = depset([pdf_file])), |
| ] |
| |
| kicad_schematic_pdf = rule( |
| implementation = _kicad_schematic_pdf_impl, |
| attrs = { |
| "srcs": attr.label_list(allow_files = [".kicad_sch"]), |
| "root": attr.label( |
| allow_single_file = [".kicad_sch"], |
| mandatory = True, |
| ), |
| "data": attr.label_list(allow_files = True), |
| "_kicad_cli": attr.label( |
| executable = True, |
| cfg = "exec", |
| allow_files = True, |
| default = Label("//build:kicad_cli"), |
| ), |
| }, |
| ) |
| |
| FOUR_LAYER_LIST = [ |
| "F.Cu", |
| "In1.Cu", |
| "In2.Cu", |
| "B.Cu", |
| "F.Paste", |
| "B.Paste", |
| "F.Silkscreen", |
| "B.Silkscreen", |
| "F.Mask", |
| "B.Mask", |
| "Edge.Cuts", |
| ] |
| |
| def _kicad_gerber_layer_extension(layer): |
| layer_extensions = { |
| "F.Cu": "gtl", |
| "In1.Cu": "g2", |
| "In2.Cu": "g3", |
| "B.Cu": "gbl", |
| "F.Adhesive": "gta", |
| "B.Adhesive": "gba", |
| "F.Paste": "gtp", |
| "B.Paste": "gbp", |
| "F.Silkscreen": "gto", |
| "B.Silkscreen": "gbo", |
| "F.Mask": "gts", |
| "B.Mask": "gbs", |
| "User.Drawings": "gbr", |
| "User.Comments": "gbr", |
| "User.Eco1": "gbr", |
| "User.Eco2": "gbr", |
| "Edge.Cuts": "gm1", |
| "Margin": "gbr", |
| "F.Courtyard": "gbr", |
| "B.Courtyard": "gbr", |
| "F.Fab": "gbr", |
| "B.Fab": "gbr", |
| "User.1": "gbr", |
| "User.2": "gbr", |
| "User.3": "gbr", |
| "User.4": "gbr", |
| "User.5": "gbr", |
| "User.6": "gbr", |
| "User.7": "gbr", |
| "User.8": "gbr", |
| "User.9": "gbr", |
| } |
| return layer_extensions.get(layer, "gbr") |
| |
| def _kicad_pcb_export_impl(ctx): |
| pcb_file_basename = ctx.file.pcb.basename.replace(".kicad_pcb", "") |
| gerber_outputs = [ |
| ctx.actions.declare_file(pcb_file_basename + "-job.gbrjob"), |
| ] |
| gerber_output_dir = gerber_outputs[0].dirname |
| |
| for layer in ctx.attr.layer_list: |
| gerber_outputs += [ |
| ctx.actions.declare_file( |
| "{}-{}.{}".format( |
| pcb_file_basename, |
| layer.replace(".", "_"), |
| _kicad_gerber_layer_extension(layer), |
| ), |
| ), |
| ] |
| |
| gerber_args = [ |
| "pcb", |
| "export", |
| "gerbers", |
| "--output", |
| gerber_output_dir, |
| "--board-plot-params", |
| ] |
| gerber_args += [ |
| "--layers", |
| ",".join(ctx.attr.layer_list), |
| ] |
| gerber_args += [ |
| ctx.file.pcb.path, |
| ] |
| |
| ctx.actions.run( |
| inputs = ctx.files.data + [ctx.file.pcb], |
| outputs = gerber_outputs, |
| arguments = gerber_args, |
| use_default_shell_env = True, |
| progress_message = "running PCB EXPORT GERBERS on %s" % ctx.attr.name, |
| executable = ctx.executable._kicad_cli, |
| ) |
| |
| drill_outputs = [ |
| ctx.actions.declare_file(pcb_file_basename + "-NPTH-drl_map.gbr"), |
| ctx.actions.declare_file(pcb_file_basename + "-NPTH.drl"), |
| ctx.actions.declare_file(pcb_file_basename + "-PTH-drl_map.gbr"), |
| ctx.actions.declare_file(pcb_file_basename + "-PTH.drl"), |
| ] |
| drill_output_dir = drill_outputs[0].dirname + "/" |
| |
| drill_args = [ |
| "pcb", |
| "export", |
| "drill", |
| "--output", |
| drill_output_dir, |
| "--drill-origin", |
| "absolute", |
| "--excellon-separate-th", |
| "--excellon-units", |
| "mm", |
| "--excellon-oval-format", |
| "alternate", |
| "--excellon-zeros-format", |
| "decimal", |
| "--generate-map", |
| "--map-format", |
| "gerberx2", |
| ctx.file.pcb.path, |
| ] |
| |
| ctx.actions.run( |
| inputs = ctx.files.data + [ctx.file.pcb], |
| outputs = drill_outputs, |
| arguments = drill_args, |
| use_default_shell_env = True, |
| progress_message = "running PCB EXPORT DRILL on %s" % ctx.attr.name, |
| executable = ctx.executable._kicad_cli, |
| ) |
| |
| return [ |
| DefaultInfo(files = depset(gerber_outputs + drill_outputs)), |
| ] |
| |
| kicad_pcb_export = rule( |
| implementation = _kicad_pcb_export_impl, |
| attrs = { |
| "pcb": attr.label( |
| allow_single_file = [".kicad_pcb"], |
| mandatory = True, |
| ), |
| "layer_list": attr.string_list(mandatory = True), |
| "data": attr.label_list(allow_files = True), |
| "_kicad_cli": attr.label( |
| executable = True, |
| cfg = "exec", |
| allow_files = True, |
| default = Label("//build:kicad_cli"), |
| ), |
| }, |
| ) |