getincludes.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. # Copyright (c) 2021 The Linux Foundation
  2. #
  3. # SPDX-License-Identifier: Apache-2.0
  4. from subprocess import run, PIPE
  5. from west import log
  6. # Given a path to the applicable C compiler, a C source file, and the
  7. # corresponding TargetCompileGroup, determine which include files would
  8. # be used.
  9. # Arguments:
  10. # 1) path to applicable C compiler
  11. # 2) C source file being analyzed
  12. # 3) TargetCompileGroup for the current target
  13. # Returns: list of paths to include files, or [] on error or empty findings.
  14. def getCIncludes(compilerPath, srcFile, tcg):
  15. log.dbg(f" - getting includes for {srcFile}")
  16. # prepare fragments
  17. fragments = [fr for fr in tcg.compileCommandFragments if fr.strip() != ""]
  18. # prepare include arguments
  19. includes = ["-I" + incl.path for incl in tcg.includes]
  20. # prepare defines
  21. defines = ["-D" + d.define for d in tcg.defines]
  22. # prepare command invocation
  23. cmd = [compilerPath, "-E", "-H"] + fragments + includes + defines + [srcFile]
  24. cp = run(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
  25. if cp.returncode != 0:
  26. log.dbg(f" - calling {compilerPath} failed with error code {cp.returncode}")
  27. return []
  28. else:
  29. # response will be in cp.stderr, not cp.stdout
  30. return extractIncludes(cp.stderr)
  31. # Parse the response from the CC -E -H call, to extract the include file paths
  32. def extractIncludes(resp):
  33. includes = set()
  34. # lines we want will start with one or more periods, followed by
  35. # a space and then the include file path, e.g.:
  36. # .... /home/steve/programming/zephyr/zephyrproject/zephyr/include/kernel.h
  37. # the number of periods indicates the depth of nesting (for transitively-
  38. # included files), but here we aren't going to care about that. We'll
  39. # treat everything as tied to the corresponding source file.
  40. # once we hit the line "Multiple include guards may be useful for:",
  41. # we're done; ignore everything after that
  42. for rline in resp.splitlines():
  43. if rline.startswith("Multiple include guards"):
  44. break
  45. if rline[0] == ".":
  46. sline = rline.split(" ", maxsplit=1)
  47. if len(sline) != 2:
  48. continue
  49. includes.add(sline[1])
  50. includesList = list(includes)
  51. includesList.sort()
  52. return includesList