2
1

lib_mk.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. # See utils/checkpackagelib/readme.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 base import _CheckFunction
  8. # Notice: ignore 'imported but unused' from pyflakes for check functions.
  9. from lib import ConsecutiveEmptyLines
  10. from lib import EmptyLastLine
  11. from lib import NewlineAtEof
  12. from lib 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 TypoInPackageVariable(_CheckFunction):
  109. ALLOWED = re.compile("|".join([
  110. "ACLOCAL_DIR",
  111. "ACLOCAL_HOST_DIR",
  112. "BR_CCACHE_INITIAL_SETUP",
  113. "BR_NO_CHECK_HASH_FOR",
  114. "LINUX_POST_PATCH_HOOKS",
  115. "LINUX_TOOLS",
  116. "LUA_RUN",
  117. "MKFS_JFFS2",
  118. "MKIMAGE_ARCH",
  119. "PKG_CONFIG_HOST_BINARY",
  120. "TARGET_FINALIZE_HOOKS",
  121. "XTENSA_CORE_NAME"]))
  122. PACKAGE_NAME = re.compile("/([^/]+)\.mk")
  123. VARIABLE = re.compile("^([A-Z0-9_]+_[A-Z0-9_]+)\s*(\+|)=")
  124. def before(self):
  125. package = self.PACKAGE_NAME.search(self.filename).group(1)
  126. package = package.replace("-", "_").upper()
  127. # linux tools do not use LINUX_TOOL_ prefix for variables
  128. package = package.replace("LINUX_TOOL_", "")
  129. self.package = package
  130. self.REGEX = re.compile("^(HOST_)?({}_[A-Z0-9_]+)".format(package))
  131. self.FIND_VIRTUAL = re.compile(
  132. "^{}_PROVIDES\s*(\+|)=\s*(.*)".format(package))
  133. self.virtual = []
  134. def check_line(self, lineno, text):
  135. m = self.VARIABLE.search(text)
  136. if m is None:
  137. return
  138. variable = m.group(1)
  139. # allow to set variables for virtual package this package provides
  140. v = self.FIND_VIRTUAL.search(text)
  141. if v:
  142. self.virtual += v.group(2).upper().split()
  143. return
  144. for virtual in self.virtual:
  145. if variable.startswith("{}_".format(virtual)):
  146. return
  147. if self.ALLOWED.match(variable):
  148. return
  149. if self.REGEX.search(text) is None:
  150. return ["{}:{}: possible typo: {} -> *{}*"
  151. .format(self.filename, lineno, variable, self.package),
  152. text]
  153. class UselessFlag(_CheckFunction):
  154. DEFAULT_AUTOTOOLS_FLAG = re.compile("^.*{}".format("|".join([
  155. "_AUTORECONF\s*=\s*NO",
  156. "_LIBTOOL_PATCH\s*=\s*YES"])))
  157. DEFAULT_GENERIC_FLAG = re.compile("^.*{}".format("|".join([
  158. "_INSTALL_IMAGES\s*=\s*NO",
  159. "_INSTALL_REDISTRIBUTE\s*=\s*YES",
  160. "_INSTALL_STAGING\s*=\s*NO",
  161. "_INSTALL_TARGET\s*=\s*YES"])))
  162. END_CONDITIONAL = re.compile("^\s*(endif)")
  163. START_CONDITIONAL = re.compile("^\s*(ifeq|ifneq)")
  164. def before(self):
  165. self.conditional = 0
  166. def check_line(self, lineno, text):
  167. if self.START_CONDITIONAL.search(text):
  168. self.conditional += 1
  169. return
  170. if self.END_CONDITIONAL.search(text):
  171. self.conditional -= 1
  172. return
  173. # allow non-default conditionally overridden by default
  174. if self.conditional > 0:
  175. return
  176. if self.DEFAULT_GENERIC_FLAG.search(text):
  177. return ["{}:{}: useless default value ({}#"
  178. "_infrastructure_for_packages_with_specific_build_systems)"
  179. .format(self.filename, lineno, self.url_to_manual),
  180. text]
  181. if self.DEFAULT_AUTOTOOLS_FLAG.search(text):
  182. return ["{}:{}: useless default value "
  183. "({}#_infrastructure_for_autotools_based_packages)"
  184. .format(self.filename, lineno, self.url_to_manual),
  185. text]