cpp_check.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #
  2. # Copyright (c) 2006-2023, RT-Thread Development Team
  3. #
  4. # SPDX-License-Identifier: Apache-2.0
  5. #
  6. # Change Logs:
  7. # Date Author Notes
  8. # 2023-05-16 dejavudwh the first version
  9. # 2024-09-12 supperthomas add cppcheck summary for detail
  10. #
  11. import click
  12. import logging
  13. import subprocess
  14. import sys
  15. import format_ignore
  16. import os
  17. '''
  18. --suppress=syntaxError:
  19. 该选项用于抑制特定的错误类型。在这里,syntaxError 是被忽略的错误类型。这意味着 Cppcheck 不会报告语法错误(syntaxError)。这是因为在某些情况下,分析工具可能会误报语法错误,但 CI(持续集成)系统会在编译时捕获这些错误,因此可以忽略。
  20. --enable=warning:
  21. 该选项用于启用特定类型的检查。Cppcheck 可以检查不同的级别和种类的问题,如错误、警告、性能问题等。--enable=warning 启用的是警告级别的检查,帮助检测代码中可能存在的问题,但不是严重的错误。
  22. performance:
  23. Cppcheck 可以启用多个检查种类,在这里指定了 performance,意味着会检查与代码性能相关的潜在问题,例如不必要的拷贝操作、无效的条件判断等。这有助于提高代码的运行效率。
  24. portability:
  25. Cppcheck 会检查代码的可移植性问题。可移植性检查帮助发现代码在不同平台或编译器中可能遇到的问题,如特定平台上不支持的类型、函数或特性。这对跨平台开发非常重要。
  26. --inline-suppr:
  27. 该选项允许在代码中使用注释来抑制特定的警告或错误信息。通过这种方式,开发者可以直接在代码中添加注释,告诉 Cppcheck 忽略某些检查或警告。例如,开发者可以在代码中添加 // cppcheck-suppress <message> 来抑制特定的警告信息。
  28. --error-exitcode=1:
  29. 该选项告诉 Cppcheck 如果遇到错误,就返回指定的退出码。在这里指定的是 1。这对自动化工具非常有用,尤其是在 CI 环境中,因为它可以通过检查返回码来判断 Cppcheck 是否发现了错误。如果有错误,CI 系统会将整个任务标记为失败。
  30. --force:
  31. 这个选项强制 Cppcheck 对所有文件进行检查,即使它检测到编译条件缺失或某些配置问题。通常,如果某些宏定义或依赖项缺失,Cppcheck 可能会跳过某些文件的检查。但 --force 会强制工具继续执行分析,即使有可能缺少某些信息。这在某些大型项目中很有用,可以确保所有文件都经过检查。
  32. '''
  33. def add_summary(text):
  34. """
  35. add summary to github action.
  36. """
  37. os.system(f'echo "{text}" >> $GITHUB_STEP_SUMMARY ;')
  38. class CPPCheck:
  39. def __init__(self, file_list):
  40. self.file_list = file_list
  41. def check(self):
  42. file_list_filtered = [file for file in self.file_list if file.endswith(('.c', '.cpp', '.cc', '.cxx'))]
  43. logging.info("Start to static code analysis.")
  44. check_result = True
  45. for file in file_list_filtered:
  46. macros = []
  47. if os.path.basename(file) == 'lwp.c':
  48. macros.append('-DRT_USING_DFS')
  49. result = subprocess.run(
  50. [
  51. 'cppcheck',
  52. '-DRT_ASSERT(x)=',
  53. '-DRTM_EXPORT(x)=',
  54. '-Drt_list_for_each_entry(a,b,c)=a=(void*)b;',
  55. '-I include',
  56. '-I thread/components/finsh',
  57. # it's okay because CI will do the real compilation to check this
  58. '--suppress=syntaxError',
  59. '--check-level=exhaustive',
  60. '--enable=warning',
  61. 'performance',
  62. 'portability',
  63. '--inline-suppr',
  64. '--error-exitcode=1',
  65. '--force',
  66. file
  67. ] + macros,
  68. stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  69. logging.info(result.stdout.decode())
  70. logging.info(result.stderr.decode())
  71. if result.stderr:
  72. add_summary("The following errors are for reference only. If they are not actual issues, please ignore them and do not make unnecessary modifications.")
  73. add_summary("以下错误仅供参考,如果发现没有问题,请直接忽略,不需要强行修改")
  74. add_summary(f"- :rotating_light: {result.stderr.decode()}")
  75. check_result = False
  76. return check_result
  77. @click.group()
  78. @click.pass_context
  79. def cli(ctx):
  80. pass
  81. @cli.command()
  82. def check():
  83. """
  84. static code analysis(cppcheck).
  85. """
  86. format_ignore.init_logger()
  87. # get modified files list
  88. checkout = format_ignore.CheckOut()
  89. file_list = checkout.get_new_file()
  90. if file_list is None:
  91. logging.error("checkout files fail")
  92. sys.exit(1)
  93. # use cppcheck
  94. cpp_check = CPPCheck(file_list)
  95. cpp_check_result = cpp_check.check()
  96. if not cpp_check_result:
  97. logging.error("static code analysis(cppcheck) fail.")
  98. sys.exit(1)
  99. logging.info("check success.")
  100. sys.exit(0)
  101. if __name__ == '__main__':
  102. cli()