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=7.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}) .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,In1.Cu,In2.Cu,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 "$(abspath $(@D))" \ --name-format "$(@F)" ibom: ${PRO_DIR}/out/bom_interactive.html %/schematic.pdf: mkdir -p $(@D) $(file >${COLORS_DIR}/pdf_export.json,${pdf_export_json}) kicad-cli sch export pdf --theme pdf_export --output "$@" --no-background-color "${SCHFILE}" rm "${COLORS_DIR}/pdf_export.json" define LAYERS {'file': "F_Edge_Cuts", 'name': "Edge.Cuts", 'mirror': False, 'border': True}, {'file': "F_Cu", 'name': "F.Cu", 'mirror': False, 'border': False}, {'file': "F_Paste", 'name': "F.Paste", 'mirror': False, 'border': False}, {'file': "F_Fab", 'name': "F.Fab", 'mirror': False, 'border': False}, {'file': "User_Drawings", 'name': "User.Drawings", 'mirror': False, 'border': False}, {'file': "User_Eco1", 'name': "User.Eco1", 'mirror': False, 'border': False}, {'file': "B_Edge_Cuts", 'name': "Edge.Cuts", 'mirror': True, 'border': True}, {'file': "B_Cu", 'name': "B.Cu", 'mirror': True, 'border': False}, {'file': "B_Paste", 'name': "B.Paste", 'mirror': True, 'border': False}, {'file': "B_Fab", 'name': "B.Fab", 'mirror': True, 'border': False}, endef %/assembly_f.pdf %/assembly_b.pdf: mkdir -p $(@D) $(file >${COLORS_DIR}/pdf_export.json,${pdf_export_json}) $(file >$(@D)/plot.py,${plot_py}) ${PYTHON} "$(@D)/plot.py" "${PCBFILE}" qpdf "$(@D)/${NAME}-F_Edge_Cuts.pdf" --overlay "$(@D)/${NAME}-F_Cu.pdf" -- "$(@D)/assembly_f.pdf" qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-F_Paste.pdf" -- qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-F_Fab.pdf" -- qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-User_Drawings.pdf" -- qpdf --replace-input "$(@D)/assembly_f.pdf" --overlay "$(@D)/${NAME}-User_Eco1.pdf" -- qpdf "$(@D)/${NAME}-B_Edge_Cuts.pdf" --overlay "$(@D)/${NAME}-B_Cu.pdf" -- "$(@D)/assembly_b.pdf" qpdf --replace-input "$(@D)/assembly_b.pdf" --overlay "$(@D)/${NAME}-B_Paste.pdf" -- qpdf --replace-input "$(@D)/assembly_b.pdf" --overlay "$(@D)/${NAME}-B_Fab.pdf" -- rm "${COLORS_DIR}/pdf_export.json" "$(@D)/plot.py" "$(@D)/${NAME}-F_Edge_Cuts.pdf" "$(@D)/${NAME}-F_Cu.pdf" "$(@D)/${NAME}-F_Paste.pdf" "$(@D)/${NAME}-F_Fab.pdf" "$(@D)/${NAME}-User_Drawings.pdf" "$(@D)/${NAME}-User_Eco1.pdf" "$(@D)/${NAME}-B_Edge_Cuts.pdf" "$(@D)/${NAME}-B_Cu.pdf" "$(@D)/${NAME}-B_Paste.pdf" "$(@D)/${NAME}-B_Fab.pdf" %/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 plot_py import os, pcbnew, sys layers = [ ${LAYERS} ] board = pcbnew.LoadBoard(sys.argv[1]) settings_manager = pcbnew.GetSettingsManager() color_settings = settings_manager.GetColorSettings('pdf_export') plot_controller = pcbnew.PLOT_CONTROLLER(board) plot_controller.SetColorMode(True) plot_options = plot_controller.GetPlotOptions() plot_options.SetOutputDirectory(os.path.dirname(os.path.abspath(__file__))) plot_options.SetPlotInvisibleText(False) # plot_options.SetPlotPadsOnSilkLayer(False) plot_options.SetUseAuxOrigin(False) plot_options.SetScale(1.0) plot_options.SetAutoScale(False) # plot_options.SetPlotMode(PLOT_MODE) # plot_options.SetLineWidth(2000) plot_options.SetNegative(False) plot_options.SetPlotValue(True) plot_options.SetPlotReference(True) plot_options.SetPlotViaOnMaskLayer(True) plot_options.SetColorSettings(color_settings) plot_options.SetBlackAndWhite(False) for layer in layers: layer_id = board.GetLayerID(layer['name']) if pcbnew.IsCopperLayer(layer_id): plot_options.SetDrillMarksType(pcbnew.DRILL_MARKS_FULL_DRILL_SHAPE) else: plot_options.SetDrillMarksType(pcbnew.DRILL_MARKS_NO_DRILL_SHAPE) plot_options.SetPlotFrameRef(layer['border']) plot_options.SetMirror(layer['mirror']) plot_controller.SetLayer(layer_id) plot_controller.OpenPlotfile(layer['file'], pcbnew.PLOT_FORMAT_PDF, '') plot_controller.PlotLayer() endef 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.300)", "b_paste": "rgba(0, 132, 0, 0.300)", "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.100)", "f": "rgba(0, 132, 0, 0.100)", "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(0, 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.300)", "f_paste": "rgba(0, 132, 0, 0.300)", "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(200, 114, 171)" }, "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; , , , 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}