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.
This commit is contained in:
Emily 2019-10-13 14:53:24 +01:00 committed by whitequark
parent 29253295ee
commit a783e4645d
9 changed files with 71 additions and 50 deletions

View file

@ -2,45 +2,36 @@ import os
import shutil import shutil
__all__ = ["ToolNotFound", "get_tool", "has_tool", "require_tool"] __all__ = ["ToolNotFound", "tool_env_var", "has_tool", "require_tool"]
class ToolNotFound(Exception): class ToolNotFound(Exception):
pass pass
def _tool_env_var(name): def tool_env_var(name):
return name.upper().replace("-", "_") return name.upper().replace("-", "_")
def get_tool(name): def _get_tool(name):
return os.environ.get(_tool_env_var(name), overrides.get(name, name)) return os.environ.get(tool_env_var(name), name)
def has_tool(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): def require_tool(name):
env_var = _tool_env_var(name) env_var = tool_env_var(name)
path = get_tool(name) path = _get_tool(name)
if shutil.which(path) is None: 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 " raise ToolNotFound("Could not find required tool {} in PATH. Place "
"it directly in PATH or specify path explicitly " "it directly in PATH or specify path explicitly "
"via the {} environment variable". "via the {} environment variable".
format(name, env_var)) 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 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 = {}

View file

@ -247,12 +247,14 @@ class TemplatedPlatform(Platform):
# {{autogenerated}} # {{autogenerated}}
set -e{{verbose("x")}} set -e{{verbose("x")}}
[ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}" [ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}"
{{emit_prelude("sh")}}
{{emit_commands("sh")}} {{emit_commands("sh")}}
""", """,
"build_{{name}}.bat": """ "build_{{name}}.bat": """
@rem {{autogenerated}} @rem {{autogenerated}}
{{quiet("@echo off")}} {{quiet("@echo off")}}
if defined {{platform._toolchain_env_var}} call %{{platform._toolchain_env_var}}% if defined {{platform._toolchain_env_var}} call %{{platform._toolchain_env_var}}%
{{emit_prelude("bat")}}
{{emit_commands("bat")}} {{emit_commands("bat")}}
""", """,
} }
@ -286,14 +288,30 @@ class TemplatedPlatform(Platform):
return verilog._convert_rtlil_text(rtlil_text, return verilog._convert_rtlil_text(rtlil_text,
strip_internal_attrs=False, write_verilog_opts=opts) 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 = [] commands = []
for index, command_tpl in enumerate(self.command_templates): 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) command = re.sub(r"\s+", " ", command)
if format == "sh": if syntax == "sh":
commands.append(command) commands.append(command)
elif format == "bat": elif syntax == "bat":
commands.append(command + " || exit /b") commands.append(command + " || exit /b")
else: else:
assert False assert False
@ -315,6 +333,16 @@ class TemplatedPlatform(Platform):
else: else:
return jinja2.Undefined(name=var) 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): def options(opts):
if isinstance(opts, str): if isinstance(opts, str):
return opts return opts
@ -336,7 +364,7 @@ class TemplatedPlatform(Platform):
else: else:
return arg return arg
def render(source, origin): def render(source, origin, syntax=None):
try: try:
source = textwrap.dedent(source).strip() source = textwrap.dedent(source).strip()
compiled = jinja2.Template(source, trim_blocks=True, lstrip_blocks=True) compiled = jinja2.Template(source, trim_blocks=True, lstrip_blocks=True)
@ -351,8 +379,10 @@ class TemplatedPlatform(Platform):
"emit_rtlil": emit_rtlil, "emit_rtlil": emit_rtlil,
"emit_verilog": emit_verilog, "emit_verilog": emit_verilog,
"emit_debug_verilog": emit_debug_verilog, "emit_debug_verilog": emit_debug_verilog,
"emit_prelude": emit_prelude,
"emit_commands": emit_commands, "emit_commands": emit_commands,
"get_tool": get_tool, "syntax": syntax,
"invoke_tool": invoke_tool,
"get_override": get_override, "get_override": get_override,
"verbose": verbose, "verbose": verbose,
"quiet": quiet, "quiet": quiet,

View file

