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:
parent
29253295ee
commit
a783e4645d
|
@ -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 = {}
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
8
nmigen/vendor/intel.py
vendored
8
nmigen/vendor/intel.py
vendored
|
@ -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}}
|
||||||
""",
|
""",
|
||||||
|
|
12
nmigen/vendor/lattice_ecp5.py
vendored
12
nmigen/vendor/lattice_ecp5.py
vendored
|
@ -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
|
||||||
""",
|
""",
|
||||||
|
|
6
nmigen/vendor/lattice_ice40.py
vendored
6
nmigen/vendor/lattice_ice40.py
vendored
|
@ -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
|
||||||
|
|
6
nmigen/vendor/lattice_machxo2.py
vendored
6
nmigen/vendor/lattice_machxo2.py
vendored
|
@ -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
|
||||||
""",
|
""",
|
||||||
|
|
2
nmigen/vendor/xilinx_7series.py
vendored
2
nmigen/vendor/xilinx_7series.py
vendored
|
@ -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
|
||||||
|
|
10
nmigen/vendor/xilinx_spartan_3_6.py
vendored
10
nmigen/vendor/xilinx_spartan_3_6.py
vendored
|
@ -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
|
||||||
|
|
2
nmigen/vendor/xilinx_ultrascale.py
vendored
2
nmigen/vendor/xilinx_ultrascale.py
vendored
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue