-
Notifications
You must be signed in to change notification settings - Fork 250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding csv mapping support for files and libraries #349
Conversation
vunit/ui.py
Outdated
for lib_name in libs_and_files.keys(): | ||
files = libs_and_files[lib_name] | ||
lib = self.add_library(lib_name) | ||
lib.add_source_files(files) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other functions that add files return the list of files added.
vunit/ui.py
Outdated
for row in content: | ||
if len(row) == 2: | ||
lib_name = row[0].strip() | ||
file_name = row[1].strip() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be reasonable to interpret the file name as relative to the location of the .csv file or an absolute path rather than relative to the current working directory when this code is executing,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I mean with the file name in this context is the file name that is written inside the csv file.
For example if a have the following structure:
/directory/proj.csv
/directory/file.vhd
/run.py
If proj.csv contains "lib, file.vhd" and I run "python run.py" in the root directory it should refer to /directory/proj.csv making the semantics of the proj.csv file independent on the current working directory where the run.py script is executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand what you want me to do, I just don't know how, can you please explain a little more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can achieve what I describe by.
from os.path import normpath, join, dirname
normpath(join(dirname(csv_file_name), file_name))
It will make file_name relative to the parent directory of the csv file unless file name is an absolute path already.
vunit/ui.py
Outdated
@@ -393,6 +394,36 @@ def add_external_library(self, library_name, path, vhdl_standard=None): | |||
self._project.add_library(library_name, abspath(path), vhdl_standard, is_external=True) | |||
return self.library(library_name) | |||
|
|||
def add_csv(self, project_csv_path, vhdl_standard=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add_source_files_from_csv would be a better name
vunit/ui.py
Outdated
@@ -393,6 +394,36 @@ def add_external_library(self, library_name, path, vhdl_standard=None): | |||
self._project.add_library(library_name, abspath(path), vhdl_standard, is_external=True) | |||
return self.library(library_name) | |||
|
|||
def add_csv(self, project_csv_path, vhdl_standard=None): | |||
""" | |||
Add a project configuration, mapping all the libraries and files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description does not describe the format of the csv file or the meaning of relative paths of the file names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some WIP related to a similar approach with JSON:
where the 'generic' run-py
contains:
- https://github.com/1138-4EB/vunit/blob/f67be68b6e8a114a69f1ac67dba92b6f79de11c2/examples/vhdl/array_axis_vcs/cfg_run.py#L16-L20
- https://github.com/1138-4EB/vunit/blob/f67be68b6e8a114a69f1ac67dba92b6f79de11c2/examples/vhdl/array_axis_vcs/cfg_run.py#L35-L48
and the example JSON itself is:
I'd be glad if the format/approach was explicitly documented, in order to follow the same pattern when I return to it.
vunit/ui.py
Outdated
@@ -422,7 +424,7 @@ def add_csv(self, project_csv_path, vhdl_standard=None): | |||
for lib_name in libs_and_files.keys(): | |||
files = libs_and_files[lib_name] | |||
lib = self.add_library(lib_name) | |||
lib.add_source_files(files) | |||
return lib.add_source_files(files) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bug: return inside for-loop only works for single library in the csv file
vunit/ui.py
Outdated
for lib_name in libs_and_files.keys(): | ||
files = libs_and_files[lib_name] | ||
lib = self.add_library(lib_name) | ||
return lib.add_source_files(files) | ||
list_of_source_files.append(lib.add_source_files(files)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will create a list of lists and not a single list of all files added.
vunit/ui.py
Outdated
@@ -426,7 +426,10 @@ def add_source_files_from_csv(self, project_csv_path, vhdl_standard=None): | |||
files = libs_and_files[lib_name] | |||
lib = self.add_library(lib_name) | |||
list_of_source_files.append(lib.add_source_files(files)) | |||
return list_of_source_files | |||
|
|||
list_of_source_files_flattened = [val for sublist in list_of_source_files for val in sublist] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+= would have been nicer. Also it seems this should have a unit test since there were so many bugs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there now. Some things left though.
vunit/test/unit/test_ui.py
Outdated
|
||
source_files = ui.add_source_files_from_csv('test_returns.csv') | ||
|
||
for i in range(len(source_files)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is flawed. source_files could just be empty or miss the last element and the test would still pass. Use list_of_files as the iteration length source instead. Or even better just compare the lists directly with self.assertEqual([source_file.name for source_file in source_files, list_of_files)
vunit/ui.py
Outdated
def add_source_files_from_csv(self, project_csv_path, vhdl_standard=None): | ||
""" | ||
Add a project configuration, mapping all the libraries and files | ||
:param project_csv_path: path to csv project specification, each line contains the name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation should also say that relative file names are relative to the parent folder of the csv file.
vunit/ui.py
Outdated
elif len(row) > 2: | ||
LOGGER.error("More than one library and one file in csv description") | ||
|
||
list_of_source_files = list() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
= SourceFileList()
Otherwise the return value will be a list() and not a SourceFileList like the documentation claims.
Good now you just have to fix the lint violations to make the Travis CI check pass.
|
vunit/test/unit/test_ui.py
Outdated
|
||
for index, library_name in enumerate(libraries): | ||
file_name = files[index] | ||
file_name_from_ui = ui.add_source_files_from_csv(file_name, library_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line does not make sense. You add the file_name as a csv file but the file is an empty vhdl_file.
Did you mean to do get_source_file?
vunit/test/unit/test_ui.py
Outdated
""" | ||
|
||
libraries = ['lib', 'lib1', 'lib2'] | ||
files = ['tb_example.vhdl', 'tb_example1.vhd', 'tb_example2.vhd', ' tb,ex3.vhd'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tb,ext3.vhd is unnessary?
vunit/ui.py
Outdated
lib = self.library(lib_name) if lib_name in libs else self.add_library(lib_name) | ||
libs.add(lib_name) | ||
file_ = lib.add_source_file(file_name_) | ||
if file_before is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This circumvents the dependency scanning performed by VUnit, why are you creating manual dependencies? VUnit will still can the files added for dependencies unless you add the no_parse argument to add_source_file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason you do not want to use the VUnit dependency scanning? Just having a linear dependency order is much worse. Since the order is linear some files later in the list will not depend on files further up in the list and thus it will cause unnecessary compilation. A compile order should be a tree and not a list.
vunit/ui.py
Outdated
@@ -393,6 +394,46 @@ def add_external_library(self, library_name, path, vhdl_standard=None): | |||
self._project.add_library(library_name, abspath(path), vhdl_standard, is_external=True) | |||
return self.library(library_name) | |||
|
|||
def add_source_files_from_csv(self, project_csv_path, vhdl_standard=None, is_in_order=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default should not be to disable the VUnit dependency scanning.
vunit/ui.py
Outdated
file_name_ = normpath(join(dirname(project_csv_path), no_normalized_file)) | ||
lib = self.library(lib_name) if lib_name in libs else self.add_library(lib_name) | ||
libs.add(lib_name) | ||
file_ = lib.add_source_file(file_name_, no_parse=is_in_order) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No parse will also inhibit any test_benches/tests from being detected from the source file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When sigasi generates the csv file, we resolve all dependencies in a way that the first file is a dependency for the next one, for example
lib, example.vhd
lib2, example2.vhd // This one depends on lib, example.vhd
lib, example3.vhd // This one depends on lib2, example2.vhd
lib3, example4.vhd // This one depends on lib, example3.vhd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dependencies are never linear they are a tree. To force them to be linear creates a lot of unnecessary re-compilation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider the case with 200 files with 20 groups of 10 files. Each group has a linear dependency but the groups are independent. If you can only express a linear order some group will be first and some group will be last. If a file in the first group is modified it causes 200 files to be recompiled instead of only 10.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigasi for sure has a dependency tree internally. It is only when you need to generate a sequence of compile commands for the initial compile that it is useful to generate an ordered list of files. For subsequent incremental compiles which is a big feature of VUnit a new ordered list of compile commands has to generated based on the files changes and the dependency tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In summary: I think skipping the VUnit dependency scanning in favor of a linear dependency list from Sigasi is a bad idea that will lead to worse re-compilation times. Also as the feature is implemented now it does not work since no_parse=True will also inhibit VUnit form recognizing any tests in the added files (which probably is not what you want). My recommendation would be to skip the is_in_order=True variant completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're planning to improve how Sigasi export the csv description. Right now we want a fist approach to the integration with Vunit. We're thinking to optimize the compile order generated by Sigasi in the near future
The function to get built in libraries should not be a part of this pull request. It should be reviewed separately. You need to use feature branches in your fork to separate the issues. |
This reverts commit 5470ab1.
vunit/ui.py
Outdated
@@ -393,6 +394,46 @@ def add_external_library(self, library_name, path, vhdl_standard=None): | |||
self._project.add_library(library_name, abspath(path), vhdl_standard, is_external=True) | |||
return self.library(library_name) | |||
|
|||
def add_source_files_from_csv(self, project_csv_path, vhdl_standard=None, is_in_order=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way is_in_order works now is just bad. VUnit will still scan all files for dependencies in addition to the sub-optimal linear dependency list enforced on top by is_in_order=True. I think you should remove the is_in_order option from this function as it does not make sense as implemented. I think the option should be removed and no manual dependency order defined.
No description provided.