f4pga/sfbuild: get INSTALL_DIR from environ

Signed-off-by: Unai Martinez-Corral <umartinezcorral@antmicro.com>
This commit is contained in:
Unai Martinez-Corral 2022-03-02 01:48:00 +01:00
parent 898eab8232
commit 72913daac2
1 changed files with 37 additions and 36 deletions

View File

@ -23,6 +23,7 @@ such as list of source code files.
from argparse import Namespace from argparse import Namespace
import os import os
from os import environ
import json import json
from typing import Iterable from typing import Iterable
from colorama import Fore, Style from colorama import Fore, Style
@ -45,7 +46,7 @@ mypath = os.path.realpath(os.sys.argv[0])
mypath = os.path.dirname(mypath) mypath = os.path.dirname(mypath)
binpath = os.path.realpath(os.path.join(mypath, '..')) binpath = os.path.realpath(os.path.join(mypath, '..'))
share_dir_path = os.path.realpath(os.path.join(mypath, '../../share/symbiflow')) share_dir_path = os.path.realpath(f"{environ.get('INSTALL_DIR', '/usr/local')}/xc7/install/share/symbiflow")
class DependencyNotProducedException(Exception): class DependencyNotProducedException(Exception):
dep_name: str dep_name: str
@ -54,7 +55,7 @@ class DependencyNotProducedException(Exception):
def __init__(self, dep_name: str, provider: str): def __init__(self, dep_name: str, provider: str):
self.dep_name = dep_name self.dep_name = dep_name
self.provider = provider self.provider = provider
def __str__(self) -> str: def __str__(self) -> str:
return f'Stage `{self.provider}` did not produce promised ' \ return f'Stage `{self.provider}` did not produce promised ' \
f'dependency `{self.dep_name}`' f'dependency `{self.dep_name}`'
@ -69,10 +70,10 @@ def platform_stages(platform_flow, r_env):
for stage_name, modulestr in platform_flow['stages'].items(): for stage_name, modulestr in platform_flow['stages'].items():
mod_opts = stage_options.get(stage_name) if stage_options else None mod_opts = stage_options.get(stage_name) if stage_options else None
yield Stage(stage_name, modulestr, mod_opts, r_env) yield Stage(stage_name, modulestr, mod_opts, r_env)
def req_exists(r): def req_exists(r):
""" Checks whether a dependency exists on a drive. """ """ Checks whether a dependency exists on a drive. """
if type(r) is str: if type(r) is str:
if not os.path.isfile(r) and not os.path.islink(r) \ if not os.path.isfile(r) and not os.path.islink(r) \
and not os.path.isdir(r): and not os.path.isdir(r):
@ -121,21 +122,21 @@ def prepare_stage_input(stage: Stage, platform_name: str, values: dict,
paths = dep_paths.get(take.name) paths = dep_paths.get(take.name)
if paths: # Some takes may be not required if paths: # Some takes may be not required
takes[take.name] = paths takes[take.name] = paths
produces = {} produces = {}
for prod in stage.produces: for prod in stage.produces:
if dep_paths.get(prod.name): if dep_paths.get(prod.name):
produces[prod.name] = dep_paths[prod.name] produces[prod.name] = dep_paths[prod.name]
elif config_paths.get(prod.name): elif config_paths.get(prod.name):
produces[prod.name] = config_paths[prod.name] produces[prod.name] = config_paths[prod.name]
stage_mod_cfg = { stage_mod_cfg = {
'takes': takes, 'takes': takes,
'produces': produces, 'produces': produces,
'values': values, 'values': values,
'platform': platform_name, 'platform': platform_name,
} }
return stage_mod_cfg return stage_mod_cfg
def update_dep_statuses(paths, consumer: str, symbicache: SymbiCache): def update_dep_statuses(paths, consumer: str, symbicache: SymbiCache):
@ -154,7 +155,7 @@ def dep_differ(paths, consumer: str, symbicache: SymbiCache):
Check if a dependency differs from its last version, lack of dependency is Check if a dependency differs from its last version, lack of dependency is
treated as "differs" treated as "differs"
""" """
if type(paths) is str: if type(paths) is str:
s = symbicache.get_status(paths, consumer) s = symbicache.get_status(paths, consumer)
if s == 'untracked': if s == 'untracked':
@ -198,7 +199,7 @@ class Flow:
# Dependendecy to build # Dependendecy to build
target: str target: str
# Values in global scope # Values in global scope
cfg: FlowConfig cfg: FlowConfig
# dependency-producer map # dependency-producer map
os_map: 'dict[str, Stage]' os_map: 'dict[str, Stage]'
@ -228,14 +229,14 @@ class Flow:
self.deps_rebuilds = {} self.deps_rebuilds = {}
self._resolve_dependencies(self.target, set()) self._resolve_dependencies(self.target, set())
def _dep_will_differ(self, dep: str, paths, consumer: str): def _dep_will_differ(self, dep: str, paths, consumer: str):
if not self.symbicache: # Handle --nocache mode if not self.symbicache: # Handle --nocache mode
return True return True
return dep_will_differ(dep, paths, consumer, return dep_will_differ(dep, paths, consumer,
self.os_map, self.run_stages, self.os_map, self.run_stages,
self.symbicache) self.symbicache)
def _resolve_dependencies(self, dep: str, stages_checked: 'set[str]'): def _resolve_dependencies(self, dep: str, stages_checked: 'set[str]'):
# Initialize the dependency status if necessary # Initialize the dependency status if necessary
if self.deps_rebuilds.get(dep) is None: if self.deps_rebuilds.get(dep) is None:
@ -251,7 +252,7 @@ class Flow:
# TODO: Check if the dependency is "on-demand" and force it in provider's # TODO: Check if the dependency is "on-demand" and force it in provider's
# config if it is. # config if it is.
for take in provider.takes: for take in provider.takes:
self._resolve_dependencies(take.name, stages_checked) self._resolve_dependencies(take.name, stages_checked)
# If any of the required dependencies is unavailable, then the # If any of the required dependencies is unavailable, then the
@ -263,17 +264,17 @@ class Flow:
if not take_paths and take.spec == 'req': if not take_paths and take.spec == 'req':
_print_unreachable_stage_message(provider, take) _print_unreachable_stage_message(provider, take)
return return
if self._dep_will_differ(take.name, take_paths, provider.name): if self._dep_will_differ(take.name, take_paths, provider.name):
sfprint(2, f'{take.name} is causing rebuild for {provider.name}') sfprint(2, f'{take.name} is causing rebuild for {provider.name}')
self.run_stages.add(provider.name) self.run_stages.add(provider.name)
self.deps_rebuilds[take.name] += 1 self.deps_rebuilds[take.name] += 1
stage_values = self.cfg.get_r_env(provider.name).values stage_values = self.cfg.get_r_env(provider.name).values
modrunctx = config_mod_runctx(provider, self.cfg.platform, modrunctx = config_mod_runctx(provider, self.cfg.platform,
stage_values, self.dep_paths, stage_values, self.dep_paths,
self.cfg.get_dependency_overrides()) self.cfg.get_dependency_overrides())
outputs = module_map(provider.module, modrunctx) outputs = module_map(provider.module, modrunctx)
stages_checked.add(provider.name) stages_checked.add(provider.name)
@ -282,7 +283,7 @@ class Flow:
for _, out_paths in outputs.items(): for _, out_paths in outputs.items():
if (out_paths is not None) and not (req_exists(out_paths)): if (out_paths is not None) and not (req_exists(out_paths)):
self.run_stages.add(provider.name) self.run_stages.add(provider.name)
# Verify module's outputs and add paths as values. # Verify module's outputs and add paths as values.
outs = outputs.keys() outs = outputs.keys()
# print(outs) # print(outs)
@ -303,7 +304,7 @@ class Flow:
provider.value_overrides[dep_value_str(o.name)] = \ provider.value_overrides[dep_value_str(o.name)] = \
outputs.get(o.name) outputs.get(o.name)
def print_resolved_dependencies(self, verbosity: int): def print_resolved_dependencies(self, verbosity: int):
deps = list(self.deps_rebuilds.keys()) deps = list(self.deps_rebuilds.keys())
deps.sort() deps.sort()
@ -333,7 +334,7 @@ class Flow:
status = Fore.RED + '[U]' + Fore.RESET status = Fore.RED + '[U]' + Fore.RESET
source = \ source = \
f'{Fore.BLUE + self.os_map[dep].name + Fore.RESET} -> ???' f'{Fore.BLUE + self.os_map[dep].name + Fore.RESET} -> ???'
sfprint(verbosity, f' {Style.BRIGHT + status} ' sfprint(verbosity, f' {Style.BRIGHT + status} '
f'{dep + Style.RESET_ALL}: {source}') f'{dep + Style.RESET_ALL}: {source}')
@ -344,12 +345,12 @@ class Flow:
if not paths: if not paths:
sfprint(2, f'Dependency {dep} is unresolved.') sfprint(2, f'Dependency {dep} is unresolved.')
return False return False
if req_exists(paths) and not run: if req_exists(paths) and not run:
return True return True
else: else:
assert(provider) assert(provider)
any_dep_differ = False if self.symbicache else True any_dep_differ = False if self.symbicache else True
for p_dep in provider.takes: for p_dep in provider.takes:
if not self._build_dep(p_dep.name): if not self._build_dep(p_dep.name):
@ -360,7 +361,7 @@ class Flow:
any_dep_differ |= \ any_dep_differ |= \
update_dep_statuses(self.dep_paths[p_dep.name], update_dep_statuses(self.dep_paths[p_dep.name],
provider.name, self.symbicache) provider.name, self.symbicache)
# If dependencies remained the same, consider the dep as up-to date # If dependencies remained the same, consider the dep as up-to date
# For example, when changing a comment in Verilog source code, # For example, when changing a comment in Verilog source code,
# the initial dependency resolution will report a need for complete # the initial dependency resolution will report a need for complete
@ -372,7 +373,7 @@ class Flow:
f'{Style.BRIGHT + dep + Style.RESET_ALL}` because all ' f'{Style.BRIGHT + dep + Style.RESET_ALL}` because all '
f'of it\'s dependencies remained unchanged') f'of it\'s dependencies remained unchanged')
return True return True
stage_values = self.cfg.get_r_env(provider.name).values stage_values = self.cfg.get_r_env(provider.name).values
modrunctx = config_mod_runctx(provider, self.cfg.platform, modrunctx = config_mod_runctx(provider, self.cfg.platform,
stage_values, self.dep_paths, stage_values, self.dep_paths,
@ -380,12 +381,12 @@ class Flow:
module_exec(provider.module, modrunctx) module_exec(provider.module, modrunctx)
self.run_stages.discard(provider.name) self.run_stages.discard(provider.name)
if not req_exists(paths): if not req_exists(paths):
raise DependencyNotProducedException(dep, provider.name) raise DependencyNotProducedException(dep, provider.name)
return True return True
def execute(self): def execute(self):
self._build_dep(self.target) self._build_dep(self.target)
if self.symbicache: if self.symbicache:
@ -402,7 +403,7 @@ def display_dep_info(stages: 'Iterable[Stage]'):
l = len(out.name) l = len(out.name)
if l > longest_out_name_len: if l > longest_out_name_len:
longest_out_name_len = l longest_out_name_len = l
desc_indent = longest_out_name_len + 7 desc_indent = longest_out_name_len + 7
nl_indentstr = '\n' nl_indentstr = '\n'
for _ in range(0, desc_indent): for _ in range(0, desc_indent):
@ -418,9 +419,9 @@ def display_dep_info(stages: 'Iterable[Stage]'):
if out.spec == 'req': if out.spec == 'req':
specstr = f'{Fore.BLUE}guaranteed{Fore.RESET}' specstr = f'{Fore.BLUE}guaranteed{Fore.RESET}'
elif out.spec == 'maybe': elif out.spec == 'maybe':
specstr = f'{Fore.YELLOW}not guaranteed{Fore.RESET}' specstr = f'{Fore.YELLOW}not guaranteed{Fore.RESET}'
elif out.spec == 'demand': elif out.spec == 'demand':
specstr = f'{Fore.RED}on-demand{Fore.RESET}' specstr = f'{Fore.RED}on-demand{Fore.RESET}'
pgen = f'{Style.DIM}stage: `{stage.name}`, '\ pgen = f'{Style.DIM}stage: `{stage.name}`, '\
f'spec: {specstr}{Style.RESET_ALL}' f'spec: {specstr}{Style.RESET_ALL}'
pdesc = stage.meta[out.name].replace('\n', nl_indentstr) pdesc = stage.meta[out.name].replace('\n', nl_indentstr)
@ -432,7 +433,7 @@ def display_stage_info(stage: Stage):
sfprint(0, f'Stage does not exist') sfprint(0, f'Stage does not exist')
sfbuild_fail() sfbuild_fail()
return return
sfprint(0, f'Stage `{Style.BRIGHT}{stage.name}{Style.RESET_ALL}`:') sfprint(0, f'Stage `{Style.BRIGHT}{stage.name}{Style.RESET_ALL}`:')
sfprint(0, f' Module: `{Style.BRIGHT}{stage.module.name}{Style.RESET_ALL}`') sfprint(0, f' Module: `{Style.BRIGHT}{stage.module.name}{Style.RESET_ALL}`')
sfprint(0, f' Module info:') sfprint(0, f' Module info:')
@ -481,13 +482,13 @@ def verify_platform_stage_params(flow_cfg: FlowConfig,
if args.platform not in flow_cfg.platforms(): if args.platform not in flow_cfg.platforms():
sfprint(0, f'Platform `{platform}`` is not in project.') sfprint(0, f'Platform `{platform}`` is not in project.')
return False return False
if stage: if stage:
if not verify_stage(platform, stage, mypath): if not verify_stage(platform, stage, mypath):
sfprint(0, f'Stage `{stage}` is invalid.') sfprint(0, f'Stage `{stage}` is invalid.')
sfbuild_fail() sfbuild_fail()
return False return False
return True return True
def get_platform_name_for_part(part_name: str): def get_platform_name_for_part(part_name: str):
@ -506,7 +507,7 @@ def cmd_build(args: Namespace):
""" sfbuild's `build` command implementation """ """ sfbuild's `build` command implementation """
project_flow_cfg: ProjectFlowConfig = None project_flow_cfg: ProjectFlowConfig = None
platform = args.platform platform = args.platform
if platform is None: if platform is None:
@ -596,7 +597,7 @@ def cmd_show_dependencies(args: Namespace):
if not verify_platform_stage_params(flow_cfg, args.platform): if not verify_platform_stage_params(flow_cfg, args.platform):
sfbuild_fail() sfbuild_fail()
return return
platform_overrides: 'set | None' = None platform_overrides: 'set | None' = None
if args.platform is not None: if args.platform is not None:
platform_overrides = \ platform_overrides = \
@ -613,14 +614,14 @@ def cmd_show_dependencies(args: Namespace):
f'{Style.BRIGHT + dep_name + Style.RESET_ALL}: {dep_paths}' f'{Style.BRIGHT + dep_name + Style.RESET_ALL}: {dep_paths}'
else: else:
prstr = f'{Style.BRIGHT + dep_name + Style.RESET_ALL}: {dep_paths}' prstr = f'{Style.BRIGHT + dep_name + Style.RESET_ALL}: {dep_paths}'
display_list.append((dep_name, prstr)) display_list.append((dep_name, prstr))
display_list.sort(key = lambda p: p[0]) display_list.sort(key = lambda p: p[0])
for _, prstr in display_list: for _, prstr in display_list:
sfprint(0, prstr) sfprint(0, prstr)
set_verbosity_level(-1) set_verbosity_level(-1)
if __name__ == '__main__': if __name__ == '__main__':