uv2compdb 0.4.0__py3-none-any.whl → 0.5.1__py3-none-any.whl
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.
- uv2compdb/main.py +4 -3
- uv2compdb/parser.py +117 -42
- {uv2compdb-0.4.0.dist-info → uv2compdb-0.5.1.dist-info}/METADATA +2 -3
- uv2compdb-0.5.1.dist-info/RECORD +9 -0
- uv2compdb-0.4.0.dist-info/RECORD +0 -9
- {uv2compdb-0.4.0.dist-info → uv2compdb-0.5.1.dist-info}/WHEEL +0 -0
- {uv2compdb-0.4.0.dist-info → uv2compdb-0.5.1.dist-info}/entry_points.txt +0 -0
- {uv2compdb-0.4.0.dist-info → uv2compdb-0.5.1.dist-info}/licenses/LICENSE +0 -0
uv2compdb/main.py
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Generate Compilation Database by parse Keil µVision project.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import shlex
|
|
5
6
|
import logging
|
|
6
7
|
import argparse
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from importlib.metadata import version
|
|
9
10
|
|
|
10
|
-
from uv2compdb.parser import UV2CompDB,
|
|
11
|
+
from uv2compdb.parser import UV2CompDB, generate_compile_commands
|
|
11
12
|
|
|
12
13
|
__version__ = version("uv2compdb")
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
@@ -63,7 +64,7 @@ def main() -> int:
|
|
|
63
64
|
if not args.target:
|
|
64
65
|
args.target = targets[0]
|
|
65
66
|
logger.warning(
|
|
66
|
-
f"Project has
|
|
67
|
+
f"Project has target(s): {targets}, use the first {args.target}"
|
|
67
68
|
)
|
|
68
69
|
elif args.target not in targets:
|
|
69
70
|
logger.error(f"Not found target: {args.target}")
|
|
@@ -80,7 +81,7 @@ def main() -> int:
|
|
|
80
81
|
target_setting = uv2compdb.parse(args.target, args.build)
|
|
81
82
|
command_objects = uv2compdb.generate_command_objects(
|
|
82
83
|
target_setting,
|
|
83
|
-
|
|
84
|
+
shlex.split(args.arguments) if args.arguments else [],
|
|
84
85
|
args.predefined,
|
|
85
86
|
)
|
|
86
87
|
if not generate_compile_commands(command_objects, args.output):
|
uv2compdb/parser.py
CHANGED
|
@@ -43,12 +43,12 @@ PREDEFINED_FILTER_ARGUMENT_REGEX = [
|
|
|
43
43
|
]
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def
|
|
46
|
+
def to_posix_path(path: str) -> str:
|
|
47
47
|
"""Convert Windows path separators to POSIX format."""
|
|
48
48
|
return path.replace("\\", "/")
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def
|
|
51
|
+
def split_and_strip(text: str, delimiter: str) -> list[str]:
|
|
52
52
|
"""Split text by delimiter and strip whitespace from each part."""
|
|
53
53
|
return [striped for item in text.split(delimiter) if (striped := item.strip())]
|
|
54
54
|
|
|
@@ -58,6 +58,7 @@ class Toolchain:
|
|
|
58
58
|
path: str
|
|
59
59
|
compiler: str
|
|
60
60
|
assembler: str
|
|
61
|
+
xml_tag: tuple[str, str]
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
@dataclass
|
|
@@ -108,10 +109,10 @@ class VariousControls:
|
|
|
108
109
|
# 'MBEDTLS_CONFIG_FILE=/\"config-aes-cbc.h/\"'
|
|
109
110
|
# => '-DMBEDTLS_CONFIG_FILE="config-aes-cbc.h"'
|
|
110
111
|
return (
|
|
111
|
-
[f"-I{
|
|
112
|
-
+ [f"{
|
|
113
|
-
+ [f"-U{
|
|
114
|
-
+ ["-D" +
|
|
112
|
+
[f"-I{to_posix_path(x)}" for x in self.include_path]
|
|
113
|
+
+ [f"{to_posix_path(x)}" for x in self.misc_controls]
|
|
114
|
+
+ [f"-U{to_posix_path(x)}" for x in self.undefine]
|
|
115
|
+
+ ["-D" + to_posix_path(x.replace(r'\\"', '"')) for x in self.define]
|
|
115
116
|
)
|
|
116
117
|
|
|
117
118
|
@classmethod
|
|
@@ -129,16 +130,48 @@ class UV2CompDB:
|
|
|
129
130
|
|
|
130
131
|
# TODO: how to deal with delimiters inside text (e.g., -DFOO="(1, 2)")
|
|
131
132
|
UV_VARIOUS_CONTROLS_MAP: dict[str, tuple[str, Callable[[str], list[str]]]] = {
|
|
132
|
-
"MiscControls": ("misc_controls", partial(
|
|
133
|
-
"Define": ("define", partial(
|
|
134
|
-
"Undefine": ("undefine", partial(
|
|
135
|
-
"IncludePath": ("include_path", partial(
|
|
133
|
+
"MiscControls": ("misc_controls", partial(split_and_strip, delimiter=" ")),
|
|
134
|
+
"Define": ("define", partial(split_and_strip, delimiter=",")),
|
|
135
|
+
"Undefine": ("undefine", partial(split_and_strip, delimiter=",")),
|
|
136
|
+
"IncludePath": ("include_path", partial(split_and_strip, delimiter=";")),
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
UV_C51_XML_TAG: tuple[str, str] = ("C51", "Ax51")
|
|
140
|
+
UV_ARM_XML_TAG: tuple[str, str] = ("Cads", "Aads")
|
|
141
|
+
|
|
142
|
+
# Language-Extensions: https://developer.arm.com/documentation/101655/0961/Cx51-User-s-Guide/Language-Extensions?lang=en
|
|
143
|
+
UV_C51_EXTENSION_KEYWORDS: dict[str, str] = {
|
|
144
|
+
# Data Type
|
|
145
|
+
"bit": "unsigned char",
|
|
146
|
+
"sbit": "volatile unsigned char",
|
|
147
|
+
"sfr": "volatile unsigned char",
|
|
148
|
+
"sfr16": "volatile unsigned short",
|
|
149
|
+
# Memory Models
|
|
150
|
+
"small": "",
|
|
151
|
+
"compact": "",
|
|
152
|
+
"large": "",
|
|
153
|
+
# Memory Type
|
|
154
|
+
"bdata": "",
|
|
155
|
+
"data": "",
|
|
156
|
+
"idata": "",
|
|
157
|
+
"pdata": "",
|
|
158
|
+
"xdata": "",
|
|
159
|
+
"far": "",
|
|
160
|
+
"code": "",
|
|
161
|
+
# Other
|
|
162
|
+
"_at_": "",
|
|
163
|
+
"alien": "",
|
|
164
|
+
"interrupt": "",
|
|
165
|
+
"_priority_": "",
|
|
166
|
+
"reentrant": "",
|
|
167
|
+
"_task_": "",
|
|
168
|
+
"using": "",
|
|
136
169
|
}
|
|
137
170
|
|
|
138
171
|
UV_TOOLCHAIN_MAP: dict[str, Toolchain] = {
|
|
139
|
-
"0x00": Toolchain("", "c51", ""),
|
|
140
|
-
"0x40": Toolchain("", "armcc", "armasm"),
|
|
141
|
-
"0x41": Toolchain("", "armclang", "armasm"),
|
|
172
|
+
"0x00": Toolchain("", "c51", "a51", UV_C51_XML_TAG),
|
|
173
|
+
"0x40": Toolchain("", "armcc", "armasm", UV_ARM_XML_TAG),
|
|
174
|
+
"0x41": Toolchain("", "armclang", "armasm", UV_ARM_XML_TAG),
|
|
142
175
|
}
|
|
143
176
|
|
|
144
177
|
UV_CLI_ERRORLEVEL_MAP: dict[int, str] = {
|
|
@@ -174,8 +207,10 @@ class UV2CompDB:
|
|
|
174
207
|
return None
|
|
175
208
|
return elem.text
|
|
176
209
|
|
|
177
|
-
def get_various_controls(
|
|
178
|
-
|
|
210
|
+
def get_various_controls(
|
|
211
|
+
self, elem: ET.Element | None, xml_tag: str | None
|
|
212
|
+
) -> VariousControls | None:
|
|
213
|
+
if elem is None or not xml_tag:
|
|
179
214
|
return None
|
|
180
215
|
|
|
181
216
|
# None: True, "0": False, "1": True, "2": inherit
|
|
@@ -184,7 +219,7 @@ class UV2CompDB:
|
|
|
184
219
|
|
|
185
220
|
result = {}
|
|
186
221
|
for name, (var_name, pred) in self.UV_VARIOUS_CONTROLS_MAP.items():
|
|
187
|
-
text = self._get_text(elem.find(f".//
|
|
222
|
+
text = self._get_text(elem.find(f".//{xml_tag}/VariousControls/{name}"))
|
|
188
223
|
result[var_name] = pred(text) if text else []
|
|
189
224
|
return VariousControls(**result)
|
|
190
225
|
|
|
@@ -199,8 +234,15 @@ class UV2CompDB:
|
|
|
199
234
|
if not (uv4_path := shutil.which("uv4")):
|
|
200
235
|
return False
|
|
201
236
|
|
|
202
|
-
cmd =
|
|
203
|
-
|
|
237
|
+
cmd = [
|
|
238
|
+
uv4_path,
|
|
239
|
+
"-b",
|
|
240
|
+
"-t",
|
|
241
|
+
target_name,
|
|
242
|
+
self.project_path.resolve().as_posix(),
|
|
243
|
+
"-j0",
|
|
244
|
+
]
|
|
245
|
+
logger.info(f"Run: `{subprocess.list2cmdline(cmd)}`")
|
|
204
246
|
try:
|
|
205
247
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
206
248
|
logger.info(
|
|
@@ -242,11 +284,14 @@ class UV2CompDB:
|
|
|
242
284
|
if not (m := TOOLCHAIN_REGEX.search(text)):
|
|
243
285
|
return None
|
|
244
286
|
|
|
245
|
-
toolchain_path =
|
|
287
|
+
toolchain_path = to_posix_path(m.group(1))
|
|
246
288
|
return Toolchain(
|
|
247
289
|
path=toolchain_path,
|
|
248
290
|
compiler=f"{toolchain_path}/{m.group(2)}",
|
|
249
291
|
assembler=f"{toolchain_path}/{m.group(3)}",
|
|
292
|
+
xml_tag=self.UV_C51_XML_TAG
|
|
293
|
+
if "c51" in m.group(2).lower()
|
|
294
|
+
else self.UV_ARM_XML_TAG,
|
|
250
295
|
)
|
|
251
296
|
|
|
252
297
|
def get_toolchain_from_xml(self, target: ET.Element | None) -> Toolchain | None:
|
|
@@ -269,13 +314,14 @@ class UV2CompDB:
|
|
|
269
314
|
else toolchain.path
|
|
270
315
|
),
|
|
271
316
|
compiler=(
|
|
272
|
-
|
|
317
|
+
to_posix_path(compiler_path) if compiler_path else toolchain.compiler
|
|
273
318
|
),
|
|
274
319
|
assembler=(
|
|
275
320
|
(Path(compiler_path).parent / toolchain.assembler).resolve().as_posix()
|
|
276
321
|
if compiler_path
|
|
277
322
|
else toolchain.assembler
|
|
278
323
|
),
|
|
324
|
+
xml_tag=toolchain.xml_tag,
|
|
279
325
|
)
|
|
280
326
|
|
|
281
327
|
def get_toolchain(
|
|
@@ -340,17 +386,21 @@ class UV2CompDB:
|
|
|
340
386
|
file_objects.append(FileObject(file=file, arguments=args))
|
|
341
387
|
return file_objects
|
|
342
388
|
|
|
343
|
-
def parse_xml(
|
|
344
|
-
|
|
389
|
+
def parse_xml(
|
|
390
|
+
self, target: ET.Element | None, toolchain: Toolchain | None
|
|
391
|
+
) -> list[FileObject]:
|
|
392
|
+
if target is None or toolchain is None:
|
|
345
393
|
return []
|
|
346
394
|
|
|
347
|
-
|
|
395
|
+
xml_tag = toolchain.xml_tag[0]
|
|
396
|
+
|
|
397
|
+
if (target_vc := self.get_various_controls(target, xml_tag)) is None:
|
|
348
398
|
logger.warning("Not found target_controls in target")
|
|
349
399
|
return []
|
|
350
400
|
|
|
351
401
|
file_objects = []
|
|
352
402
|
for group in target.findall(".//Group"):
|
|
353
|
-
if (group_vc := self.get_various_controls(group)) is None:
|
|
403
|
+
if (group_vc := self.get_various_controls(group, xml_tag)) is None:
|
|
354
404
|
continue
|
|
355
405
|
|
|
356
406
|
current_vc = VariousControls.merge(target_vc, group_vc)
|
|
@@ -358,17 +408,17 @@ class UV2CompDB:
|
|
|
358
408
|
file_path = self._get_text(file.find("FilePath"))
|
|
359
409
|
# file_type = self._get_text(file.find("FileType"))
|
|
360
410
|
|
|
361
|
-
if not file_path or not file_path.endswith(
|
|
362
|
-
(".s", ".c", ".cpp", ".cc", ".cx", ".cxx")
|
|
411
|
+
if not file_path or not file_path.lower().endswith(
|
|
412
|
+
(".a51", ".s", ".c", ".cpp", ".cc", ".cx", ".cxx")
|
|
363
413
|
):
|
|
364
414
|
continue
|
|
365
415
|
|
|
366
|
-
if (file_controls := self.get_various_controls(file)) is None:
|
|
416
|
+
if (file_controls := self.get_various_controls(file, xml_tag)) is None:
|
|
367
417
|
continue
|
|
368
418
|
|
|
369
419
|
file_objects.append(
|
|
370
420
|
FileObject(
|
|
371
|
-
file=
|
|
421
|
+
file=to_posix_path(file_path),
|
|
372
422
|
arguments=VariousControls.merge(
|
|
373
423
|
current_vc, file_controls
|
|
374
424
|
).get_options(),
|
|
@@ -387,9 +437,15 @@ class UV2CompDB:
|
|
|
387
437
|
return None
|
|
388
438
|
logger.info(f"Toolchain: {toolchain}")
|
|
389
439
|
|
|
390
|
-
if
|
|
391
|
-
|
|
392
|
-
|
|
440
|
+
if toolchain.xml_tag == self.UV_C51_XML_TAG:
|
|
441
|
+
file_objects = self.parse_xml(target, toolchain)
|
|
442
|
+
elif toolchain.xml_tag == self.UV_ARM_XML_TAG:
|
|
443
|
+
if not (file_objects := self.parse_dep(target, try_build)):
|
|
444
|
+
logger.warning("Not found dep file, fallback to parse xml")
|
|
445
|
+
file_objects = self.parse_xml(target, toolchain)
|
|
446
|
+
else:
|
|
447
|
+
logger.error(f"Unknown {toolchain.xml_tag=}")
|
|
448
|
+
return None
|
|
393
449
|
|
|
394
450
|
return TargetSetting(
|
|
395
451
|
name=target_name,
|
|
@@ -399,16 +455,18 @@ class UV2CompDB:
|
|
|
399
455
|
|
|
400
456
|
@staticmethod
|
|
401
457
|
@lru_cache(maxsize=32)
|
|
402
|
-
def _get_predefined_macros_cached(
|
|
458
|
+
def _get_predefined_macros_cached(
|
|
459
|
+
compiler: str, args: tuple[str, ...]
|
|
460
|
+
) -> tuple[str, ...]:
|
|
403
461
|
"""Get predefined macros from compiler with caching."""
|
|
404
462
|
if "armcc" in compiler.lower():
|
|
405
|
-
cmd =
|
|
463
|
+
cmd = [compiler, *args, "--list_macros"]
|
|
406
464
|
elif "armclang" in compiler.lower():
|
|
407
|
-
cmd =
|
|
465
|
+
cmd = [compiler, *args, "--target=arm-arm-none-eabi", "-dM", "-E", "-"]
|
|
408
466
|
else:
|
|
409
467
|
return ()
|
|
410
468
|
|
|
411
|
-
logger.info(f"Get predefined macro by: `{cmd}`")
|
|
469
|
+
logger.info(f"Get predefined macro by: `{subprocess.list2cmdline(cmd)}`")
|
|
412
470
|
try:
|
|
413
471
|
result = subprocess.run(cmd, capture_output=True, text=True, input="")
|
|
414
472
|
if result.returncode != 0:
|
|
@@ -433,6 +491,21 @@ class UV2CompDB:
|
|
|
433
491
|
if toolchain is None or not args:
|
|
434
492
|
return []
|
|
435
493
|
|
|
494
|
+
if toolchain.xml_tag == self.UV_C51_XML_TAG:
|
|
495
|
+
# Predefined-Macros: https://developer.arm.com/documentation/101655/0961/Cx51-User-s-Guide/Preprocessor/Macros/Predefined-Macros?lang=en
|
|
496
|
+
c51_defs = ["-D__C51__"]
|
|
497
|
+
c51_defs.extend(
|
|
498
|
+
f"-D{key}={val}" for key, val in self.UV_C51_EXTENSION_KEYWORDS.items()
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
# /path/to/keil/c51/bin -> /path/to/keil/c51/inc
|
|
502
|
+
if (idx := toolchain.path.lower().rfind("bin")) != -1:
|
|
503
|
+
c51_inc = toolchain.path[:idx] + toolchain.path[idx:].lower().replace(
|
|
504
|
+
"bin", "inc"
|
|
505
|
+
)
|
|
506
|
+
c51_defs.append(f"-I{c51_inc}")
|
|
507
|
+
return c51_defs
|
|
508
|
+
|
|
436
509
|
filtered_args = []
|
|
437
510
|
args_iter = iter(args)
|
|
438
511
|
for arg in args_iter:
|
|
@@ -445,9 +518,7 @@ class UV2CompDB:
|
|
|
445
518
|
next(args_iter, None)
|
|
446
519
|
|
|
447
520
|
return list(
|
|
448
|
-
self._get_predefined_macros_cached(
|
|
449
|
-
toolchain.compiler, " ".join(filtered_args)
|
|
450
|
-
)
|
|
521
|
+
self._get_predefined_macros_cached(toolchain.compiler, tuple(filtered_args))
|
|
451
522
|
)
|
|
452
523
|
|
|
453
524
|
def filter_unknown_argument(
|
|
@@ -487,7 +558,8 @@ class UV2CompDB:
|
|
|
487
558
|
self.get_predefined_macros(
|
|
488
559
|
target_setting.toolchain, file_object.arguments
|
|
489
560
|
)
|
|
490
|
-
if predefined_macros
|
|
561
|
+
if predefined_macros
|
|
562
|
+
and not file_object.file.lower().endswith((".a51", ".s"))
|
|
491
563
|
else []
|
|
492
564
|
)
|
|
493
565
|
arguments = self.filter_unknown_argument(
|
|
@@ -499,13 +571,16 @@ class UV2CompDB:
|
|
|
499
571
|
file=file_object.file,
|
|
500
572
|
arguments=(
|
|
501
573
|
[
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
574
|
+
(
|
|
575
|
+
target_setting.toolchain.compiler
|
|
576
|
+
if not file_object.file.lower().endswith((".a51", ".s"))
|
|
577
|
+
else target_setting.toolchain.assembler
|
|
578
|
+
)
|
|
505
579
|
]
|
|
506
580
|
+ toolchain_args
|
|
507
581
|
+ arguments
|
|
508
582
|
+ extra_args
|
|
583
|
+
+ [file_object.file]
|
|
509
584
|
),
|
|
510
585
|
)
|
|
511
586
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uv2compdb
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Generate Compilation Database by parse Keil µVision project
|
|
5
5
|
Keywords: keil,MDK,µVision,clangd,Compilation Database,compiled_commands.json
|
|
6
6
|
Author: xbin
|
|
@@ -79,12 +79,11 @@ optional arguments:
|
|
|
79
79
|
|
|
80
80
|
## Limit
|
|
81
81
|
|
|
82
|
-
+ [ ] Not support C51
|
|
83
82
|
+ [x] Not parsed `"Options" -> "C/C++" -> "Language / Code Generation"`
|
|
84
83
|
+ [x] Not parsed `"Options" -> "ASM"`, so Asm file use same options with C file
|
|
85
84
|
+ [x] Can't parse **RTE** components
|
|
86
85
|
+ [x] Can't add toolchain predefined macros and include path
|
|
87
|
-
+ [ ] The support for ARMCC (AC5) not well
|
|
86
|
+
+ [ ] The support for C51 / ARMCC (AC5) not well
|
|
88
87
|
+ need config `.clangd` manually
|
|
89
88
|
|
|
90
89
|
## [Clangd]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
uv2compdb/__init__.py,sha256=eL3VL6_9X_0E-oz3h4d1ovhCLrATHvviKkyZQOguqqQ,55
|
|
2
|
+
uv2compdb/__main__.py,sha256=6nm32QqZwc9URAzRAwrgJTyoLM-nGu0r9wH5iZfOKuE,70
|
|
3
|
+
uv2compdb/main.py,sha256=SvgdSzYk7jVywnlm0y67Vb15j8LOaPxFr2bvAjal96M,2970
|
|
4
|
+
uv2compdb/parser.py,sha256=v4GTmzwradOIFsgbhrDj_cO8iaJXWhfmDH2NcRHo-5o,21630
|
|
5
|
+
uv2compdb-0.5.1.dist-info/licenses/LICENSE,sha256=jBXhW_dm3ZqVqD8CitzmaDMGPonkPOmqWSDaIEUO30M,1085
|
|
6
|
+
uv2compdb-0.5.1.dist-info/WHEEL,sha256=XjEbIc5-wIORjWaafhI6vBtlxDBp7S9KiujWF1EM7Ak,79
|
|
7
|
+
uv2compdb-0.5.1.dist-info/entry_points.txt,sha256=O6qqKx-ZWjCetvl-PiycCpx92c9Xwm-EN9_UZEMHo04,46
|
|
8
|
+
uv2compdb-0.5.1.dist-info/METADATA,sha256=cS-Bz5kZesMNJMEiV7bGpMmJdbC7L7WBhh5sce9rbpE,3549
|
|
9
|
+
uv2compdb-0.5.1.dist-info/RECORD,,
|
uv2compdb-0.4.0.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
uv2compdb/__init__.py,sha256=eL3VL6_9X_0E-oz3h4d1ovhCLrATHvviKkyZQOguqqQ,55
|
|
2
|
-
uv2compdb/__main__.py,sha256=6nm32QqZwc9URAzRAwrgJTyoLM-nGu0r9wH5iZfOKuE,70
|
|
3
|
-
uv2compdb/main.py,sha256=0druk2CVT-FfUoHjYayC3J27zAEXBFPA1tYz0DhSeOg,2998
|
|
4
|
-
uv2compdb/parser.py,sha256=BN-MHujtrSiL9wibFpPGIu8le9WEWZhLtAnXdUXFeig,18927
|
|
5
|
-
uv2compdb-0.4.0.dist-info/licenses/LICENSE,sha256=jBXhW_dm3ZqVqD8CitzmaDMGPonkPOmqWSDaIEUO30M,1085
|
|
6
|
-
uv2compdb-0.4.0.dist-info/WHEEL,sha256=XjEbIc5-wIORjWaafhI6vBtlxDBp7S9KiujWF1EM7Ak,79
|
|
7
|
-
uv2compdb-0.4.0.dist-info/entry_points.txt,sha256=O6qqKx-ZWjCetvl-PiycCpx92c9Xwm-EN9_UZEMHo04,46
|
|
8
|
-
uv2compdb-0.4.0.dist-info/METADATA,sha256=k7L8K53W4BihcOLFgu4MBBRlXsoleqakCkf1ZfsTQF8,3566
|
|
9
|
-
uv2compdb-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|