opencos-eda 0.3.12__tar.gz → 0.3.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. {opencos_eda-0.3.12/opencos_eda.egg-info → opencos_eda-0.3.14}/PKG-INFO +1 -2
  2. opencos_eda-0.3.14/opencos/commands/flist.py +413 -0
  3. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/multi.py +4 -2
  4. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/sim.py +192 -8
  5. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/deps/deps_file.py +4 -1
  6. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/deps_schema.py +2 -2
  7. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda.py +12 -9
  8. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_base.py +39 -8
  9. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_config.py +37 -6
  10. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_config_defaults.yml +30 -5
  11. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_tool_helper.py +4 -4
  12. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/cocotb.py +0 -11
  13. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/invio.py +0 -6
  14. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/iverilog.py +17 -16
  15. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/modelsim_ase.py +0 -12
  16. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/quartus.py +21 -1
  17. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/questa.py +0 -14
  18. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/questa_common.py +54 -25
  19. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/questa_fe.py +0 -14
  20. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/questa_fse.py +0 -14
  21. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/riviera.py +104 -25
  22. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/slang.py +12 -9
  23. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/slang_yosys.py +0 -6
  24. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/surelog.py +11 -8
  25. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/tabbycad_yosys.py +1 -7
  26. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/verilator.py +18 -11
  27. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/vivado.py +92 -25
  28. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/yosys.py +8 -5
  29. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/util.py +14 -5
  30. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/str_helpers.py +4 -1
  31. {opencos_eda-0.3.12 → opencos_eda-0.3.14/opencos_eda.egg-info}/PKG-INFO +1 -2
  32. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos_eda.egg-info/requires.txt +0 -1
  33. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/pyproject.toml +1 -2
  34. opencos_eda-0.3.12/opencos/commands/flist.py +0 -230
  35. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/LICENSE +0 -0
  36. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/LICENSE.spdx +0 -0
  37. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/README.md +0 -0
  38. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/Architecture.md +0 -0
  39. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/ConnectingApps.md +0 -0
  40. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/DEPS.md +0 -0
  41. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/Debug.md +0 -0
  42. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/DirectoryStructure.md +0 -0
  43. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/Installation.md +0 -0
  44. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/OcVivadoTcl.md +0 -0
  45. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/OpenQuestions.md +0 -0
  46. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/README.md +0 -0
  47. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/RtlCodingStyle.md +0 -0
  48. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/eda.md +0 -0
  49. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/docs/oc_cli.md +0 -0
  50. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/__init__.py +0 -0
  51. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/_version.py +0 -0
  52. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/_waves_pkg.sv +0 -0
  53. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/__init__.py +0 -0
  54. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/build.py +0 -0
  55. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/deps_help.py +0 -0
  56. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/elab.py +0 -0
  57. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/export.py +0 -0
  58. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/lec.py +0 -0
  59. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/lint.py +0 -0
  60. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/open.py +0 -0
  61. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/proj.py +0 -0
  62. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/shell.py +0 -0
  63. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/sweep.py +0 -0
  64. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/synth.py +0 -0
  65. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/targets.py +0 -0
  66. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/upload.py +0 -0
  67. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/commands/waves.py +0 -0
  68. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/deps/__init__.py +0 -0
  69. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/deps/defaults.py +0 -0
  70. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/deps/deps_commands.py +0 -0
  71. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/deps/deps_processor.py +0 -0
  72. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_config_reduced.yml +0 -0
  73. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_deps_bash_completion.bash +0 -0
  74. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_deps_sanitize.py +0 -0
  75. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/eda_extract_targets.py +0 -0
  76. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/export_helper.py +0 -0
  77. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/export_json_convert.py +0 -0
  78. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/files.py +0 -0
  79. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/hw/__init__.py +0 -0
  80. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/hw/oc_cli.py +0 -0
  81. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/hw/pcie.py +0 -0
  82. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/names.py +0 -0
  83. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/peakrdl_cleanup.py +0 -0
  84. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/seed.py +0 -0
  85. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/__init__.py +0 -0
  86. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/invio_helpers.py +0 -0
  87. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/tools/invio_yosys.py +0 -0
  88. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/__init__.py +0 -0
  89. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/dict_helpers.py +0 -0
  90. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/markup_helpers.py +0 -0
  91. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/status_constants.py +0 -0
  92. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/subprocess_helpers.py +0 -0
  93. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/vscode_helper.py +0 -0
  94. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos/utils/vsim_helper.py +0 -0
  95. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos_eda.egg-info/SOURCES.txt +0 -0
  96. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos_eda.egg-info/dependency_links.txt +0 -0
  97. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos_eda.egg-info/entry_points.txt +0 -0
  98. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/opencos_eda.egg-info/top_level.txt +0 -0
  99. {opencos_eda-0.3.12 → opencos_eda-0.3.14}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencos-eda
