uv2compdb 0.3.0__tar.gz → 0.5.0__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.
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/PKG-INFO +10 -8
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/README.md +9 -7
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/pyproject.toml +1 -1
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/src/uv2compdb/__init__.py +0 -2
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/src/uv2compdb/main.py +12 -3
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/src/uv2compdb/parser.py +101 -33
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/LICENSE +0 -0
- {uv2compdb-0.3.0 → uv2compdb-0.5.0}/src/uv2compdb/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uv2compdb
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
@@ -57,31 +57,33 @@ uv2compdb /path/to/project -t target -o /path/to/compile_commands.json
|
|
|
57
57
|
### Help
|
|
58
58
|
|
|
59
59
|
```sh
|
|
60
|
-
usage: uv2compdb [-h] [-a ARGUMENTS] [-b] [-t TARGET] [-o OUTPUT] [-p] project
|
|
60
|
+
usage: uv2compdb [-h] [-v] [-a ARGUMENTS] [-b] [-t TARGET] [-o OUTPUT] [-p] project
|
|
61
61
|
|
|
62
62
|
Generate compile_commands.json by parse Keil µVision project
|
|
63
63
|
|
|
64
64
|
positional arguments:
|
|
65
65
|
project path to .uvproj[x] file
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
optional arguments:
|
|
68
68
|
-h, --help show this help message and exit
|
|
69
|
-
-
|
|
69
|
+
-v, --version show version and exit
|
|
70
|
+
-a ARGUMENTS, --arguments ARGUMENTS
|
|
70
71
|
add extra arguments
|
|
71
72
|
-b, --build try to build while dep/build_log files don't not exist
|
|
72
|
-
-t, --target TARGET
|
|
73
|
-
|
|
73
|
+
-t TARGET, --target TARGET
|
|
74
|
+
target name
|
|
75
|
+
-o OUTPUT, --output OUTPUT
|
|
76
|
+
output dir/file path (default: compile_commands.json)
|
|
74
77
|
-p, --predefined try to add predefined macros
|
|
75
78
|
```
|
|
76
79
|
|
|
77
80
|
## Limit
|
|
78
81
|
|
|
79
|
-
+ [ ] Not support C51
|
|
80
82
|
+ [x] Not parsed `"Options" -> "C/C++" -> "Language / Code Generation"`
|
|
81
83
|
+ [x] Not parsed `"Options" -> "ASM"`, so Asm file use same options with C file
|
|
82
84
|
+ [x] Can't parse **RTE** components
|
|
83
85
|
+ [x] Can't add toolchain predefined macros and include path
|
|
84
|
-
+ [ ] The support for ARMCC (AC5) not well
|
|
86
|
+
+ [ ] The support for C51 / ARMCC (AC5) not well
|
|
85
87
|
+ need config `.clangd` manually
|
|
86
88
|
|
|
87
89
|
## [Clangd]
|
|
@@ -35,31 +35,33 @@ uv2compdb /path/to/project -t target -o /path/to/compile_commands.json
|
|
|
35
35
|
### Help
|
|
36
36
|
|
|
37
37
|
```sh
|
|
38
|
-
usage: uv2compdb [-h] [-a ARGUMENTS] [-b] [-t TARGET] [-o OUTPUT] [-p] project
|
|
38
|
+
usage: uv2compdb [-h] [-v] [-a ARGUMENTS] [-b] [-t TARGET] [-o OUTPUT] [-p] project
|
|
39
39
|
|
|
40
40
|
Generate compile_commands.json by parse Keil µVision project
|
|
41
41
|
|
|
42
42
|
positional arguments:
|
|
43
43
|
project path to .uvproj[x] file
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
optional arguments:
|
|
46
46
|
-h, --help show this help message and exit
|
|
47
|
-
-
|
|
47
|
+
-v, --version show version and exit
|
|
48
|
+
-a ARGUMENTS, --arguments ARGUMENTS
|
|
48
49
|
add extra arguments
|
|
49
50
|
-b, --build try to build while dep/build_log files don't not exist
|
|
50
|
-
-t, --target TARGET
|
|
51
|
-
|
|
51
|
+
-t TARGET, --target TARGET
|
|
52
|
+
target name
|
|
53
|
+
-o OUTPUT, --output OUTPUT
|
|
54
|
+
output dir/file path (default: compile_commands.json)
|
|
52
55
|
-p, --predefined try to add predefined macros
|
|
53
56
|
```
|
|
54
57
|
|
|
55
58
|
## Limit
|
|
56
59
|
|
|
57
|
-
+ [ ] Not support C51
|
|
58
60
|
+ [x] Not parsed `"Options" -> "C/C++" -> "Language / Code Generation"`
|
|
59
61
|
+ [x] Not parsed `"Options" -> "ASM"`, so Asm file use same options with C file
|
|
60
62
|
+ [x] Can't parse **RTE** components
|
|
61
63
|
+ [x] Can't add toolchain predefined macros and include path
|
|
62
|
-
+ [ ] The support for ARMCC (AC5) not well
|
|
64
|
+
+ [ ] The support for C51 / ARMCC (AC5) not well
|
|
63
65
|
+ need config `.clangd` manually
|
|
64
66
|
|
|
65
67
|
## [Clangd]
|
|
@@ -5,9 +5,11 @@ Generate Compilation Database by parse Keil µVision project.
|
|
|
5
5
|
import logging
|
|
6
6
|
import argparse
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from importlib.metadata import version
|
|
8
9
|
|
|
9
|
-
from uv2compdb.parser import UV2CompDB,
|
|
10
|
+
from uv2compdb.parser import UV2CompDB, split_and_strip, generate_compile_commands
|
|
10
11
|
|
|
12
|
+
__version__ = version("uv2compdb")
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
12
14
|
logging.basicConfig(
|
|
13
15
|
level=logging.INFO,
|
|
@@ -20,6 +22,13 @@ def main() -> int:
|
|
|
20
22
|
parser = argparse.ArgumentParser(
|
|
21
23
|
description="Generate compile_commands.json by parse Keil µVision project"
|
|
22
24
|
)
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"-v",
|
|
27
|
+
"--version",
|
|
28
|
+
action="version",
|
|
29
|
+
version=__version__,
|
|
30
|
+
help="show version and exit",
|
|
31
|
+
)
|
|
23
32
|
parser.add_argument("-a", "--arguments", default=None, help="add extra arguments")
|
|
24
33
|
parser.add_argument(
|
|
25
34
|
"-b",
|
|
@@ -54,7 +63,7 @@ def main() -> int:
|
|
|
54
63
|
if not args.target:
|
|
55
64
|
args.target = targets[0]
|
|
56
65
|
logger.warning(
|
|
57
|
-
f"Project has
|
|
66
|
+
f"Project has target(s): {targets}, use the first {args.target}"
|
|
58
67
|
)
|
|
59
68
|
elif args.target not in targets:
|
|
60
69
|
logger.error(f"Not found target: {args.target}")
|
|
@@ -71,7 +80,7 @@ def main() -> int:
|
|
|
71
80
|
target_setting = uv2compdb.parse(args.target, args.build)
|
|
72
81
|
command_objects = uv2compdb.generate_command_objects(
|
|
73
82
|
target_setting,
|
|
74
|
-
|
|
83
|
+
split_and_strip(args.arguments, delimiter=" ") if args.arguments else [],
|
|
75
84
|
args.predefined,
|
|
76
85
|
)
|
|
77
86
|
if not generate_compile_commands(command_objects, args.output):
|
|
@@ -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
|
|
|
@@ -242,11 +277,14 @@ class UV2CompDB:
|
|
|
242
277
|
if not (m := TOOLCHAIN_REGEX.search(text)):
|
|
243
278
|
return None
|
|
244
279
|
|
|
245
|
-
toolchain_path =
|
|
280
|
+
toolchain_path = to_posix_path(m.group(1))
|
|
246
281
|
return Toolchain(
|
|
247
282
|
path=toolchain_path,
|
|
248
283
|
compiler=f"{toolchain_path}/{m.group(2)}",
|
|
249
284
|
assembler=f"{toolchain_path}/{m.group(3)}",
|
|
285
|
+
xml_tag=self.UV_C51_XML_TAG
|
|
286
|
+
if "c51" in m.group(2).lower()
|
|
287
|
+
else self.UV_ARM_XML_TAG,
|
|
250
288
|
)
|
|
251
289
|
|
|
252
290
|
def get_toolchain_from_xml(self, target: ET.Element | None) -> Toolchain | None:
|
|
@@ -269,13 +307,14 @@ class UV2CompDB:
|
|
|
269
307
|
else toolchain.path
|
|
270
308
|
),
|
|
271
309
|
compiler=(
|
|
272
|
-
|
|
310
|
+
to_posix_path(compiler_path) if compiler_path else toolchain.compiler
|
|
273
311
|
),
|
|
274
312
|
assembler=(
|
|
275
313
|
(Path(compiler_path).parent / toolchain.assembler).resolve().as_posix()
|
|
276
314
|
if compiler_path
|
|
277
315
|
else toolchain.assembler
|
|
278
316
|
),
|
|
317
|
+
xml_tag=toolchain.xml_tag,
|
|
279
318
|
)
|
|
280
319
|
|
|
281
320
|
def get_toolchain(
|
|
@@ -340,17 +379,21 @@ class UV2CompDB:
|
|
|
340
379
|
file_objects.append(FileObject(file=file, arguments=args))
|
|
341
380
|
return file_objects
|
|
342
381
|
|
|
343
|
-
def parse_xml(
|
|
344
|
-
|
|
382
|
+
def parse_xml(
|
|
383
|
+
self, target: ET.Element | None, toolchain: Toolchain | None
|
|
384
|
+
) -> list[FileObject]:
|
|
385
|
+
if target is None or toolchain is None:
|
|
345
386
|
return []
|
|
346
387
|
|
|
347
|
-
|
|
388
|
+
xml_tag = toolchain.xml_tag[0]
|
|
389
|
+
|
|
390
|
+
if (target_vc := self.get_various_controls(target, xml_tag)) is None:
|
|
348
391
|
logger.warning("Not found target_controls in target")
|
|
349
392
|
return []
|
|
350
393
|
|
|
351
394
|
file_objects = []
|
|
352
395
|
for group in target.findall(".//Group"):
|
|
353
|
-
if (group_vc := self.get_various_controls(group)) is None:
|
|
396
|
+
if (group_vc := self.get_various_controls(group, xml_tag)) is None:
|
|
354
397
|
continue
|
|
355
398
|
|
|
356
399
|
current_vc = VariousControls.merge(target_vc, group_vc)
|
|
@@ -358,17 +401,17 @@ class UV2CompDB:
|
|
|
358
401
|
file_path = self._get_text(file.find("FilePath"))
|
|
359
402
|
# file_type = self._get_text(file.find("FileType"))
|
|
360
403
|
|
|
361
|
-
if not file_path or not file_path.endswith(
|
|
362
|
-
(".s", ".c", ".cpp", ".cc", ".cx", ".cxx")
|
|
404
|
+
if not file_path or not file_path.lower().endswith(
|
|
405
|
+
(".a51", ".s", ".c", ".cpp", ".cc", ".cx", ".cxx")
|
|
363
406
|
):
|
|
364
407
|
continue
|
|
365
408
|
|
|
366
|
-
if (file_controls := self.get_various_controls(file)) is None:
|
|
409
|
+
if (file_controls := self.get_various_controls(file, xml_tag)) is None:
|
|
367
410
|
continue
|
|
368
411
|
|
|
369
412
|
file_objects.append(
|
|
370
413
|
FileObject(
|
|
371
|
-
file=
|
|
414
|
+
file=to_posix_path(file_path),
|
|
372
415
|
arguments=VariousControls.merge(
|
|
373
416
|
current_vc, file_controls
|
|
374
417
|
).get_options(),
|
|
@@ -387,9 +430,15 @@ class UV2CompDB:
|
|
|
387
430
|
return None
|
|
388
431
|
logger.info(f"Toolchain: {toolchain}")
|
|
389
432
|
|
|
390
|
-
if
|
|
391
|
-
|
|
392
|
-
|
|
433
|
+
if toolchain.xml_tag == self.UV_C51_XML_TAG:
|
|
434
|
+
file_objects = self.parse_xml(target, toolchain)
|
|
435
|
+
elif toolchain.xml_tag == self.UV_ARM_XML_TAG:
|
|
436
|
+
if not (file_objects := self.parse_dep(target, try_build)):
|
|
437
|
+
logger.warning("Not found dep file, fallback to parse xml")
|
|
438
|
+
file_objects = self.parse_xml(target, toolchain)
|
|
439
|
+
else:
|
|
440
|
+
logger.error(f"Unknown {toolchain.xml_tag=}")
|
|
441
|
+
return None
|
|
393
442
|
|
|
394
443
|
return TargetSetting(
|
|
395
444
|
name=target_name,
|
|
@@ -433,6 +482,21 @@ class UV2CompDB:
|
|
|
433
482
|
if toolchain is None or not args:
|
|
434
483
|
return []
|
|
435
484
|
|
|
485
|
+
if toolchain.xml_tag == self.UV_C51_XML_TAG:
|
|
486
|
+
# Predefined-Macros: https://developer.arm.com/documentation/101655/0961/Cx51-User-s-Guide/Preprocessor/Macros/Predefined-Macros?lang=en
|
|
487
|
+
c51_defs = ["-D__C51__"]
|
|
488
|
+
c51_defs.extend(
|
|
489
|
+
f"-D{key}={val}" for key, val in self.UV_C51_EXTENSION_KEYWORDS.items()
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
# /path/to/keil/c51/bin -> /path/to/keil/c51/inc
|
|
493
|
+
if (idx := toolchain.path.lower().rfind("bin")) != -1:
|
|
494
|
+
c51_inc = toolchain.path[:idx] + toolchain.path[idx:].lower().replace(
|
|
495
|
+
"bin", "inc"
|
|
496
|
+
)
|
|
497
|
+
c51_defs.append(f"-I{c51_inc}")
|
|
498
|
+
return c51_defs
|
|
499
|
+
|
|
436
500
|
filtered_args = []
|
|
437
501
|
args_iter = iter(args)
|
|
438
502
|
for arg in args_iter:
|
|
@@ -487,7 +551,8 @@ class UV2CompDB:
|
|
|
487
551
|
self.get_predefined_macros(
|
|
488
552
|
target_setting.toolchain, file_object.arguments
|
|
489
553
|
)
|
|
490
|
-
if predefined_macros
|
|
554
|
+
if predefined_macros
|
|
555
|
+
and not file_object.file.lower().endswith((".a51", ".s"))
|
|
491
556
|
else []
|
|
492
557
|
)
|
|
493
558
|
arguments = self.filter_unknown_argument(
|
|
@@ -499,13 +564,16 @@ class UV2CompDB:
|
|
|
499
564
|
file=file_object.file,
|
|
500
565
|
arguments=(
|
|
501
566
|
[
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
567
|
+
(
|
|
568
|
+
target_setting.toolchain.compiler
|
|
569
|
+
if not file_object.file.lower().endswith((".a51", ".s"))
|
|
570
|
+
else target_setting.toolchain.assembler
|
|
571
|
+
)
|
|
505
572
|
]
|
|
506
573
|
+ toolchain_args
|
|
507
574
|
+ arguments
|
|
508
575
|
+ extra_args
|
|
576
|
+
+ [file_object.file]
|
|
509
577
|
),
|
|
510
578
|
)
|
|
511
579
|
)
|
|
File without changes
|
|
File without changes
|