From ca4fd8d4cf43a8624a9c902682e157f80708d47b Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Fri, 27 Sep 2019 15:07:11 +0200 Subject: kicad_gerber.cmake: Adding KicadUtilsPython option to select which python binary to use. kicad_gerber.py: Sync from ee-python, support executing self with python3 if running under v2 and other way around. Useful if kicad is using the other version. --- cmake/kicad_gerber.cmake | 10 +++- py/kicad_gerber.py | 134 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 108 insertions(+), 36 deletions(-) diff --git a/cmake/kicad_gerber.cmake b/cmake/kicad_gerber.cmake index c56ed19..4e8c850 100644 --- a/cmake/kicad_gerber.cmake +++ b/cmake/kicad_gerber.cmake @@ -25,6 +25,10 @@ function(kicad_gerber) get_filename_component(pcb_file "${ARGS_PCB_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") get_filename_component(basename "${pcb_file}" NAME_WE) + if (NOT DEFINED KicadUtilsPython) + set(KicadUtilsPython python) + endif () + if (NOT ARGS_TARGET) set(target "${basename}-gerber") else () @@ -56,10 +60,11 @@ function(kicad_gerber) endif() execute_process( - COMMAND "${KicadUtilsPyDir}/kicad_gerber.py" + COMMAND "${KicadUtilsPython}" "${KicadUtilsPyDir}/kicad_gerber.py" --pcb "${pcb_file}" --output-directory "${out_dir}" - --detect-files-only ${CMAKE_CURRENT_BINARY_DIR}/${target}-gerber-index.txt + --detect-files-only + --index ${CMAKE_CURRENT_BINARY_DIR}/${target}-gerber-index.txt ${protel} ${uppercase_extensions} ${extended_gerber_attributes} @@ -107,6 +112,7 @@ function(kicad_gerber) OUTPUT ${ARGS_ZIP_FILE} MAIN_DEPENDENCY "${pcb_file}" DEPENDS ${outputs} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND cmake -E remove -f ${ARGS_ZIP_FILE} COMMAND zip -q ${ARGS_ZIP_FILE} -j ${outputs}) endif () diff --git a/py/kicad_gerber.py b/py/kicad_gerber.py index 511f9ee..ac0556d 100755 --- a/py/kicad_gerber.py +++ b/py/kicad_gerber.py @@ -1,9 +1,45 @@ #!/usr/bin/env python from __future__ import print_function -import sys -import os + import argparse -from pcbnew import * +import os +import sys + +try: + from pcbnew import * +except ImportError as e: + ee_hack = os.environ.get("EE_HACK", "0") + print("ee_hack={}".format(ee_hack), file=sys.stderr) + try_p2 = ee_hack == "0" + try_system = ee_hack == "1" + print("Could not import 'pcbnew' module. Make sure you run this command with KiCAD's python.", file=sys.stderr) + + ret = 1 + try: + import subprocess + + if try_p2: + argv = sys.argv[1:] + # Try running explicitly with Python 2 + cmd = "/usr/bin/python2 {} {}".format(__file__, " ".join(argv)) + env = dict(os.environ) + env["EE_HACK"] = "1" + print(cmd, file=sys.stderr) + ret = subprocess.call(cmd, shell=True, env=env) + elif try_system: + argv = sys.argv[1:] + # Try with the OS's main python, hopefully the KiCAD packages support that + cmd = "/usr/bin/python3 {} {}".format(__file__, " ".join(argv)) + env = dict(os.environ) + env["EE_HACK"] = "2" + print(cmd, file=sys.stderr) + ret = subprocess.call(cmd, shell=True, env=env) + finally: + pass + print("ret={}".format(ret), file=sys.stderr) + + sys.exit(ret) + def layer_name_parser(s): parts = s.split('=') @@ -12,6 +48,7 @@ def layer_name_parser(s): else: return parts + parser = argparse.ArgumentParser(description='KiCAD PCB to GERBER converter') parser.add_argument('--pcb', @@ -28,8 +65,15 @@ parser.add_argument('--output-directory', parser.add_argument('--detect-files-only', dest='detect_files_only', - action='store', - help='Don\'t create the GERBER files, just write a list of to be created') + action='store_true', + help='Don\'t create the GERBER files, just list the files to be created') + +parser.add_argument('-M', + dest='mkdep', + help='Output a Makefile-compatible file') + +parser.add_argument('--index', + dest='index') parser.add_argument('--create-drill-map-file', dest='create_drill_map_file', @@ -69,6 +113,7 @@ if args.layer_extensions is not None: board = LoadBoard(args.pcb) + class Plan: def __init__(self, layerNum, layerName, description): self.layerNum = layerNum @@ -88,6 +133,7 @@ class Plan: description = "Copper Layer " + layerName return Plan(layerNum, layerName, description) + plot_plan = [Plan.standard(layerNum, description) for (layerNum, description) in [ (F_SilkS, "Silk front"), (F_Mask, "Mask front"), @@ -105,6 +151,7 @@ pctl = PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() output_directory = args.output_directory +output_directory = os.path.abspath(args.output_directory) popt.SetOutputDirectory(output_directory) if not os.path.isdir(output_directory): @@ -132,6 +179,12 @@ basename = os.path.splitext(filename)[0] drlFileOut = drlFile = basename + "-PTH.drl" drlNpthFileOut = drlNpthFile = basename + "-NPTH.drl" +if args.protel_extensions: + n, e = os.path.splitext(drlFileOut) + drlFileOut = n + ".txt" + n, e = os.path.splitext(drlNpthFileOut) + drlNpthFileOut = n + ".txt" + if args.uppercase_extensions: n, e = os.path.splitext(drlFileOut) drlFileOut = n + e.upper() @@ -162,43 +215,60 @@ for plan in plot_plan: # if newExt is not None: # ext = "." + newExt + # if not args.protel_extensions: plan.postfix = plan.layerName plan.filename = basename + "-" + plan.postfix + ext # print "filename = " + plan.filename + ", postfix=" + plan.postfix # print "filename: " + plan.filename +if args.mkdep: + with open(args.mkdep, "w") as f: + pcb = os.path.abspath(args.pcb) + + def w(path): + p = path[len(os.path.commonprefix([path, pcb])):] + print("{}: {}".format(p, args.pcb), file=f) + + for plan in plot_plan: + w(plan.filename) + + w(drlFileOut) + w(drlNpthFileOut) + +if args.index: + with open(args.index, "w") as f: + pcb = os.path.abspath(args.pcb) + + def w(path): + p = path[len(os.path.commonprefix([path, pcb])):] + print("{}".format(p), file=f) + + for plan in plot_plan: + w(plan.filename) + + w(drlFileOut) + w(drlNpthFileOut) + if args.detect_files_only: - with open(args.detect_files_only, "w") as f: - for plan in plot_plan: - print(plan.filename, file=f) + for plan in plot_plan: + print(plan.filename) + + print(drlFileOut) + print(drlNpthFileOut) - print(drlFileOut, file=f) - print(drlNpthFileOut, file=f) sys.exit(0) # Set some important plot options: popt.SetPlotFrameRef(False) - -# "Default line width (mm)", default=0.1mm -popt.SetLineWidth(FromMM(0.1)) +popt.SetLineWidth(FromMM(0.35)) popt.SetAutoScale(False) - -# "Mirrored plot", default=False. Not applicable for Gerber +popt.SetScale(1) popt.SetMirror(False) - -# "Include extended attributes", default=False popt.SetUseGerberAttributes(args.extended_gerber_attributes) - -# "Drill marks" -popt.SetDrillMarksType(PCB_PLOT_PARAMS.NO_DRILL_SHAPE) - -# "Scaling" popt.SetScale(1) - -# "Use auxilary axis as origin" -popt.SetUseAuxOrigin(False) +popt.SetUseAuxOrigin(True) # This by gerbers only (also the name is truly horrid!) popt.SetSubtractMaskFromSilk(False) @@ -218,20 +288,16 @@ for plan in plot_plan: pctl.PlotLayer() pctl.ClosePlot() +popt.SetDrillMarksType(PCB_PLOT_PARAMS.FULL_DRILL_SHAPE) + drlwriter = EXCELLON_WRITER(board) drlwriter.SetMapFileFormat(PLOT_FORMAT_GERBER) -# "Drill file options" - -# "Mirror y axis", default=False mirror = False - -# "Minimal header", default=True -minimalHeader = True - +minimalHeader = False offset = wxPoint(0, 0) - -# "Merge PTH and NPTH into one file", default=False +# False to generate 2 separate drill files (one for plated holes, one for non plated holes) +# True to generate only one drill file mergeNPTH = False drlwriter.SetOptions(mirror, minimalHeader, offset, mergeNPTH) -- cgit v1.2.3