From a783e4645d22096bf7cb1c9bc509ab43c9a9c317 Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 13 Oct 2019 14:53:24 +0100 Subject: [PATCH] Refactor build script toolchain lookups. Now environment variable overrides no longer infect the build scripts. _toolchain.overrides is dropped as probably misguided in the first place. Fixes #251. --- nmigen/_toolchain.py | 33 +++++++++-------------- nmigen/build/plat.py | 42 ++++++++++++++++++++++++----- nmigen/vendor/intel.py | 8 +++--- nmigen/vendor/lattice_ecp5.py | 12 ++++----- nmigen/vendor/lattice_ice40.py | 6 ++--- nmigen/vendor/lattice_machxo2.py | 6 ++--- nmigen/vendor/xilinx_7series.py | 2 +- nmigen/vendor/xilinx_spartan_3_6.py | 10 +++---- nmigen/vendor/xilinx_ultrascale.py | 2 +- 9 files changed, 71 insertions(+), 50 deletions(-) diff --git a/nmigen/_toolchain.py b/nmigen/_toolchain.py index 4878a32..fca2bac 100644 --- a/nmigen/_toolchain.py +++ b/nmigen/_toolchain.py @@ -2,45 +2,36 @@ import os import shutil -__all__ = ["ToolNotFound", "get_tool", "has_tool", "require_tool"] +__all__ = ["ToolNotFound", "tool_env_var", "has_tool", "require_tool"] class ToolNotFound(Exception): pass -def _tool_env_var(name): +def tool_env_var(name): return name.upper().replace("-", "_") -def get_tool(name): - return os.environ.get(_tool_env_var(name), overrides.get(name, name)) +def _get_tool(name): + return os.environ.get(tool_env_var(name), name) def has_tool(name): - return shutil.which(get_tool(name)) is not None + return shutil.which(_get_tool(name)) is not None def require_tool(name): - env_var = _tool_env_var(name) - path = get_tool(name) + env_var = tool_env_var(name) + path = _get_tool(name) if shutil.which(path) is None: - if path == name: + if env_var in os.environ: + raise ToolNotFound("Could not find required tool {} in {} as " + "specified via the {} environment variable". + format(name, path, env_var)) + else: raise ToolNotFound("Could not find required tool {} in PATH. Place " "it directly in PATH or specify path explicitly " "via the {} environment variable". format(name, env_var)) - else: - if os.getenv(env_var): - via = "the {} environment variable".format(env_var) - else: - via = "your packager's toolchain overrides. This is either an " \ - "nMigen bug or a packaging error" - raise ToolNotFound("Could not find required tool {} in {} as " - "specified via {}".format(name, path, via)) return path - - -# Packages for systems like Nix can inject full paths to certain tools by adding them in -# this dictionary, e.g. ``overrides = {"yosys": "/full/path/to/yosys"}``. -overrides = {} diff --git a/nmigen/build/plat.py b/nmigen/build/plat.py index a006c7e..65d5401 100644 --- a/nmigen/build/plat.py +++ b/nmigen/build/plat.py @@ -247,12 +247,14 @@ class TemplatedPlatform(Platform): # {{autogenerated}} set -e{{verbose("x")}} [ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}" + {{emit_prelude("sh")}} {{emit_commands("sh")}} """, "build_{{name}}.bat": """ @rem {{autogenerated}} {{quiet("@echo off")}} if defined {{platform._toolchain_env_var}} call %{{platform._toolchain_env_var}}% + {{emit_prelude("bat")}} {{emit_commands("bat")}} """, } @@ -286,14 +288,30 @@ class TemplatedPlatform(Platform): return verilog._convert_rtlil_text(rtlil_text, strip_internal_attrs=False, write_verilog_opts=opts) - def emit_commands(format): + def emit_prelude(syntax): + commands = [] + for name in self.required_tools: + env_var = tool_env_var(name) + if syntax == "sh": + template = ": ${{{env_var}:={name}}}" + elif syntax == "bat": + template = \ + "if [%{env_var}%] eq [\"\"] set {env_var}=\n" \ + "if [%{env_var}%] eq [] set {env_var}={name}" + else: + assert False + commands.append(template.format(env_var=env_var, name=name)) + return "\n".join(commands) + + def emit_commands(syntax): commands = [] for index, command_tpl in enumerate(self.command_templates): - command = render(command_tpl, origin="".format(index + 1)) + command = render(command_tpl, origin="".format(index + 1), + syntax=syntax) command = re.sub(r"\s+", " ", command) - if format == "sh": + if syntax == "sh": commands.append(command) - elif format == "bat": + elif syntax == "bat": commands.append(command + " || exit /b") else: assert False @@ -315,6 +333,16 @@ class TemplatedPlatform(Platform): else: return jinja2.Undefined(name=var) + @jinja2.contextfunction + def invoke_tool(context, name): + env_var = tool_env_var(name) + if context.parent["syntax"] == "sh": + return "\"${}\"".format(env_var) + elif context.parent["syntax"] == "bat": + return "%{}%".format(env_var) + else: + assert False + def options(opts): if isinstance(opts, str): return opts @@ -336,7 +364,7 @@ class TemplatedPlatform(Platform): else: return arg - def render(source, origin): + def render(source, origin, syntax=None): try: source = textwrap.dedent(source).strip() compiled = jinja2.Template(source, trim_blocks=True, lstrip_blocks=True) @@ -351,8 +379,10 @@ class TemplatedPlatform(Platform): "emit_rtlil": emit_rtlil, "emit_verilog": emit_verilog, "emit_debug_verilog": emit_debug_verilog, + "emit_prelude": emit_prelude, "emit_commands": emit_commands, - "get_tool": get_tool, + "syntax": syntax, + "invoke_tool": invoke_tool, "get_override": get_override, "verbose": verbose, "quiet": quiet, diff --git a/nmigen/vendor/intel.py b/nmigen/vendor/intel.py index 07943ec..c65b7c0 100644 --- a/nmigen/vendor/intel.py +++ b/nmigen/vendor/intel.py @@ -103,22 +103,22 @@ class IntelPlatform(TemplatedPlatform): } command_templates = [ r""" - {{get_tool("quartus_map")}} + {{invoke_tool("quartus_map")}} {{get_override("quartus_map_opts")|options}} --rev={{name}} {{name}} """, r""" - {{get_tool("quartus_fit")}} + {{invoke_tool("quartus_fit")}} {{get_override("quartus_fit_opts")|options}} --rev={{name}} {{name}} """, r""" - {{get_tool("quartus_asm")}} + {{invoke_tool("quartus_asm")}} {{get_override("quartus_asm_opts")|options}} --rev={{name}} {{name}} """, r""" - {{get_tool("quartus_sta")}} + {{invoke_tool("quartus_sta")}} {{get_override("quartus_sta_opts")|options}} --rev={{name}} {{name}} """, diff --git a/nmigen/vendor/lattice_ecp5.py b/nmigen/vendor/lattice_ecp5.py index b40046e..c3ca286 100644 --- a/nmigen/vendor/lattice_ecp5.py +++ b/nmigen/vendor/lattice_ecp5.py @@ -136,14 +136,14 @@ class LatticeECP5Platform(TemplatedPlatform): } _trellis_command_templates = [ r""" - {{get_tool("yosys")}} + {{invoke_tool("yosys")}} {{quiet("-q")}} {{get_override("yosys_opts")|options}} -l {{name}}.rpt {{name}}.ys """, r""" - {{get_tool("nextpnr-ecp5")}} + {{invoke_tool("nextpnr-ecp5")}} {{quiet("--quiet")}} {{get_override("nextpnr_opts")|options}} --log {{name}}.tim @@ -155,7 +155,7 @@ class LatticeECP5Platform(TemplatedPlatform): --textcfg {{name}}.config """, r""" - {{get_tool("ecppack")}} + {{invoke_tool("ecppack")}} {{verbose("--verbose")}} {{get_override("ecppack_opts")|options}} --input {{name}}.config @@ -235,16 +235,16 @@ class LatticeECP5Platform(TemplatedPlatform): _diamond_command_templates = [ # These don't have any usable command-line option overrides. r""" - {{get_tool("pnmainc")}} + {{invoke_tool("pnmainc")}} {{name}}.tcl """, r""" - {{get_tool("ddtcmd")}} + {{invoke_tool("ddtcmd")}} -oft -bit -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.bit """, r""" - {{get_tool("ddtcmd")}} + {{invoke_tool("ddtcmd")}} -oft -svfsingle -revd -op "Fast Program" -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.svf """, diff --git a/nmigen/vendor/lattice_ice40.py b/nmigen/vendor/lattice_ice40.py index d3fa8c7..5a8d197 100644 --- a/nmigen/vendor/lattice_ice40.py +++ b/nmigen/vendor/lattice_ice40.py @@ -140,14 +140,14 @@ class LatticeICE40Platform(TemplatedPlatform): } _icestorm_command_templates = [ r""" - {{get_tool("yosys")}} + {{invoke_tool("yosys")}} {{quiet("-q")}} {{get_override("yosys_opts")|options}} -l {{name}}.rpt {{name}}.ys """, r""" - {{get_tool("nextpnr-ice40")}} + {{invoke_tool("nextpnr-ice40")}} {{quiet("--quiet")}} {{get_override("nextpnr_opts")|options}} --log {{name}}.tim @@ -160,7 +160,7 @@ class LatticeICE40Platform(TemplatedPlatform): --asc {{name}}.asc """, r""" - {{get_tool("icepack")}} + {{invoke_tool("icepack")}} {{verbose("-v")}} {{name}}.asc {{name}}.bin diff --git a/nmigen/vendor/lattice_machxo2.py b/nmigen/vendor/lattice_machxo2.py index c744bc5..99c093c 100644 --- a/nmigen/vendor/lattice_machxo2.py +++ b/nmigen/vendor/lattice_machxo2.py @@ -106,17 +106,17 @@ class LatticeMachXO2Platform(TemplatedPlatform): command_templates = [ # These don't have any usable command-line option overrides. r""" - {{get_tool("pnmainc")}} + {{invoke_tool("pnmainc")}} {{name}}.tcl """, r""" - {{get_tool("ddtcmd")}} + {{invoke_tool("ddtcmd")}} -oft -jed -dev {{platform.device}}-{{platform.speed}}{{platform.package}}{{platform.grade}} -if {{name}}_impl/{{name}}_impl.jed -of {{name}}.jed """, r""" - {{get_tool("ddtcmd")}} + {{invoke_tool("ddtcmd")}} -oft -svfsingle -revd -op "FLASH Erase,Program,Verify" -if {{name}}_impl/{{name}}_impl.jed -of {{name}}.svf """, diff --git a/nmigen/vendor/xilinx_7series.py b/nmigen/vendor/xilinx_7series.py index e94f8d2..a5f6bd6 100644 --- a/nmigen/vendor/xilinx_7series.py +++ b/nmigen/vendor/xilinx_7series.py @@ -139,7 +139,7 @@ class Xilinx7SeriesPlatform(TemplatedPlatform): } command_templates = [ r""" - {{get_tool("vivado")}} + {{invoke_tool("vivado")}} {{verbose("-verbose")}} {{get_override("vivado_opts")|options}} -mode batch diff --git a/nmigen/vendor/xilinx_spartan_3_6.py b/nmigen/vendor/xilinx_spartan_3_6.py index 929b81d..a6158bb 100644 --- a/nmigen/vendor/xilinx_spartan_3_6.py +++ b/nmigen/vendor/xilinx_spartan_3_6.py @@ -141,12 +141,12 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform): } command_templates = [ r""" - {{get_tool("xst")}} + {{invoke_tool("xst")}} {{get_override("xst_opts")|options}} -ifn {{name}}.xst """, r""" - {{get_tool("ngdbuild")}} + {{invoke_tool("ngdbuild")}} {{quiet("-quiet")}} {{verbose("-verbose")}} {{get_override("ngdbuild_opts")|options}} @@ -154,7 +154,7 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform): {{name}}.ngc """, r""" - {{get_tool("map")}} + {{invoke_tool("map")}} {{verbose("-detail")}} {{get_override("map_opts")|default([])|options}} -w @@ -163,7 +163,7 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform): {{name}}.pcf """, r""" - {{get_tool("par")}} + {{invoke_tool("par")}} {{get_override("par_opts")|default([])|options}} -w {{name}}_map.ncd @@ -171,7 +171,7 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform): {{name}}.pcf """, r""" - {{get_tool("bitgen")}} + {{invoke_tool("bitgen")}} {{get_override("bitgen_opts")|default(["-g Compress"])|options}} -w -g Binary:Yes diff --git a/nmigen/vendor/xilinx_ultrascale.py b/nmigen/vendor/xilinx_ultrascale.py index a4dd1fd..663ff2e 100644 --- a/nmigen/vendor/xilinx_ultrascale.py +++ b/nmigen/vendor/xilinx_ultrascale.py @@ -139,7 +139,7 @@ class XilinxUltraScalePlatform(TemplatedPlatform): } command_templates = [ r""" - {{get_tool("vivado")}} + {{invoke_tool("vivado")}} {{verbose("-verbose")}} {{get_override("vivado_opts")|options}} -mode batch -- 2.30.2