uv2compdb 0.3.0__py3-none-any.whl → 0.5.0__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/__init__.py CHANGED
@@ -1,5 +1,3 @@
1
- __version__ = "0.3.0"
2
-
3
1
  from uv2compdb.main import main
4
2
 
5
3
  __all__ = ["main"]
uv2compdb/main.py CHANGED
@@ -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, _split_and_strip, generate_compile_commands
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 multi targets: {targets}, use the first {args.target}"
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
- _split_and_strip(args.arguments, delimiter=" ") if args.arguments else [],
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):
uv2compdb/parser.py CHANGED
@@ -43,12 +43,12 @@ PREDEFINED_FILTER_ARGUMENT_REGEX = [
43
43
  ]
44
44
 
45
45
 
46
- def _to_posix_path(path: str) -> str:
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 _split_and_strip(text: str, delimiter: str) -> list[str]:
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{_to_posix_path(x)}" for x in self.include_path]
112
- + [f"{_to_posix_path(x)}" for x in self.misc_controls]
113
- + [f"-U{_to_posix_path(x)}" for x in self.undefine]
114
- + ["-D" + _to_posix_path(x.replace(r'\\"', '"')) for x in self.define]
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(_split_and_strip, delimiter=" ")),
133
- "Define": ("define", partial(_split_and_strip, delimiter=",")),
134
- "Undefine": ("undefine", partial(_split_and_strip, delimiter=",")),
135
- "IncludePath": ("include_path", partial(_split_and_strip, delimiter=";")),
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(self, elem: ET.Element | None) -> VariousControls | None:
178
- if elem is None:
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".//Cads/VariousControls/{name}"))
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 = _to_posix_path(m.group(1))
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
- _to_posix_path(compiler_path) if compiler_path else toolchain.compiler
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(self, target: ET.Element | None) -> list[FileObject]:
344
- if target is None:
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
- if (target_vc := self.get_various_controls(target)) is None:
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=_to_posix_path(file_path),
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 not (file_objects := self.parse_dep(target, try_build)):
391
- logger.warning("Not found dep file, fallback to parse xml")
392
- file_objects = self.parse_xml(target)
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 and not file_object.file.endswith(".s")
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
- target_setting.toolchain.compiler
503
- if not file_object.file.endswith(".s")
504
- else target_setting.toolchain.assembler
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
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uv2compdb
3
- Version: 0.3.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
- options:
67
+ optional arguments:
68
68
  -h, --help show this help message and exit
69
- -a, --arguments ARGUMENTS
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 target name
73
- -o, --output OUTPUT output dir/file path (default: compile_commands.json)
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]
@@ -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=00Kqr3ljifQQXsOOR9TRFZVn5TZ96JHdnnfTDO-Wtz0,2992
4
+ uv2compdb/parser.py,sha256=rSCnNVmr4ba2Ot5s2YQg3pwulCqLgwPvhK1Qfd-c4_U,21496
5
+ uv2compdb-0.5.0.dist-info/licenses/LICENSE,sha256=jBXhW_dm3ZqVqD8CitzmaDMGPonkPOmqWSDaIEUO30M,1085
6
+ uv2compdb-0.5.0.dist-info/WHEEL,sha256=XjEbIc5-wIORjWaafhI6vBtlxDBp7S9KiujWF1EM7Ak,79
7
+ uv2compdb-0.5.0.dist-info/entry_points.txt,sha256=O6qqKx-ZWjCetvl-PiycCpx92c9Xwm-EN9_UZEMHo04,46
8
+ uv2compdb-0.5.0.dist-info/METADATA,sha256=r9rXA-6sLrPPmqWpOmwf_0ePf2zatgDOAcOEPTNTte0,3549
9
+ uv2compdb-0.5.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- uv2compdb/__init__.py,sha256=QGf8GNYJg7LAumsXASUDPORucTmkrjVVyBPqa9JrBSA,80
2
- uv2compdb/__main__.py,sha256=6nm32QqZwc9URAzRAwrgJTyoLM-nGu0r9wH5iZfOKuE,70
3
- uv2compdb/main.py,sha256=vIqI6CKChSzZfN40wTjXhUS3OvIqeH2DKFD-mSQcRY8,2756
4
- uv2compdb/parser.py,sha256=BN-MHujtrSiL9wibFpPGIu8le9WEWZhLtAnXdUXFeig,18927
5
- uv2compdb-0.3.0.dist-info/licenses/LICENSE,sha256=jBXhW_dm3ZqVqD8CitzmaDMGPonkPOmqWSDaIEUO30M,1085
6
- uv2compdb-0.3.0.dist-info/WHEEL,sha256=XjEbIc5-wIORjWaafhI6vBtlxDBp7S9KiujWF1EM7Ak,79
7
- uv2compdb-0.3.0.dist-info/entry_points.txt,sha256=O6qqKx-ZWjCetvl-PiycCpx92c9Xwm-EN9_UZEMHo04,46
8
- uv2compdb-0.3.0.dist-info/METADATA,sha256=9-41mNUKZg29dpXTBMh7khDZwMO6DGAh7ZHg4It97BU,3433
9
- uv2compdb-0.3.0.dist-info/RECORD,,