pvsstudio.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. from SCons.Builder import Builder
  2. from SCons.Action import Action
  3. from SCons.Script import Delete, Mkdir, GetBuildFailures
  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. if bf.node.exists and bf.node.name.endswith(".html"):
  26. # macOS
  27. if sys.platform == "darwin":
  28. subprocess.run(["open", bf.node.abspath])
  29. else:
  30. webbrowser.open(bf.node.abspath)
  31. break
  32. def generate(env):
  33. env.SetDefault(
  34. PVSNCORES=multiprocessing.cpu_count(),
  35. PVSOPTIONS=[
  36. "@.pvsoptions",
  37. "-j${PVSNCORES}",
  38. # "--incremental", # kinda broken on PVS side
  39. ],
  40. PVSCONVOPTIONS=[
  41. "-a",
  42. "GA:1,2,3",
  43. "-t",
  44. "fullhtml",
  45. "--indicate-warnings",
  46. ],
  47. )
  48. if env["PLATFORM"] == "win32":
  49. env.SetDefault(
  50. PVSCHECKBIN="CompilerCommandsAnalyzer.exe",
  51. PVSCONVBIN="PlogConverter.exe",
  52. )
  53. else:
  54. env.SetDefault(
  55. PVSCHECKBIN="pvs-studio-analyzer",
  56. PVSCONVBIN="plog-converter",
  57. )
  58. if not env["VERBOSE"]:
  59. env.SetDefault(
  60. PVSCHECKCOMSTR="\tPVS\t${TARGET}",
  61. PVSCONVCOMSTR="\tPVSREP\t${TARGET}",
  62. )
  63. env.Append(
  64. BUILDERS={
  65. "PVSCheck": Builder(
  66. action=Action(
  67. '${PVSCHECKBIN} analyze ${PVSOPTIONS} -f "${SOURCE}" -o "${TARGET}"',
  68. "${PVSCHECKCOMSTR}",
  69. ),
  70. suffix=".log",
  71. src_suffix=".json",
  72. ),
  73. "PVSReport": Builder(
  74. action=Action(
  75. [
  76. Delete("${TARGET.dir}"),
  77. # PlogConverter.exe and plog-converter have different behavior
  78. Mkdir("${TARGET.dir}") if env["PLATFORM"] == "win32" else None,
  79. Action(_set_browser_action, None),
  80. '${PVSCONVBIN} ${PVSCONVOPTIONS} "${SOURCE}" -o "${REPORT_DIR}"',
  81. ],
  82. "${PVSCONVCOMSTR}",
  83. ),
  84. emitter=emit_pvsreport,
  85. src_suffix=".log",
  86. ),
  87. }
  88. )
  89. atexit.register(atexist_handler)
  90. def exists(env):
  91. return True