# Required tools: kicad-cli, InteractiveHtmlBom, python, zip, qpdf, imagemagick, xsltproc, rst2pdf, sed, awk
#
PRO="your_project.kicad_pro"
PRO_DIR=$(dir ${PRO})
NAME=$(basename $(notdir ${PRO}))
SCHFILE=${PRO_DIR}/${NAME}.kicad_sch
PCBFILE=${PRO_DIR}/${NAME}.kicad_pcb
REV=$(shell sed -En 's/.*\(rev "(.*)"\).*/\1/p' "${SCHFILE}")
KICAD_VER=8.0
PYTHON=python
IBOM_SCRIPT_WIN=${USERPROFILE}/Documents/KiCad/${KICAD_VER}/3rdparty/plugins/org_openscopeproject_InteractiveHtmlBom/generate_interactive_bom.py
IBOM_SCRIPT_NIX=${HOME}/.local/share/kicad/${KICAD_VER}/3rdparty/plugins/org_openscopeproject_InteractiveHtmlBom/generate_interactive_bom.py
IBOM_SCRIPT=$(if $(wildcard ${IBOM_SCRIPT_NIX}),${IBOM_SCRIPT_NIX},${IBOM_SCRIPT_WIN})
COLORS_DIR_WIN=${USERPROFILE}/AppData/Roaming/kicad/${KICAD_VER}/colors
COLORS_DIR_NIX=${HOME}/.config/kicad/${KICAD_VER}/colors
COLORS_DIR=$(if $(wildcard ${COLORS_DIR_NIX}),${COLORS_DIR_NIX},${COLORS_DIR_WIN})
.SUFFIXES:
.PHONY: all clean gerber pdf ibom
.FORCE:
all: gerber pdf ibom
clean:
rm -rf "${PRO_DIR}/out/"
%/gerber.zip: .FORCE
rm -rf $@ "$(@D)/gerber/"
mkdir -p "$(@D)/gerber/"
kicad-cli pcb export drill --output "$(@D)/gerber/" \
--format excellon \
--drill-origin absolute \
--excellon-units mm \
--excellon-separate-th \
--excellon-zeros-format decimal \
--generate-map \
--map-format gerberx2 \
"${PCBFILE}"
kicad-cli pcb export gerbers --output "$(@D)/gerber/" \
--layers F.Cu,B.Cu,`awk '/layer "In2.Cu"/{print "In1.Cu,In2.Cu,"; exit}' "${PCBFILE}"`F.Silkscreen,B.Silkscreen,F.Mask,B.Mask,F.Paste,B.Paste,Edge.Cuts \
--no-protel-ext \
--no-x2 \
--disable-aperture-macros \
"${PCBFILE}"
zip -rj $@ "$(@D)/gerber/"
rm -rf "$(@D)/gerber/"
gerber: ${PRO_DIR}/out/gerber.zip
%/bom_interactive.html: .FORCE
mkdir -p "$(@D)"
${PYTHON} "${IBOM_SCRIPT}" "${PCBFILE}" \
--dnp-field DNP \
--group-fields "Value,Footprint" \
--include-nets \
--normalize-field-case \
--no-browser \
--dest-dir "out" \
--name-format "$(basename $(@F))"
ibom: ${PRO_DIR}/out/bom_interactive.html
.INTERMEDIATE: ${COLORS_DIR}/pdf_export.json
${COLORS_DIR}/pdf_export.json:
$(file >${COLORS_DIR}/pdf_export.json,${pdf_export_json})
%/schematic.pdf: ${COLORS_DIR}/pdf_export.json
mkdir -p $(@D)
kicad-cli sch export pdf --theme pdf_export --no-background-color --output "$@" "${SCHFILE}"
%/assembly_f.pdf: ${COLORS_DIR}/pdf_export.json
mkdir -p $(@D)
kicad-cli pcb export pdf --theme pdf_export --include-border-title --output "$@" \
--layers Edge.Cuts,F.Cu,F.Paste,F.Fab,User.Drawings,User.Eco1,User.Eco2 \
"${PCBFILE}"
%/assembly_b.pdf: ${COLORS_DIR}/pdf_export.json
mkdir -p $(@D)
kicad-cli pcb export pdf --theme pdf_export --include-border-title --output "$@" --mirror \
--layers Edge.Cuts,B.Cu,B.Paste,B.Fab \
"${PCBFILE}"
%/bom.pdf:
mkdir -p "$(@D)"
kicad-cli sch export python-bom --output "$(@D)/bom.xml" "${SCHFILE}"
$(file >$(@D)/bom2csv.xsl,${bom2csv_xsl})
xsltproc -o "$(@D)/bom.csv" "$(@D)/bom2csv.xsl" "$(@D)/bom.xml"
$(file >$(@D)/bom.rst,${bom_rst})
$(file >$(@D)/bom.rst.style,${bom_rst_style})
rst2pdf -s "$(@D)/bom.rst.style" "$(@D)/bom.rst" "$@"
rm "$(@D)/bom2csv.xsl" "$(@D)/bom.rst" "$(@D)/bom.rst.style" "$(@D)/bom.csv" "$(@D)/bom.xml"
# Current KiCad version cannot automatically export 3D or VRML file, so you need to manually do it and save result to out/*_3d.png
%_3d.jpg: %_3d.png
convert "$<" -quality 90 "$@"
%_3d.pdf: %_3d.jpg
convert "$<" -density 250 "$@"
PC := %
.SECONDEXPANSION:
%/pcb.pdf: $$(@D)/schematic.pdf $$(@D)/assembly_f.pdf $$(@D)/assembly_b.pdf $$(@D)/bom.pdf $$(patsubst $${PC}.png,$${PC}.pdf,$$(wildcard $$(@D)/*_3d.png))
qpdf --empty --pages $+ -- "$@"
rm $+
pdf: ${PRO_DIR}/out/pcb.pdf
define pdf_export_json
{
"3d_viewer": {
"background_bottom": "rgb(102, 102, 128)",
"background_top": "rgb(204, 204, 230)",
"board": "rgba(51, 43, 23, 0.902)",
"copper": "rgb(179, 156, 0)",
"silkscreen_bottom": "rgb(230, 230, 230)",
"silkscreen_top": "rgb(230, 230, 230)",
"soldermask_bottom": "rgba(20, 51, 36, 0.831)",
"soldermask_top": "rgba(20, 51, 36, 0.831)",
"solderpaste": "rgb(128, 128, 128)",
"use_board_stackup_colors": true
},
"board": {
"anchor": "rgb(255, 38, 226)",
"aux_items": "rgb(255, 255, 255)",
"b_adhes": "rgb(0, 0, 132)",
"b_crtyd": "rgb(38, 233, 255)",
"b_fab": "rgb(0, 0, 0)",
"b_mask": "rgba(0, 132, 0, 0.400)",
"b_paste": "rgba(0, 132, 0, 0.400)",
"b_silks": "rgb(255, 0, 0)",
"background": "rgb(255, 255, 255)",
"cmts_user": "rgb(89, 148, 220)",
"conflicts_shadow": "rgba(255, 0, 5, 0.502)",
"copper": {
"b": "rgba(0, 132, 0, 0.200)",
"f": "rgba(0, 132, 0, 0.200)",
"in1": "rgb(127, 200, 127)",
"in10": "rgb(237, 124, 51)",
"in11": "rgb(91, 195, 235)",
"in12": "rgb(247, 111, 142)",
"in13": "rgb(167, 165, 198)",
"in14": "rgb(40, 204, 217)",
"in15": "rgb(232, 178, 167)",
"in16": "rgb(242, 237, 161)",
"in17": "rgb(237, 124, 51)",
"in18": "rgb(91, 195, 235)",
"in19": "rgb(247, 111, 142)",
"in2": "rgb(206, 125, 44)",
"in20": "rgb(167, 165, 198)",
"in21": "rgb(40, 204, 217)",
"in22": "rgb(232, 178, 167)",
"in23": "rgb(242, 237, 161)",
"in24": "rgb(237, 124, 51)",
"in25": "rgb(91, 195, 235)",
"in26": "rgb(247, 111, 142)",
"in27": "rgb(167, 165, 198)",
"in28": "rgb(40, 204, 217)",
"in29": "rgb(232, 178, 167)",
"in3": "rgb(79, 203, 203)",
"in30": "rgb(242, 237, 161)",
"in4": "rgb(219, 98, 139)",
"in5": "rgb(167, 165, 198)",
"in6": "rgb(40, 204, 217)",
"in7": "rgb(232, 178, 167)",
"in8": "rgb(242, 237, 161)",
"in9": "rgb(141, 203, 129)"
},
"cursor": "rgb(255, 255, 255)",
"dwgs_user": "rgb(0, 0, 0)",
"eco1_user": "rgb(72, 0, 0)",
"eco2_user": "rgb(0, 0, 72)",
"edge_cuts": "rgb(72, 72, 0)",
"f_adhes": "rgb(132, 0, 132)",
"f_crtyd": "rgb(255, 38, 226)",
"f_fab": "rgb(0, 0, 0)",
"f_mask": "rgba(0, 132, 0, 0.400)",
"f_paste": "rgba(0, 132, 0, 0.400)",
"f_silks": "rgb(255, 0, 0)",
"footprint_text_invisible": "rgb(132, 132, 132)",
"grid": "rgb(194, 194, 194)",
"grid_axes": "rgb(72, 72, 72)",
"locked_shadow": "rgba(255, 38, 226, 0.502)",
"margin": "rgb(255, 38, 226)",
"pad_plated_hole": "rgb(194, 194, 0)",
"pad_through_hole": "rgb(227, 183, 46)",
"page_limits": "rgb(132, 132, 132)",
"plated_hole": "rgb(26, 196, 210)",
"ratsnest": "rgba(0, 248, 255, 0.349)",
"user_1": "rgb(194, 194, 194)",
"user_2": "rgb(89, 148, 220)",
"user_3": "rgb(180, 219, 210)",
"user_4": "rgb(216, 200, 82)",
"user_5": "rgb(194, 194, 194)",
"user_6": "rgb(89, 148, 220)",
"user_7": "rgb(180, 219, 210)",
"user_8": "rgb(216, 200, 82)",
"user_9": "rgb(232, 178, 167)",
"via_blind_buried": "rgb(187, 151, 38)",
"via_hole": "rgb(227, 183, 46)",
"via_micro": "rgb(0, 132, 132)",
"via_through": "rgb(236, 236, 236)",
"worksheet": "rgb(132, 0, 0)"
},
"meta": {
"name": "pdf_export",
"version": 5
},
"schematic": {
"anchor": "rgb(0, 0, 255)",
"aux_items": "rgb(0, 0, 0)",
"background": "rgb(245, 244, 239)",
"brightened": "rgb(255, 0, 255)",
"bus": "rgb(0, 0, 132)",
"bus_junction": "rgb(0, 0, 132)",
"component_body": "rgb(255, 255, 194)",
"component_outline": "rgb(132, 0, 0)",
"cursor": "rgb(15, 15, 15)",
"fields": "rgb(132, 0, 132)",
"grid": "rgb(181, 181, 181)",
"grid_axes": "rgb(0, 0, 132)",
"hidden": "rgb(94, 194, 194)",
"hovered": "rgb(0, 0, 255)",
"junction": "rgb(0, 150, 0)",
"label_global": "rgb(132, 0, 0)",
"label_hier": "rgb(114, 86, 0)",
"label_local": "rgb(15, 15, 15)",
"netclass_flag": "rgb(72, 72, 72)",
"no_connect": "rgb(0, 0, 132)",
"note": "rgb(0, 0, 194)",
"note_background": "rgba(0, 0, 0, 0.000)",
"override_item_colors": false,
"page_limits": "rgb(181, 181, 181)",
"pin": "rgb(132, 0, 0)",
"pin_name": "rgb(0, 100, 100)",
"pin_number": "rgb(169, 0, 0)",
"private_note": "rgb(72, 72, 255)",
"reference": "rgb(0, 100, 100)",
"shadow": "rgba(102, 179, 255, 0.800)",
"sheet": "rgb(132, 0, 0)",
"sheet_background": "rgba(255, 255, 255, 0.000)",
"sheet_fields": "rgb(132, 0, 132)",
"sheet_filename": "rgb(114, 86, 0)",
"sheet_label": "rgb(0, 100, 100)",
"sheet_name": "rgb(0, 100, 100)",
"value": "rgb(0, 100, 100)",
"wire": "rgb(0, 150, 0)",
"worksheet": "rgb(132, 0, 0)"
}
}
endef
define bom2csv_xsl
]>
References, Value, Footprint, Qty
&nl;
,"
(Alternatives:
)
","
",
endef
define bom_rst
Bill Of Materials
-----------------
.. csv-table::
:file: bom.csv
:header-rows: 1
:widths: 4,4,5,1
.. footer:: ${NAME} rev.${REV} BOM page ###Page###/###Total###
endef
define bom_rst_style
pageSetup:
spacing-footer: 0mm
spacing-header: 0mm
margin-bottom: 5mm
margin-gutter: 0mm
margin-left: 7mm
margin-right: 7mm
margin-top: 5mm
styles:
base
fontSize: 9
table-heading:
fontName: stdBold
endef
export PATH:=/cygdrive/c/Program Files/KiCad/${KICAD_VER}/bin:/cygdrive/c/Program Files/qpdf/bin:${PATH}