Refactor build script toolchain lookups.
authorEmily <vcs@emily.moe>
Sun, 13 Oct 2019 13:53:24 +0000 (14:53 +0100)
committerwhitequark <cz@m-labs.hk>
Sun, 13 Oct 2019 13:53:24 +0000 (13:53 +0000)
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
nmigen/build/plat.py
nmigen/vendor/intel.py
nmigen/vendor/lattice_ecp5.py
nmigen/vendor/lattice_ice40.py
nmigen/vendor/lattice_machxo2.py
nmigen/vendor/xilinx_7series.py
nmigen/vendor/xilinx_spartan_3_6.py
nmigen/vendor/xilinx_ultrascale.py

index 4878a3261a659cb505df62d7a609e0cae2e17485..fca2bacb31bb4e5de2c978fd92b06da6fd0dfa9e 100644 (file)
@@ -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 = {}
index a006c7e603ed91ba3d7d1c412d241945967c855f..65d5401c7d2a620b146c5373d6df0f23424d6c73 100644 (file)
@@ -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="<command#{}>".format(index + 1))
+                command = render(command_tpl, origin="<command#{}>".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,
index 07943ec4ac0dd0a76ce248123bc873fb630046f3..c65b7c041cddbb247eb20a45b9974733ae398b51 100644 (file)
@@ -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}}
         """,
index b40046ef3bcf2c453ec56cb7d332616418ed07b6..c3ca286ca7697f983d02e66b2ff6d1de0f70a4d9 100644 (file)
@@ -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
         """,
index d3fa8c71e04719688e6cbc87966aef73897460b8..5a8d197cf5cce87485a66005109b35ae4e03d777 100644 (file)
@@ -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
index c744bc5d8fa0f3c61dc72040e280998e340ac84a..99c093cf6514a6423b1a33ac2db7c0da36b1fac0 100644 (file)
@@ -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
         """,
index e94f8d2f53524ac7dd6a43ec6e64aeef4189f96b..a5f6bd657f0118cd1bca78ff08cb08e86590e469 100644 (file)
@@ -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
index 929b81d022035f0f990c32d7e7fd641049fc3c01..a6158bb29e4ac1b8e6ab2e7590688f86620d8c64 100644 (file)
@@ -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
index a4dd1fd826d0bc40ca88eae855830d917bfa706b..663ff2edcdc9502b42aead697298a71c282c76cd 100644 (file)
@@ -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