VUnit / vunit

VUnit is a unit testing framework for VHDL/SystemVerilog
http://vunit.github.io/
Other
721 stars 258 forks source link

failed to find a primary design unit 'all' #857

Open asicnet opened 2 years ago

asicnet commented 2 years ago

Hi we have big designs with a lot of this warnings

WARNING - /sim_lib/xxxxxxx.vhd: failed to find a  primary design unit 'all' in library 'yyyyyyy'

the syntax is use library_name.package_name.all;

but a lot of designer use it for the library itself

use library_name.all;

For the compiler is this no problem. I think no desinger create a " package all is ...."

so is it possible to change within the project.py

def _find_other_vhdl_design_unit_dependencies()
...
        try:
            primary_unit = library.primary_design_units[ref.design_unit]
        except KeyError:
            **if ref.design_unit != 'all':**
              if not library.is_external:
                LOGGER.warning(
                    "%s: failed to find a **reference** design unit '%s' in library '%s'",

def _find_primary_secondary_design_unit_dependencies()
....
        try:
            primary_unit = library.primary_design_units[unit.primary_design_unit]
        except KeyError:
          **if unit.primary_design_unit != 'all':**
            LOGGER.warning( .......
LarsAsplund commented 2 years ago

@asicnet This is something that we've discussed before but I failed to find where. When you know what package the file depends on then you also know what file it depends on (the one defining the package) and then you have a dependency = compile order between those files. When you depend on everything in a library you can't simply find out what files you depend on and what a correct compile order is. That requires a much better parser than the regexp analysis VUnit is using.

asicnet commented 1 year ago

Hi it's just a warning, but I'm full of them if it comes from generated code or from someone else's. Then I no longer see the warnings that are really interesting. Therefore the suggestion to prevent the "all" or to install a cmd-line option to suppress it.

LarsAsplund commented 1 year ago

When VUnit sees use a.b it thinks b is a design unit in library a. It represents a situation like this

use ieee.std_logic_1144; -- This is legal
...
signal foo : std_logic_1164.std_logic; -- but forces you to be more explicit when things are used from std_logic_1164

Without any support for use my_library.all, all will be treated as a design unit that is not found in my_library and a warning is issued. Since all is a reserved word in VHDL it would be easy for VUnit to detect this case and have a better warning message.

When you say "prevent" do you mean preventing this specific warning from ever be produced or do you mean VUnit shouldn't allow you to have such references at all? I guess you mean the first as the second wouldn't solve the problem. Generally speaking we recognize that there are legal VHDL styles that we do not support because it requires too much parsing. We do not forbid them because they are legal. Instead we provide workarounds to deal with those situations, in this case the workaround is to use the add_dependency_on method to explicitly define the dependencies that the VHDL developer/producer was too lazy to do. Are you doing that or is all only used with pre-compiled libraries?

Another approach would be to automatically create a dependency between the file containing use my_library.all and all of my_library, i.e. all files compiled into that library. This is after all what the VHDL statement says. I don't think that is a great idea since it promotes a style which, if used to heavily, means that everything depends on everything. If that is the case we lose incremental compilation or we might not even know how to compile due to perceived circular dependencies

Suppression would be an option (once the problem has been dealt with) but this is too much corner case-ish to be awarded an option in the command line. In that case it would be a configuration that can be set in the run script.

asicnet commented 1 year ago

Hi The main problem is only the big count of the same warning messages. It will be good only suppress the warning that arises because of "use my_lib.all;" and that is very often seen with generated and foreign code. And "use my_lib.all;" has no effect.

In an other case i define a dict within init , count the same warnings and suppress this warning after 3 occurrences, because I then know the problem and do not overlook other important warnings. Maybe this is an acceptable implementation for you.

Example:

def __init__(...)..
 self.cnt={}

def _find_other_vhdl_design_unit_dependencies( 
    self, source_file, depend_on_package_body, implementation_dependencies
):
    """
    Iterate over the dependencies on other design unit of the source_file
    """
    for ref in source_file.dependencies:
        try:
            library = self._find_vhdl_library_reference(ref.library)
        except KeyError:
            if ref.library not in self._builtin_libraries:

              try: self.cnt[ref.library]+=1
              except:self.cnt[ref.library]=1
              if self.cnt[ref.library]<4:
                LOGGER.warning("%s: failed to find library '%s'", source_file.name, ref.library) 
              if self.cnt[ref.library]==4:
                LOGGER.warning("More failed to find library '%s' suppressed", ref.library)
            #  ----------------------------------------------------    
            continue
LarsAsplund commented 1 year ago

@asicnet

What about this solution. The logger in project.py is public (although not documented) so you can apply a logger filter with an arbitrary rule for message suppression. For example:

from logging import Filter
from vunit.project import LOGGER

class MyFilter(Filter):
    def __init__(self):
        self._warning_count = 0

    def filter(self, record):
        if "failed to find a primary design unit 'all'" in record.getMessage():
            self._warning_count += 1
            if self._warning_count > 3:
                return False
        return True

LOGGER.addFilter(MyFilter())