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
9 from base import _CheckFunction
10 from lib import ConsecutiveEmptyLines # noqa: F401
11 from lib import EmptyLastLine # noqa: F401
12 from lib import NewlineAtEof # noqa: F401
13 from lib import TrailingSpace # noqa: F401
16 class Indent(_CheckFunction):
17 COMMENT = re.compile("^\s*#")
18 CONDITIONAL = re.compile("^\s*(ifeq|ifneq|endif)\s")
19 ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
20 END_DEFINE = re.compile("^\s*endef\s")
21 MAKEFILE_TARGET = re.compile("^[^# \t]+:\s")
22 START_DEFINE = re.compile("^\s*define\s")
26 self.backslash = False
27 self.makefile_target = False
29 def check_line(self, lineno, text):
30 if self.START_DEFINE.search(text):
33 if self.END_DEFINE.search(text):
38 if self.define or self.backslash or self.makefile_target:
40 if self.CONDITIONAL.search(text):
43 # calculate for next line
44 if self.ENDS_WITH_BACKSLASH.search(text):
47 self.backslash = False
49 if self.MAKEFILE_TARGET.search(text):
50 self.makefile_target = True
52 if text.strip() == "":
53 self.makefile_target = False
56 # comment can be indented or not inside define ... endef, so ignore it
57 if self.define and self.COMMENT.search(text):
61 if not text.startswith("\t"):
62 return ["{}:{}: expected indent with tabs"
63 .format(self.filename, lineno),
66 if text.startswith("\t"):
67 return ["{}:{}: unexpected indent with tabs"
68 .format(self.filename, lineno),
72 class PackageHeader(_CheckFunction):
76 def check_line(self, lineno, text):
77 if self.skip or lineno > 6:
81 if lineno == 1 and text.startswith("include "):
84 if text.rstrip() != "#" * 80:
85 return ["{}:{}: should be 80 hashes ({}#writing-rules-mk)"
86 .format(self.filename, lineno, self.url_to_manual),
89 elif lineno in [2, 4]:
90 if text.rstrip() != "#":
91 return ["{}:{}: should be 1 hash ({}#writing-rules-mk)"
92 .format(self.filename, lineno, self.url_to_manual),
95 if text.rstrip() != "":
96 return ["{}:{}: should be a blank line ({}#writing-rules-mk)"
97 .format(self.filename, lineno, self.url_to_manual),
101 class RemoveDefaultPackageSourceVariable(_CheckFunction):
102 packages_that_may_contain_default_source = ["binutils", "gcc", "gdb"]
103 PACKAGE_NAME = re.compile("/([^/]+)\.mk")
106 package = self.PACKAGE_NAME.search(self.filename).group(1)
107 package_upper = package.replace("-", "_").upper()
108 self.package = package
109 self.FIND_SOURCE = re.compile(
110 "^{}_SOURCE\s*=\s*{}-\$\({}_VERSION\)\.tar\.gz"
111 .format(package_upper, package, package_upper))
113 def check_line(self, lineno, text):
114 if self.FIND_SOURCE.search(text):
116 if self.package in self.packages_that_may_contain_default_source:
119 return ["{}:{}: remove default value of _SOURCE variable "
120 "({}#generic-package-reference)"
121 .format(self.filename, lineno, self.url_to_manual),
125 class SpaceBeforeBackslash(_CheckFunction):
126 TAB_OR_MULTIPLE_SPACES_BEFORE_BACKSLASH = re.compile(r"^.*( |\t)\\$")
128 def check_line(self, lineno, text):
129 if self.TAB_OR_MULTIPLE_SPACES_BEFORE_BACKSLASH.match(text.rstrip()):
130 return ["{}:{}: use only one space before backslash"
131 .format(self.filename, lineno),
135 class TrailingBackslash(_CheckFunction):
136 ENDS_WITH_BACKSLASH = re.compile(r"^[^#].*\\$")
139 self.backslash = False
141 def check_line(self, lineno, text):
142 last_line_ends_in_backslash = self.backslash
144 # calculate for next line
145 if self.ENDS_WITH_BACKSLASH.search(text):
146 self.backslash = True
149 self.backslash = False
151 if last_line_ends_in_backslash and text.strip() == "":
152 return ["{}:{}: remove trailing backslash"
153 .format(self.filename, lineno - 1),
157 class TypoInPackageVariable(_CheckFunction):
158 ALLOWED = re.compile("|".join([
161 "BR_CCACHE_INITIAL_SETUP",
162 "BR_NO_CHECK_HASH_FOR",
163 "LINUX_POST_PATCH_HOOKS",
168 "PKG_CONFIG_HOST_BINARY",
169 "TARGET_FINALIZE_HOOKS",
170 "XTENSA_CORE_NAME"]))
171 PACKAGE_NAME = re.compile("/([^/]+)\.mk")
172 VARIABLE = re.compile("^([A-Z0-9_]+_[A-Z0-9_]+)\s*(\+|)=")
175 package = self.PACKAGE_NAME.search(self.filename).group(1)
176 package = package.replace("-", "_").upper()
177 # linux tools do not use LINUX_TOOL_ prefix for variables
178 package = package.replace("LINUX_TOOL_", "")
179 self.package = package
180 self.REGEX = re.compile("^(HOST_)?({}_[A-Z0-9_]+)".format(package))
181 self.FIND_VIRTUAL = re.compile(
182 "^{}_PROVIDES\s*(\+|)=\s*(.*)".format(package))
185 def check_line(self, lineno, text):
186 m = self.VARIABLE.search(text)
190 variable = m.group(1)
192 # allow to set variables for virtual package this package provides
193 v = self.FIND_VIRTUAL.search(text)
195 self.virtual += v.group(2).upper().split()
197 for virtual in self.virtual:
198 if variable.startswith("{}_".format(virtual)):
201 if self.ALLOWED.match(variable):
203 if self.REGEX.search(text) is None:
204 return ["{}:{}: possible typo: {} -> *{}*"
205 .format(self.filename, lineno, variable, self.package),
209 class UselessFlag(_CheckFunction):
210 DEFAULT_AUTOTOOLS_FLAG = re.compile("^.*{}".format("|".join([
211 "_AUTORECONF\s*=\s*NO",
212 "_LIBTOOL_PATCH\s*=\s*YES"])))
213 DEFAULT_GENERIC_FLAG = re.compile("^.*{}".format("|".join([
214 "_INSTALL_IMAGES\s*=\s*NO",
215 "_INSTALL_REDISTRIBUTE\s*=\s*YES",
216 "_INSTALL_STAGING\s*=\s*NO",
217 "_INSTALL_TARGET\s*=\s*YES"])))
218 END_CONDITIONAL = re.compile("^\s*(endif)")
219 START_CONDITIONAL = re.compile("^\s*(ifeq|ifneq)")
224 def check_line(self, lineno, text):
225 if self.START_CONDITIONAL.search(text):
226 self.conditional += 1
228 if self.END_CONDITIONAL.search(text):
229 self.conditional -= 1
232 # allow non-default conditionally overridden by default
233 if self.conditional > 0:
236 if self.DEFAULT_GENERIC_FLAG.search(text):
237 return ["{}:{}: useless default value ({}#"
238 "_infrastructure_for_packages_with_specific_build_systems)"
239 .format(self.filename, lineno, self.url_to_manual),
242 if self.DEFAULT_AUTOTOOLS_FLAG.search(text) and not text.lstrip().startswith("HOST_"):
243 return ["{}:{}: useless default value "
244 "({}#_infrastructure_for_autotools_based_packages)"
245 .format(self.filename, lineno, self.url_to_manual),