diff --git a/vunit/project.py b/vunit/project.py index 89eaf6054..514faf150 100644 --- a/vunit/project.py +++ b/vunit/project.py @@ -42,6 +42,7 @@ def __init__(self, self._verilog_parser = verilog_parser self._libraries = {} self._source_files_in_order = [] + self._manual_dependencies = [] self._depend_on_components = depend_on_components self._depend_on_package_body = depend_on_package_body @@ -97,6 +98,12 @@ def add_source_file(self, file_name, library_name, file_type='vhdl', include_dir self._source_files_in_order.append(source_file) return source_file + def add_manual_dependency(self, source_file, depends_on): + """ + Add manual dependency where 'source_file' depends_on 'depends_on' + """ + self._manual_dependencies.append((source_file, depends_on)) + @staticmethod def _find_primary_secondary_design_unit_dependencies(source_file): """ @@ -257,6 +264,9 @@ def add_dependencies(dependency_function, files): if self._depend_on_components: add_dependencies(self._find_component_design_unit_dependencies, vhdl_files) + for source_file, depends_on in self._manual_dependencies: + add_dependency(depends_on, source_file) + return dependency_graph def get_files_in_compile_order(self, incremental=True): diff --git a/vunit/test/unit/test_project.py b/vunit/test/unit/test_project.py index ebe508357..e5ae334d7 100644 --- a/vunit/test/unit/test_project.py +++ b/vunit/test/unit/test_project.py @@ -759,6 +759,29 @@ def create_project(): module = create_project() self.assert_should_recompile([module]) + def test_manual_dependencies(self): + self.project.add_library("lib", "lib_path") + ent1 = self.add_source_file("lib", "ent1.vhd", """\ +entity ent1 is +end ent1; + +architecture arch of ent1 is +begin +end architecture; +""") + + ent2 = self.add_source_file("lib", "ent2.vhd", """\ +entity ent2 is +end ent2; + +architecture arch of ent2 is +begin +end architecture; +""") + + self.project.add_manual_dependency(ent2, depends_on=ent1) + self.assert_compiles(ent1, before=ent2) + def test_file_type_of(self): self.assertEqual(file_type_of("file.vhd"), "vhdl") self.assertEqual(file_type_of("file.vhdl"), "vhdl") diff --git a/vunit/test/unit/test_ui.py b/vunit/test/unit/test_ui.py index d67457fef..41f6f618b 100644 --- a/vunit/test/unit/test_ui.py +++ b/vunit/test/unit/test_ui.py @@ -206,6 +206,63 @@ def test_get_source_files_errors(self): self.assertRaisesRegexp(ValueError, ".*Found no file named.*%s.* in library 'lib1'" % non_existant_name, ui.get_source_file, non_existant_name, "lib1") + @mock.patch("vunit.project.Project.add_manual_dependency", autospec=True) + def test_add_single_file_manual_dependencies(self, add_manual_dependency): + # pylint: disable=protected-access + ui = self._create_ui() + lib = ui.library("lib") + file_name1 = self.create_entity_file(1) + file_name2 = self.create_entity_file(2) + file1 = lib.add_source_file(file_name1) + file2 = lib.add_source_file(file_name2) + + add_manual_dependency.assert_has_calls([]) + file1.depends_on(file2) + add_manual_dependency.assert_has_calls([ + mock.call(ui._project, + file1._source_file, + depends_on=file2._source_file)]) + + @mock.patch("vunit.project.Project.add_manual_dependency", autospec=True) + def test_add_multiple_file_manual_dependencies(self, add_manual_dependency): + # pylint: disable=protected-access + ui = self._create_ui() + lib = ui.library("lib") + self.create_file("foo1.vhd") + self.create_file("foo2.vhd") + self.create_file("foo3.vhd") + self.create_file("bar.vhd") + foo_files = lib.add_source_files("foo*.vhd") + bar_file = lib.add_source_file("bar.vhd") + + add_manual_dependency.assert_has_calls([]) + bar_file.depends_on(foo_files) + add_manual_dependency.assert_has_calls([ + mock.call(ui._project, + bar_file._source_file, + depends_on=foo_file._source_file) + for foo_file in foo_files]) + + @mock.patch("vunit.project.Project.add_manual_dependency", autospec=True) + def test_add_fileset_manual_dependencies(self, add_manual_dependency): + # pylint: disable=protected-access + ui = self._create_ui() + lib = ui.library("lib") + self.create_file("foo1.vhd") + self.create_file("foo2.vhd") + self.create_file("foo3.vhd") + self.create_file("bar.vhd") + foo_files = lib.add_source_files("foo*.vhd") + bar_file = lib.add_source_file("bar.vhd") + + add_manual_dependency.assert_has_calls([]) + foo_files.depends_on(bar_file) + add_manual_dependency.assert_has_calls([ + mock.call(ui._project, + foo_file._source_file, + depends_on=bar_file._source_file) + for foo_file in foo_files]) + def _test_pre_config_helper(self, retval, test_not_entity=False): """ Helper method to test pre_config where the pre config can return different values diff --git a/vunit/ui.py b/vunit/ui.py index b62232e2d..b5ea1f65e 100644 --- a/vunit/ui.py +++ b/vunit/ui.py @@ -280,7 +280,7 @@ def get_source_files(self, pattern="*", library_name=None, allow_empty=False): fnmatch(relpath(source_file.name), pattern)): continue - results.append(FileFacade(source_file)) + results.append(FileFacade(source_file, self._project)) if (not allow_empty) and len(results) == 0: raise ValueError(("Pattern %r did not match any file. " @@ -317,7 +317,8 @@ def add_source_file(self, file_name, library_name, preprocessors=None, include_d return FileFacade(self._project.add_source_file(file_name, library_name, file_type=file_type, - include_dirs=include_dirs)) + include_dirs=include_dirs), + self._project) def _preprocess(self, library_name, file_name, preprocessors): """ @@ -816,13 +817,21 @@ def set_compile_option(self, name, value): for source_file in self: source_file.set_compile_option(name, value) + def depends_on(self, source_file): + """ + Add manual dependency of these files on another + """ + for my_source_file in self: + my_source_file.depends_on(source_file) + class FileFacade(object): """ A single file """ - def __init__(self, source_file): + def __init__(self, source_file, project): self._source_file = source_file + self._project = project def set_compile_option(self, name, value): """ @@ -830,6 +839,20 @@ def set_compile_option(self, name, value): """ self._source_file.set_compile_option(name, value) + def depends_on(self, source_file): + """ + Add manual dependency of this file on another + """ + if isinstance(source_file, FileFacade): + private_source_file = source_file._source_file # pylint: disable=protected-access + self._project.add_manual_dependency(self._source_file, + depends_on=private_source_file) + elif hasattr(source_file, "__iter__"): + for element in source_file: + self.depends_on(element) + else: + raise ValueError(source_file) + def select_vhdl_standard(): """