checkpackagelib_mk.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. # See support/scripts/check-package.txt before editing this file.
  2. # There are already dependency checks during the build, so below check
  3. # functions don't need to check for things already checked by exploring the
  4. # menu options using "make menuconfig" and by running "make" with appropriate
  5. # packages enabled.
  6. import re
  7. from checkpackagebase import _CheckFunction
  8. # Notice: ignore 'imported but unused' from pyflakes for check functions.
  9. from checkpackagelib import ConsecutiveEmptyLines
  10. from checkpackagelib import EmptyLastLine
  11. from checkpackagelib import NewlineAtEof
  12. from checkpackagelib import TrailingSpace
  13. class Indent(_CheckFunction):
  14. COMMENT = re.compile("^\s*#")
  15. CONDITIONAL = re.compile("^\s*(ifeq|ifneq|endif)\s")
  16. ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
  17. END_DEFINE = re.compile("^\s*endef\s")
  18. MAKEFILE_TARGET = re.compile("^[^# \t]+:\s")
  19. START_DEFINE = re.compile("^\s*define\s")
  20. def before(self):
  21. self.define = False
  22. self.backslash = False
  23. self.makefile_target = False
  24. def check_line(self, lineno, text):
  25. if self.START_DEFINE.search(text):
  26. self.define = True
  27. return
  28. if self.END_DEFINE.search(text):
  29. self.define = False
  30. return
  31. expect_tabs = False
  32. if self.define or self.backslash or self.makefile_target:
  33. expect_tabs = True
  34. if self.CONDITIONAL.search(text):
  35. expect_tabs = False
  36. # calculate for next line
  37. if self.ENDS_WITH_BACKSLASH.search(text):
  38. self.backslash = True
  39. else:
  40. self.backslash = False
  41. if self.MAKEFILE_TARGET.search(text):
  42. self.makefile_target = True
  43. return
  44. if text.strip() == "":
  45. self.makefile_target = False
  46. return
  47. # comment can be indented or not inside define ... endef, so ignore it
  48. if self.define and self.COMMENT.search(text):
  49. return
  50. if expect_tabs:
  51. if not text.startswith("\t"):
  52. return ["{}:{}: expected indent with tabs"
  53. .format(self.filename, lineno),
  54. text]
  55. else:
  56. if text.startswith("\t"):
  57. return ["{}:{}: unexpected indent with tabs"
  58. .format(self.filename, lineno),
  59. text]
  60. class PackageHeader(_CheckFunction):
  61. def before(self):
  62. self.skip = False
  63. def check_line(self, lineno, text):
  64. if self.skip or lineno > 6:
  65. return
  66. if lineno in [1, 5]:
  67. if lineno == 1 and text.startswith("include "):
  68. self.skip = True
  69. return
  70. if text.rstrip() != "#" * 80:
  71. return ["{}:{}: should be 80 hashes ({}#writing-rules-mk)"
  72. .format(self.filename, lineno, self.url_to_manual),
  73. text,
  74. "#" * 80]
  75. elif lineno in [2, 4]:
  76. if text.rstrip() != "#":
  77. return ["{}:{}: should be 1 hash ({}#writing-rules-mk)"
  78. .format(self.filename, lineno, self.url_to_manual),
  79. text]
  80. elif lineno == 6:
  81. if text.rstrip() != "":
  82. return ["{}:{}: should be a blank line ({}#writing-rules-mk)"
  83. .format(self.filename, lineno, self.url_to_manual),
  84. text]
  85. class SpaceBeforeBackslash(_CheckFunction):
  86. TAB_OR_MULTIPLE_SPACES_BEFORE_BACKSLASH = re.compile(r"^.*( |\t)\\$")
  87. def check_line(self, lineno, text):
  88. if self.TAB_OR_MULTIPLE_SPACES_BEFORE_BACKSLASH.match(text.rstrip()):
  89. return ["{}:{}: use only one space before backslash"
  90. .format(self.filename, lineno),
  91. text]
  92. class TrailingBackslash(_CheckFunction):
  93. ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
  94. def before(self):
  95. self.backslash = False
  96. def check_line(self, lineno, text):
  97. last_line_ends_in_backslash = self.backslash
  98. # calculate for next line
  99. if self.ENDS_WITH_BACKSLASH.search(text):
  100. self.backslash = True
  101. self.lastline = text
  102. return
  103. self.backslash = False
  104. if last_line_ends_in_backslash and text.strip() == "":
  105. return ["{}:{}: remove trailing backslash"
  106. .format(self.filename, lineno - 1),
  107. self.lastline]
  108. class UselessFlag(_CheckFunction):
  109. DEFAULT_AUTOTOOLS_FLAG = re.compile("^.*{}".format("|".join([
  110. "_AUTORECONF\s*=\s*NO",
  111. "_LIBTOOL_PATCH\s*=\s*YES"])))
  112. DEFAULT_GENERIC_FLAG = re.compile("^.*{}".format("|".join([
  113. "_INSTALL_IMAGES\s*=\s*NO",
  114. "_INSTALL_REDISTRIBUTE\s*=\s*YES",
  115. "_INSTALL_STAGING\s*=\s*NO",
  116. "_INSTALL_TARGET\s*=\s*YES"])))
  117. END_CONDITIONAL = re.compile("^\s*(endif)")
  118. START_CONDITIONAL = re.compile("^\s*(ifeq|ifneq)")
  119. def before(self):
  120. self.conditional = 0
  121. def check_line(self, lineno, text):
  122. if self.START_CONDITIONAL.search(text):
  123. self.conditional += 1
  124. return
  125. if self.END_CONDITIONAL.search(text):
  126. self.conditional -= 1
  127. return
  128. # allow non-default conditionally overridden by default
  129. if self.conditional > 0:
  130. return
  131. if self.DEFAULT_GENERIC_FLAG.search(text):
  132. return ["{}:{}: useless default value ({}#"
  133. "_infrastructure_for_packages_with_specific_build_systems)"
  134. .format(self.filename, lineno, self.url_to_manual),
  135. text]
  136. if self.DEFAULT_AUTOTOOLS_FLAG.search(text):
  137. return ["{}:{}: useless default value "
  138. "({}#_infrastructure_for_autotools_based_packages)"
  139. .format(self.filename, lineno, self.url_to_manual),
  140. text]