uv2compdb 0.4.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/main.py CHANGED
@@ -7,7 +7,7 @@ import argparse
7
7
  from pathlib import Path
8
8
  from importlib.metadata import version
9
9
 
10
- from uv2compdb.parser import UV2CompDB, _split_and_strip, generate_compile_commands
10
+ from uv2compdb.parser import UV2CompDB, split_and_strip, generate_compile_commands
11
11
 
12
12
  __version__ = version("uv2compdb")
13
13
  logger = logging.getLogger(__name__)
@@ -63,7 +63,7 @@ def main() -> int:
63
63
  if not args.target:
64
64
  args.target = targets[0]
65
65
  logger.warning(
66
- f"Project has multi targets: {targets}, use the first {args.target}"
66
+ f"Project has target(s): {targets}, use the first {args.target}"
67
67
  )
68
68
  elif args.target not in targets:
69
69
  logger.error(f"Not found target: {args.target}")
@@ -80,7 +80,7 @@ def main() -> int:
80
80
  target_setting = uv2compdb.parse(args.target, args.build)
81
81
  command_objects = uv2compdb.generate_command_objects(
82
82
  target_setting,
83
- _split_and_strip(args.arguments, delimiter=" ") if args.arguments else [],
83
+ split_and_strip(args.arguments, delimiter=" ") if args.arguments else [],
84
84
  args.predefined,
85
85
  )
86
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.4.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
@@ -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=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=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,,