3
- Version: 0.3.12
3
+ Version: 0.3.14
4
4
  Summary: A simple Python package for wrapping RTL simuliatons and synthesis
5
5
  Author-email: Simon Sabato <simon@cognichip.ai>, Drew Ranck <drew@cognichip.ai>
6
6
  Project-URL: Homepage, https://github.com/cognichip/opencos
@@ -20,7 +20,6 @@ Requires-Dist: supports_color>=0.2.0
20
20
  Provides-Extra: dev
21
21
  Requires-Dist: pylint>=3.0.0; extra == "dev"
22
22
  Requires-Dist: pytest>=8.3.5; extra == "dev"
23
- Requires-Dist: twine>=6.1.0; extra == "dev"
24
23
  Provides-Extra: cocotb
25
24
  Requires-Dist: cocotb>=2.0; extra == "cocotb"
26
25
  Requires-Dist: pytest>=8.3.5; extra == "cocotb"
@@ -0,0 +1,413 @@
1
+ '''opencos.commands.flist - Base class command handler for: eda flist ...
2
+
3
+ Intended to be overriden by Tool based classes (such as CommandFListVivado, etc).'''
4
+
5
+ # pylint: disable=too-many-branches
6
+ # pylint: disable=too-many-statements
7
+
8
+ import os
9
+ import shlex
10
+
11
+ from opencos import util, eda_config
12
+ from opencos.eda_base import CommandDesign, Tool
13
+ from opencos.utils.str_helpers import strip_all_quotes
14
+ from opencos.commands.sim import parameters_dict_get_command_list
15
+ from opencos.utils.str_helpers import strip_outer_quotes
16
+
17
+ class CommandFList(CommandDesign):
18
+ '''Base class command handler for: eda flist ...'''
19
+
20
+ command_name = 'flist'
21
+
22
+ def __init__(self, config: dict):
23
+ CommandDesign.__init__(self, config=config)
24
+
25
+ # If there's no tool attached, then we'll assume this flist is being created
26
+ # to run in `eda`, not some vendor tool.
27
+ self.flist_has_tool = isinstance(self, Tool)
28
+
29
+ self.flist_args = {
30
+ 'out' : "flist.out",
31
+ 'emit-define' : True,
32
+ 'emit-parameter' : True,
33
+ 'emit-incdir' : True,
34
+ 'emit-plusargs' : True,
35
+ 'emit-v' : True,
36
+ 'emit-sv' : True,
37
+ 'emit-vhd' : True,
38
+ 'emit-cpp' : True,
39
+ 'emit-non-sources' : True, # as comments, from DEPS 'reqs'
40
+ 'emit-eda-args' : not self.flist_has_tool, # no Tool means flist for eda.
41
+ 'prefix-define' : "+define+",
42
+ 'prefix-parameter' : "-G",
43
+ 'prefix-incdir' : "+incdir+",
44
+ 'prefix-plusargs' : "+",
45
+ 'prefix-v' : "",
46
+ 'prefix-sv' : "",
47
+ 'prefix-vhd' : "",
48
+ 'prefix-cpp' : "",
49
+ 'prefix-non-sources' : "", # as comments anyway.
50
+ # NOTE - the defaults are for creating an flist that is suitable for 'eda', which for
51
+ # defines means: optionally single-quote the entire thing, double-quote string values
52
+ # only.
53
+ # Tool classes should override if they want to set safe-mode-defines=True.
54
+ # Tool classes may also avoid these args entirely in their derived CommandFList class
55
+ 'safe-mode-defines' : not self.flist_has_tool, # no Tool
56
+ 'bracket-quote-define': False,
57
+ 'single-quote-define': False,
58
+ 'quote-define' : self.flist_has_tool, # Tool, this is NOT for eda.
59
+ 'equal-define' : True,
60
+ 'escape-define-value': False,
61
+ 'quote-define-value' : False,
62
+ 'bracket-quote-path' : False,
63
+ 'single-quote-path' : False,
64
+ 'double-quote-path' : False,
65
+ 'quote-path' : True,
66
+ 'build-script' : "", # we don't want this to error either
67
+
68
+ 'print-to-stdout': False,
69
+
70
+ # ex: eda flist --print-to-stdout --emit-rel-path --quiet <target>
71
+ 'emit-rel-path' : False,
72
+ }
73
+
74
+
75
+ self.args.update({
76
+ 'eda-dir' : 'eda.flist', # user can specify eda-dir if files are generated.
77
+ })
78
+ self.args.update(self.flist_args)
79
+
80
+ self.args_help.update({
81
+ 'print-to-stdout': "do not save file, print to stdout",
82
+ })
83
+
84
+ def process_tokens(
85
+ self, tokens: list , process_all: bool = True, pwd: str = os.getcwd()
86
+ ) -> list:
87
+ unparsed = CommandDesign.process_tokens(
88
+ self, tokens=tokens, process_all=process_all, pwd=pwd
89
+ )
90
+ if self.stop_process_tokens_before_do_it():
91
+ return unparsed
92
+
93
+ self.do_it()
94
+ return unparsed
95
+
96
+ def get_flist_dict(self) -> dict:
97
+ '''Returns dict of some internal class member vars, ignores args
98
+
99
+ Useful for an external caller to get details about this CommandDesign child
100
+ object without generating a .f file, or having to know specifics about the
101
+ class
102
+ '''
103
+ self.command_safe_set_tool_defines() # (Command.command_safe_set_tool_defines)
104
+
105
+ ret = {}
106
+ for key in ['files_sv', 'files_v', 'files_vhd', 'defines', 'incdirs',
107
+ 'parameters', 'unprocessed-plusargs']:
108
+ # These keys must exist, all are lists, defines is a dict
109
+ x = getattr(self, key, None)
110
+ if isinstance(x, (dict, list)):
111
+ ret[key] = x.copy()
112
+ else:
113
+ ret[key] = x
114
+ return ret
115
+
116
+ def get_flist_defines_list(self) -> list:
117
+ '''Returns formatted list of str for known defines'''
118
+
119
+ ret = []
120
+ prefix = strip_all_quotes(self.args['prefix-define'])
121
+ for d, value in self.defines.items():
122
+
123
+ if value is None:
124
+ ret.append(prefix + d)
125
+ continue
126
+
127
+ # else, value exists:
128
+ safe_mode_guard_str_value = bool(
129
+ self.args['safe-mode-defines'] and isinstance(value, str) and ' ' in value
130
+ )
131
+
132
+ if self.args['bracket-quote-define']:
133
+ qd1 = "{"
134
+ qd2 = "}"
135
+ elif self.args['single-quote-define']:
136
+ qd1 = "'"
137
+ qd2 = "'"
138
+ elif self.args['quote-define']:
139
+ qd1 = '"'
140
+ qd2 = '"'
141
+ else:
142
+ qd1 = ''
143
+ qd2 = ''
144
+
145
+ if self.args['equal-define']:
146
+ ed1 = '='
147
+ else:
148
+ ed1 = ' '
149
+
150
+ if self.args['escape-define-value']:
151
+ value = value.replace('\\', '\\\\').replace('"', '\\"')
152
+ if self.args['quote-define-value']:
153
+ value = '"' + value + '"'
154
+ if safe_mode_guard_str_value:
155
+ value = strip_outer_quotes(value.strip('\n'))
156
+ value = '"' + value + '"'
157
+
158
+ if self.args['quote-define'] and value.startswith('"') and value.endswith('"'):
159
+ # If you wanted your define to look like:
160
+ # +define+"NAME=VALUE", but VALUE also has double quotes wrapping it,
161
+ # it's unlikely to work so we'll optimistically so escape the " wrapping value.
162
+ # If you have additional " in the middle of the value, good luck.
163
+ value = '\\"' + value[1:-1] + '\\"'
164
+
165
+ newline = prefix + qd1 + f"{d}{ed1}{value}" + qd2
166
+
167
+ if safe_mode_guard_str_value:
168
+ # wrap the entire thing with single-quotes, so it survives as a single
169
+ # token in an eda dot-f file:
170
+ newline = shlex.quote(newline)
171
+
172
+ ret.append(newline)
173
+
174
+ return ret
175
+
176
+ def get_flist_plusargs_list(self) -> list:
177
+ '''Returns formatted list of str for unprocessed plusargs
178
+
179
+ Tool based classes can override if they also want to query their own
180
+ processed plusargs, such as CommandSim.args[sim-plusargs']
181
+ '''
182
+ ret = []
183
+ for x in self.args.get('unprocessed-plusargs', []) + self.args.get('sim-plusargs', []):
184
+ if self.args['prefix-plusargs']:
185
+ if x.startswith('+'):
186
+ x = x[1:] # strip leading +
187
+ x = self.args['prefix-plusargs'] + x
188
+ ret.append(x)
189
+ return ret
190
+
191
+ def get_flist_parameter_list(self) -> list:
192
+ '''Returns formatted list of str for parameters'''
193
+ prefix = strip_all_quotes(self.args['prefix-parameter'])
194
+ return parameters_dict_get_command_list(
195
+ params=self.parameters, arg_prefix=prefix, for_flist=True
196
+ )
197
+
198
+ def get_flist_eda_args_list(self) -> list:
199
+ '''Returns list of eda args for an eda-capable flist
200
+
201
+ - This will NOT add any util based args (--color | --no-color, --debug, etc)
202
+ - This will NOT add any -f/--input-file args (those are already resolved)
203
+
204
+ - This WILL add --env-file args
205
+ - This WILL add --config-yml args that were not default value
206
+
207
+ Not intended to be overriden by Tool based command classes.
208
+ '''
209
+ ret = []
210
+
211
+ # --env-file(s), if used:
212
+ for env_file in util.env_files_loaded:
213
+ ret.append(f'--env-file={env_file}')
214
+
215
+ # --config-yml, if non-default:
216
+ ret.extend(eda_config.get_config_yml_args_for_flist())
217
+
218
+ # EDA args, but not the flist specific args, and only those that were modified.
219
+ for arg, _ in self.modified_args.items():
220
+
221
+ if arg in self.flist_args:
222
+ # do not emit flist command args
223
+ continue
224
+
225
+ value = self.args[arg]
226
+ if isinstance(value, bool):
227
+ if value:
228
+ ret.append(f'--{arg}')
229
+ else:
230
+ ret.append(f'--no-{arg}')
231
+ else:
232
+ ret.append(f'--{arg}={value}')
233
+ return ret
234
+
235
+ def get_additional_flist_args_list(self) -> list:
236
+ '''Derived classes may override, to output additional args in the flist'''
237
+ return []
238
+
239
+ def get_additional_flist_files_list(self) -> list:
240
+ '''Derived classes may override, to output additional files in the flist'''
241
+ return []
242
+
243
+
244
+ def do_it(self) -> None:
245
+ '''do_it() is the main entry point for creating the flist(),
246
+
247
+ Usually it is called from self.process_tokens()'''
248
+
249
+ # add defines for this job
250
+ self.command_safe_set_tool_defines() # (Command.command_safe_set_tool_defines)
251
+
252
+ if not self.args['top']:
253
+ util.warning(f'CommandFList: {self.command_name=} not run due to lack of',
254
+ f'{self.args["top"]=} value')
255
+ self.write_eda_config_and_args()
256
+ return
257
+
258
+ if self.config['tool']:
259
+ tool_string = f' (with --tool={self.config["tool"]})'
260
+ else:
261
+ tool_string = ''
262
+
263
+ # if config['tool'] is set, but self.flist_has_tool is False, we're likely using
264
+ # this default handler CommandFList and the Tool class hasn't defined what they
265
+ # do. In this case, simply warn that this will emit a non-tool specific default flist
266
+ # intended for use by `eda`:
267
+ if self.config['tool'] and not self.flist_has_tool:
268
+ util.warning(f'For command="flist"{tool_string}, there is no tool',
269
+ 'specific handler for producing an flist. The default eda flist will',
270
+ 'be emitted')
271
+ # If this happens, you'll likely want the Tool based defines (that were never set
272
+ # by Tool.set_tool_defines(self) b/c we have no Tool class.
273
+ # TODO(drew): This is only a best-effort, we could create a derived Tool object and
274
+ # instead call obj.set_tool_defines(), and update self.defines instead?
275
+ _tool_config = self.config.get('tools', {}).get(self.config['tool'], {})
276
+ self.defines.update(
277
+ _tool_config.get('defines', {})
278
+ )
279
+
280
+
281
+
282
+ # check if we're overwriting the output flist file.
283
+ if self.args['print-to-stdout']:
284
+ pass
285
+ elif os.path.exists(self.args['out']):
286
+ if self.args['force']:
287
+ util.info(f"Removing existing {self.args['out']}")
288
+ os.remove(self.args['out'])
289
+ else:
290
+ self.error(f"Not overwriting {self.args['out']} unless you specify --force")
291
+
292
+ # Note - we create a work_dir in case any DEPS commands created files that need to be
293
+ # added to our sources.
294
+ self.create_work_dir()
295
+ self.run_dep_commands()
296
+
297
+ pq1 = ""
298
+ pq2 = "" # pq = path quote
299
+ if not self.args['quote-path']:
300
+ pass # if we decide to make one of the below default, this will override
301
+ elif self.args['bracket-quote-path']:
302
+ pq1 = "{"
303
+ pq2 = "}"
304
+ elif self.args['single-quote-path']:
305
+ pq1 = "'"
306
+ pq2 = "'"
307
+ elif self.args['double-quote-path']:
308
+ pq1 = '"'
309
+ pq2 = '"'
310
+
311
+ if self.args['print-to-stdout']:
312
+ fo = None
313
+ print()
314
+ else:
315
+ util.debug(f"Opening {self.args['out']} for writing")
316
+ fo = open( # pylint: disable=consider-using-with
317
+ self.args['out'], 'w', encoding='utf-8'
318
+ )
319
+ print(f"## {self.args=}", file=fo)
320
+
321
+ if self.args['emit-non-sources']:
322
+ if self.files_non_source:
323
+ print('## reqs (non-source files that are dependencies):', file=fo)
324
+ prefix = strip_all_quotes(self.args['prefix-non-sources'])
325
+ for f in self.files_non_source:
326
+ if self.args['emit-rel-path']:
327
+ f = os.path.relpath(f)
328
+ print('## ' + prefix + pq1 + f + pq2, file=fo)
329
+
330
+ if self.args['emit-eda-args']:
331
+ for newline in self.get_flist_eda_args_list():
332
+ print(newline, file=fo)
333
+
334
+ defines_lines = self.get_flist_defines_list()
335
+ if not self.args['emit-define'] and defines_lines:
336
+ util.warning(f'Command "flist"{tool_string}, has defines present but they were not',
337
+ f'included in the output flist: {defines_lines}')
338
+
339
+ parameter_lines = self.get_flist_parameter_list()
340
+ if not self.args['emit-parameter'] and parameter_lines:
341
+ util.warning(f'Command "flist"{tool_string}, has parameters present but they were not',
342
+ f'included in the output flist: {parameter_lines}')
343
+
344
+ plusarg_lines = self.get_flist_plusargs_list()
345
+ if not self.args['emit-plusargs'] and plusarg_lines:
346
+ util.warning(f'Command "flist"{tool_string}, has plusargs present but they were not',
347
+ f'included in the output flist: {plusarg_lines}')
348
+
349
+ if self.args['emit-define']:
350
+ for newline in defines_lines:
351
+ print(newline, file=fo)
352
+
353
+ if self.args['emit-parameter']:
354
+ for newline in parameter_lines:
355
+ print(newline, file=fo)
356
+
357
+
358
+ if self.args['emit-incdir']:
359
+ prefix = strip_all_quotes(self.args['prefix-incdir'])
360
+ for i in self.incdirs:
361
+ if self.args['emit-rel-path']:
362
+ i = os.path.relpath(i)
363
+ print(prefix + pq1 + i + pq2, file=fo)
364
+
365
+ if self.args['emit-plusargs']:
366
+ for newline in plusarg_lines:
367
+ print(newline, file=fo)
368
+
369
+
370
+ # Hook for derived classes to optionally print additional custom args, prior to
371
+ # any files:
372
+ for newline in self.get_additional_flist_args_list():
373
+ print(newline, file=fo)
374
+
375
+ if self.args['emit-v']:
376
+ prefix = strip_all_quotes(self.args['prefix-v'])
377
+ for f in self.files_v:
378
+ if self.args['emit-rel-path']:
379
+ f = os.path.relpath(f)
380
+ print(prefix + pq1 + f + pq2, file=fo)
381
+
382
+ if self.args['emit-sv']:
383
+ prefix = strip_all_quotes(self.args['prefix-sv'])
384
+ for f in self.files_sv:
385
+ if self.args['emit-rel-path']:
386
+ f = os.path.relpath(f)
387
+ print(prefix + pq1 + f + pq2, file=fo)
388
+ if self.args['emit-vhd']:
389
+ prefix = strip_all_quotes(self.args['prefix-vhd'])
390
+ for f in self.files_vhd:
391
+ if self.args['emit-rel-path']:
392
+ f = os.path.relpath(f)
393
+ print(prefix + pq1 + f + pq2, file=fo)
394
+ if self.args['emit-cpp']:
395
+ prefix = strip_all_quotes(self.args['prefix-cpp'])
396
+ for f in self.files_cpp:
397
+ if self.args['emit-rel-path']:
398
+ f = os.path.relpath(f)
399
+ print(prefix + pq1 + f + pq2, file=fo)
400
+
401
+ # Hook for derived classes to optionally print additional flist items after
402
+ # any files:
403
+ for newline in self.get_additional_flist_files_list():
404
+ print(newline, file=fo)
405
+
406
+ if self.args['print-to-stdout']:
407
+ print() # don't need to close fo (None)
408
+ else:
409
+ fo.close()
410
+ util.info(f"Created file: {self.args['out']}")
411
+
412
+ self.write_eda_config_and_args()
413
+ self.run_post_tool_dep_commands()
@@ -354,9 +354,11 @@ class CommandMulti(CommandParallel):
354
354
 
355
355
  if self.args['print-targets']:
356
356
  util.info('Multi print-targets (will not run jobs): -->')
357
- for t in self.targets:
357
+ print_targets = [t[0] for t in self.targets]
358
+ print_targets.sort()
359
+ for x in print_targets:
358
360
  # t = tuple of (target:str, tool:str), we just want the target.
359
- print(f' {t[0]}')
361
+ print(f' {x}')
360
362
  else:
361
363
  util.debug("Multi: converting list of targets into list of jobs")
362
364
  self.jobs = []