pvsstudio.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. from SCons.Builder import Builder
  2. from SCons.Action import Action
  3. from SCons.Script import Delete, Mkdir, GetBuildFailures, Flatten
  4. import multiprocessing
  5. import webbrowser
  6. import atexit
  7. import sys
  8. import subprocess
  9. __no_browser = False
  10. def _set_browser_action(target, source, env):
  11. if env["PVSNOBROWSER"]:
  12. global __no_browser
  13. __no_browser = True
  14. def emit_pvsreport(target, source, env):
  15. target_dir = env["REPORT_DIR"]
  16. if env["PLATFORM"] == "win32":
  17. # Report generator on Windows emits to a subfolder of given output folder
  18. target_dir = target_dir.Dir("fullhtml")
  19. return [target_dir.File("index.html")], source
  20. def atexist_handler():
  21. global __no_browser
  22. if __no_browser:
  23. return
  24. for bf in GetBuildFailures():
  25. for node in Flatten(bf.node):
  26. if node.exists and node.name.endswith(".html"):
  27. # macOS
  28. if sys.platform == "darwin":
  29. subprocess.run(["open", node.abspath])
  30. else:
  31. webbrowser.open(node.abspath)
  32. break
  33. def generate(env):
  34. env.SetDefault(
  35. PVSNCORES=multiprocessing.cpu_count(),
  36. PVSOPTIONS=[
  37. "@.pvsoptions",
  38. "-j${PVSNCORES}",
  39. # "--incremental", # kinda broken on PVS side
  40. ],
  41. PVSCONVOPTIONS=[
  42. "-a",
  43. "GA:1,2,3",
  44. "-t",
  45. "fullhtml",
  46. "--indicate-warnings",
  47. ],
  48. )
  49. if env["PLATFORM"] == "win32":
  50. env.SetDefault(
  51. PVSCHECKBIN="CompilerCommandsAnalyzer.exe",
  52. PVSCONVBIN="PlogConverter.exe",
  53. )
  54. else:
  55. env.SetDefault(
  56. PVSCHECKBIN="pvs-studio-analyzer",
  57. PVSCONVBIN="plog-converter",
  58. )
  59. if not env["VERBOSE"]:
  60. env.SetDefault(
  61. PVSCHECKCOMSTR="\tPVS\t${TARGET}",
  62. PVSCONVCOMSTR="\tPVSREP\t${TARGET}",
  63. )
  64. env.Append(
  65. BUILDERS={
  66. "PVSCheck": Builder(
  67. action=Action(
  68. '${PVSCHECKBIN} analyze ${PVSOPTIONS} -f "${SOURCE}" -o "${TARGET}"',
  69. "${PVSCHECKCOMSTR}",
  70. ),
  71. suffix=".log",
  72. src_suffix=".json",
  73. ),
  74. "PVSReport": Builder(
  75. action=Action(
  76. [
  77. Delete("${TARGET.dir}"),
  78. # PlogConverter.exe and plog-converter have different behavior
  79. Mkdir("${TARGET.dir}") if env["PLATFORM"] == "win32" else None,
  80. Action(_set_browser_action, None),
  81. '${PVSCONVBIN} ${PVSCONVOPTIONS} "${SOURCE}" -o "${REPORT_DIR}"',
  82. ],
  83. "${PVSCONVCOMSTR}",
  84. ),
  85. emitter=emit_pvsreport,
  86. src_suffix=".log",
  87. ),
  88. }
  89. )
  90. atexit.register(atexist_handler)
  91. def exists(env):
  92. return True