@ -103,22 +103,22 @@ class IntelPlatform(TemplatedPlatform):
} }
command_templates = [ command_templates = [
r""" r"""
{{get_tool("quartus_map")}} {{invoke_tool("quartus_map")}}
{{get_override("quartus_map_opts")|options}} {{get_override("quartus_map_opts")|options}}
--rev={{name}} {{name}} --rev={{name}} {{name}}
""", """,
r""" r"""
{{get_tool("quartus_fit")}} {{invoke_tool("quartus_fit")}}
{{get_override("quartus_fit_opts")|options}} {{get_override("quartus_fit_opts")|options}}
--rev={{name}} {{name}} --rev={{name}} {{name}}
""", """,
r""" r"""
{{get_tool("quartus_asm")}} {{invoke_tool("quartus_asm")}}
{{get_override("quartus_asm_opts")|options}} {{get_override("quartus_asm_opts")|options}}
--rev={{name}} {{name}} --rev={{name}} {{name}}
""", """,
r""" r"""
{{get_tool("quartus_sta")}} {{invoke_tool("quartus_sta")}}
{{get_override("quartus_sta_opts")|options}} {{get_override("quartus_sta_opts")|options}}
--rev={{name}} {{name}} --rev={{name}} {{name}}
""", """,

View file

@ -136,14 +136,14 @@ class LatticeECP5Platform(TemplatedPlatform):
} }
_trellis_command_templates = [ _trellis_command_templates = [
r""" r"""
{{get_tool("yosys")}} {{invoke_tool("yosys")}}
{{quiet("-q")}} {{quiet("-q")}}
{{get_override("yosys_opts")|options}} {{get_override("yosys_opts")|options}}
-l {{name}}.rpt -l {{name}}.rpt
{{name}}.ys {{name}}.ys
""", """,
r""" r"""
{{get_tool("nextpnr-ecp5")}} {{invoke_tool("nextpnr-ecp5")}}
{{quiet("--quiet")}} {{quiet("--quiet")}}
{{get_override("nextpnr_opts")|options}} {{get_override("nextpnr_opts")|options}}
--log {{name}}.tim --log {{name}}.tim
@ -155,7 +155,7 @@ class LatticeECP5Platform(TemplatedPlatform):
--textcfg {{name}}.config --textcfg {{name}}.config
""", """,
r""" r"""
{{get_tool("ecppack")}} {{invoke_tool("ecppack")}}
{{verbose("--verbose")}} {{verbose("--verbose")}}
{{get_override("ecppack_opts")|options}} {{get_override("ecppack_opts")|options}}
--input {{name}}.config --input {{name}}.config
@ -235,16 +235,16 @@ class LatticeECP5Platform(TemplatedPlatform):
_diamond_command_templates = [ _diamond_command_templates = [
# These don't have any usable command-line option overrides. # These don't have any usable command-line option overrides.
r""" r"""
{{get_tool("pnmainc")}} {{invoke_tool("pnmainc")}}
{{name}}.tcl {{name}}.tcl
""", """,
r""" r"""
{{get_tool("ddtcmd")}} {{invoke_tool("ddtcmd")}}
-oft -bit -oft -bit
-if {{name}}_impl/{{name}}_impl.bit -of {{name}}.bit -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.bit
""", """,
r""" r"""
{{get_tool("ddtcmd")}} {{invoke_tool("ddtcmd")}}
-oft -svfsingle -revd -op "Fast Program" -oft -svfsingle -revd -op "Fast Program"
-if {{name}}_impl/{{name}}_impl.bit -of {{name}}.svf -if {{name}}_impl/{{name}}_impl.bit -of {{name}}.svf
""", """,

View file

@ -140,14 +140,14 @@ class LatticeICE40Platform(TemplatedPlatform):
} }
_icestorm_command_templates = [ _icestorm_command_templates = [
r""" r"""
{{get_tool("yosys")}} {{invoke_tool("yosys")}}
{{quiet("-q")}} {{quiet("-q")}}
{{get_override("yosys_opts")|options}} {{get_override("yosys_opts")|options}}
-l {{name}}.rpt -l {{name}}.rpt
{{name}}.ys {{name}}.ys
""", """,
r""" r"""
{{get_tool("nextpnr-ice40")}} {{invoke_tool("nextpnr-ice40")}}
{{quiet("--quiet")}} {{quiet("--quiet")}}
{{get_override("nextpnr_opts")|options}} {{get_override("nextpnr_opts")|options}}
--log {{name}}.tim --log {{name}}.tim
@ -160,7 +160,7 @@ class LatticeICE40Platform(TemplatedPlatform):
--asc {{name}}.asc --asc {{name}}.asc
""", """,
r""" r"""
{{get_tool("icepack")}} {{invoke_tool("icepack")}}
{{verbose("-v")}} {{verbose("-v")}}
{{name}}.asc {{name}}.asc
{{name}}.bin {{name}}.bin

View file

@ -106,17 +106,17 @@ class LatticeMachXO2Platform(TemplatedPlatform):
command_templates = [ command_templates = [
# These don't have any usable command-line option overrides. # These don't have any usable command-line option overrides.
r""" r"""
{{get_tool("pnmainc")}} {{invoke_tool("pnmainc")}}
{{name}}.tcl {{name}}.tcl
""", """,
r""" r"""
{{get_tool("ddtcmd")}} {{invoke_tool("ddtcmd")}}
-oft -jed -oft -jed
-dev {{platform.device}}-{{platform.speed}}{{platform.package}}{{platform.grade}} -dev {{platform.device}}-{{platform.speed}}{{platform.package}}{{platform.grade}}
-if {{name}}_impl/{{name}}_impl.jed -of {{name}}.jed -if {{name}}_impl/{{name}}_impl.jed -of {{name}}.jed
""", """,
r""" r"""
{{get_tool("ddtcmd")}} {{invoke_tool("ddtcmd")}}
-oft -svfsingle -revd -op "FLASH Erase,Program,Verify" -oft -svfsingle -revd -op "FLASH Erase,Program,Verify"
-if {{name}}_impl/{{name}}_impl.jed -of {{name}}.svf -if {{name}}_impl/{{name}}_impl.jed -of {{name}}.svf
""", """,

View file

@ -139,7 +139,7 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
} }
command_templates = [ command_templates = [
r""" r"""
{{get_tool("vivado")}} {{invoke_tool("vivado")}}
{{verbose("-verbose")}} {{verbose("-verbose")}}
{{get_override("vivado_opts")|options}} {{get_override("vivado_opts")|options}}
-mode batch -mode batch

View file

@ -141,12 +141,12 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
} }
command_templates = [ command_templates = [
r""" r"""
{{get_tool("xst")}} {{invoke_tool("xst")}}
{{get_override("xst_opts")|options}} {{get_override("xst_opts")|options}}
-ifn {{name}}.xst -ifn {{name}}.xst
""", """,
r""" r"""
{{get_tool("ngdbuild")}} {{invoke_tool("ngdbuild")}}
{{quiet("-quiet")}} {{quiet("-quiet")}}
{{verbose("-verbose")}} {{verbose("-verbose")}}
{{get_override("ngdbuild_opts")|options}} {{get_override("ngdbuild_opts")|options}}
@ -154,7 +154,7 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
{{name}}.ngc {{name}}.ngc
""", """,
r""" r"""
{{get_tool("map")}} {{invoke_tool("map")}}
{{verbose("-detail")}} {{verbose("-detail")}}
{{get_override("map_opts")|default([])|options}} {{get_override("map_opts")|default([])|options}}
-w -w
@ -163,7 +163,7 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
{{name}}.pcf {{name}}.pcf
""", """,
r""" r"""
{{get_tool("par")}} {{invoke_tool("par")}}
{{get_override("par_opts")|default([])|options}} {{get_override("par_opts")|default([])|options}}
-w -w
{{name}}_map.ncd {{name}}_map.ncd
@ -171,7 +171,7 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
{{name}}.pcf {{name}}.pcf
""", """,
r""" r"""
{{get_tool("bitgen")}} {{invoke_tool("bitgen")}}
{{get_override("bitgen_opts")|default(["-g Compress"])|options}} {{get_override("bitgen_opts")|default(["-g Compress"])|options}}
-w -w
-g Binary:Yes -g Binary:Yes

View file

@ -139,7 +139,7 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
} }
command_templates = [ command_templates = [
r""" r"""
{{get_tool("vivado")}} {{invoke_tool("vivado")}}
{{verbose("-verbose")}} {{verbose("-verbose")}}
{{get_override("vivado_opts")|options}} {{get_override("vivado_opts")|options}}
-mode batch -mode batch