def _getFlags(self, path, scope): # type: (Path, BuildFlagScope) -> BuildFlags """ Gets flags to build the path, both builder based and from the database. If a build is forced, assume we're building a single file (not its dependencies) """ return tuple(self._database.getFlags(path, scope)) + tuple( self.default_flags.get(scope, {}).get(FileType.fromPath(path), ()) + self.default_flags. get(BuildFlagScope.all, {}).get(FileType.fromPath(path), ()))
def addSource(self, path, library, single_flags=None, dependencies_flags=None): # type: (Path, Optional[str], Optional[BuildFlags], Optional[BuildFlags]) -> None """ Adds a source to the database, triggering its parsing even if the source has already been added previously """ _logger.info( "Adding %s, library=%s, flags=(single=%s, dependencies=%s)", path, library, single_flags, dependencies_flags, ) self._paths.add(path) self._flags_map[path] = { BuildFlagScope.single: tuple(single_flags or ()), BuildFlagScope.dependencies: tuple(dependencies_flags or ()), } if library is not None: self._library_map[path] = Identifier( library, case_sensitive=FileType.fromPath(path) != FileType.vhdl ) # TODO: Parse on a process pool self._parseSource(path)
def getSourceParserFromPath( path): # type: (Path) -> Union[VhdlParser, VerilogParser] """ Returns either a VhdlParser or VerilogParser based on the path's file extension """ return PARSERS[FileType.fromPath(path)](path)
def __init__(self, filename): # type: (Path, ) -> None assert isinstance(filename, Path), "Invalid type: {}".format(filename) self.filename = filename self._cache = {} # type: Dict[str, Any] self._content = None # type: Optional[str] self._mtime = 0 # type: Optional[float] self.filetype = FileType.fromPath(self.filename) self._dependencies = None # type: Optional[Set[BaseDependencySpec]] self._design_units = None # type: Optional[Set[tAnyDesignUnit]] self._libraries = None
def _buildSource(self, path, library, flags=None): # type: (Path, Identifier, Optional[BuildFlags]) -> Iterable[str] filetype = FileType.fromPath(path) if filetype == FileType.vhdl: return self._buildVhdl(path, library, flags) if filetype in (FileType.verilog, FileType.systemverilog): return self._buildVerilog(path, library, flags) self._logger.error( # pragma: no cover "Unknown file type %s for path '%s'", filetype, path) return "" # Just to satisfy pylint
def build(self, path, library, scope, forced=False): # type: (Path, Identifier, BuildFlagScope, bool) -> Tuple[Set[CheckerDiagnostic], Set[RebuildInfo]] """ Method that interfaces with parents and implements the building chain """ if not self._isFileTypeSupported(path): self._logger.warning( "Path '%s' with file type '%s' is not " "supported", path, FileType.fromPath(path), ) return set(), set() if path not in self._build_info_cache: self._build_info_cache[path] = { "compile_time": 0.0, "diagnostics": [], "rebuilds": [], } cached_info = self._build_info_cache[path] build = False if forced: build = True self._logger.info("Forcing build of %s", str(path)) elif path.mtime > cached_info["compile_time"]: build = True self._logger.info("Building %s", str(path)) if build: with self._lock: diagnostics, rebuilds = self._buildAndGetDiagnostics( path, library, self._getFlags(path, scope)) cached_info["diagnostics"] = diagnostics cached_info["rebuilds"] = rebuilds cached_info["compile_time"] = path.mtime if DiagType.ERROR in [x.severity for x in diagnostics]: cached_info["compile_time"] = 0 else: self._logger.debug("Nothing to do for %s", path) diagnostics = cached_info["diagnostics"] rebuilds = cached_info["rebuilds"] return diagnostics, rebuilds
def findRtlSourcesByPath(path): # type: (Path) -> Iterable[Path] """ Finds RTL sources (files with extensions within FileType enum) inside <path> """ for dirpath, _, filenames in os.walk(path.name): for filename in filenames: full_path = Path(p.join(dirpath, filename)) if not p.isfile(full_path.name): continue try: # FileType.fromPath will fail if the file's extension is not # valid (one of '.vhd', '.vhdl', '.v', '.vh', '.sv', # '.svh') FileType.fromPath(full_path) except UnknownTypeExtension: continue if isFileReadable(full_path.name): yield full_path
def _expand(config, ref_path): # type: (Dict[str, Any], str) -> Iterable[SourceEntry] """ Expands the sources defined in the config dict into a list of tuples """ flags = {} for filetype in FileType: filetype_cfg = config.pop(filetype.value, {}).pop("flags", {}) flags[filetype] = ( filetype_cfg.get(BuildFlagScope.single.value, ()), filetype_cfg.get(BuildFlagScope.dependencies.value, ()), filetype_cfg.get(BuildFlagScope.all.value, ()), ) sources = config.pop("sources", None) # If no sources were defined, search ref_path if sources is None: _logger.debug("No sources found, will search %s", ref_path) sources = (x.name for x in findRtlSourcesByPath(Path(ref_path))) for entry in sources: source = JsonSourceEntry.make(entry) path_expr = ( source.path_expr if p.isabs(source.path_expr) else p.join(ref_path, source.path_expr) ) for _path in glob(path_expr): path = Path(_path, ref_path) try: filetype = FileType.fromPath(path) except UnknownTypeExtension: _logger.warning("Won't include non RTL file '%s'", path) continue single_flags = flags[filetype][0] dependencies_flags = flags[filetype][1] global_flags = flags[filetype][2] yield SourceEntry( path, source.library, tuple(global_flags) + tuple(single_flags) + tuple(source.flags), tuple(global_flags) + tuple(dependencies_flags), )
def _getExtraFlags(self, path): # type: (Path) -> Iterable[str] """ Gets extra flags configured for the specific language """ self._logger.debug("Getting flags for %s", path) lang = FileType.fromPath(path) if lang is FileType.systemverilog: lang = FileType.verilog libs = [] # type: List[str] for library in self._added_libraries | self._external_libraries[lang]: libs = ["-L", library.name] for incdir in self._getIncludesForPath(path): libs += ["+incdir+" + incdir] return libs
def __init__( self, design_units, # type: Iterable[Dict[str, str]] library=None, # type: str dependencies=None, # type: Iterable[MockDep] filename=None, # type: Optional[str] ): self._design_units = list(design_units or []) if filename is not None: self._filename = Path(p.join(self.base_path, filename)) else: library = "lib_not_set" if library is None else library self._filename = Path( p.join( self.base_path, library, "_{}.vhd".format(self._design_units[0]["name"]), )) self.filetype = FileType.fromPath(self.filename) # self.abspath = p.abspath(self.filename) self.flags = [] # type: ignore self.library = library self._dependencies = [] # type: List[RequiredDesignUnit] for dep_spec in dependencies or []: _name = dep_spec[0] _library = "work" try: _library, _name = dep_spec # type: ignore except ValueError: pass self._dependencies.append( RequiredDesignUnit( self._filename, Identifier(_name, False), Identifier(_library, False), )) self._createMockFile()
def _buildVerilog(self, path, library, flags=None): # type: (Path, Identifier, Optional[BuildFlags]) -> Iterable[str] "Builds a Verilog/SystemVerilog file" cmd = [ "vlog", "-modelsimini", self._modelsim_ini.name, "-quiet", "-work", p.join(self._work_folder, library.name), ] if FileType.fromPath(path) == FileType.systemverilog: cmd += ["-sv"] if flags: # pragma: no cover cmd += flags cmd += self._getExtraFlags(path) cmd += [path.name] return runShellCommand(cmd)
def _isFileTypeSupported(self, path): # type: (Path) -> bool """ Checks if a given path is supported by this builder """ return FileType.fromPath(path) in self.file_types