blob: 330a5ff94a6fdbef59d0d5f35ce7fb0c527093a3 [file] [log] [blame]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002
3def read_file(filename):
4 try:
5 f = open( filename, "r" )
6 except IOError as reason:
7 return "" # WARNING: can't raise an error now because of the new RDEPENDS handling. This is a bit ugly. :M:
8 else:
9 data = f.read().strip()
10 f.close()
11 return data
12 return None
13
14def ifelse(condition, iftrue = True, iffalse = False):
15 if condition:
16 return iftrue
17 else:
18 return iffalse
19
20def conditional(variable, checkvalue, truevalue, falsevalue, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050021 if d.getVar(variable) == checkvalue:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022 return truevalue
23 else:
24 return falsevalue
25
26def less_or_equal(variable, checkvalue, truevalue, falsevalue, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050027 if float(d.getVar(variable)) <= float(checkvalue):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028 return truevalue
29 else:
30 return falsevalue
31
32def version_less_or_equal(variable, checkvalue, truevalue, falsevalue, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050033 result = bb.utils.vercmp_string(d.getVar(variable), checkvalue)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034 if result <= 0:
35 return truevalue
36 else:
37 return falsevalue
38
39def both_contain(variable1, variable2, checkvalue, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050040 val1 = d.getVar(variable1)
41 val2 = d.getVar(variable2)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042 val1 = set(val1.split())
43 val2 = set(val2.split())
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044 if isinstance(checkvalue, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045 checkvalue = set(checkvalue.split())
46 else:
47 checkvalue = set(checkvalue)
48 if checkvalue.issubset(val1) and checkvalue.issubset(val2):
49 return " ".join(checkvalue)
50 else:
51 return ""
52
53def set_intersect(variable1, variable2, d):
54 """
55 Expand both variables, interpret them as lists of strings, and return the
56 intersection as a flattened string.
57
58 For example:
59 s1 = "a b c"
60 s2 = "b c d"
61 s3 = set_intersect(s1, s2)
62 => s3 = "b c"
63 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -050064 val1 = set(d.getVar(variable1).split())
65 val2 = set(d.getVar(variable2).split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -050066 return " ".join(val1 & val2)
67
68def prune_suffix(var, suffixes, d):
69 # See if var ends with any of the suffixes listed and
70 # remove it if found
71 for suffix in suffixes:
72 if var.endswith(suffix):
73 var = var.replace(suffix, "")
74
Brad Bishop6e60e8b2018-02-01 10:27:11 -050075 prefix = d.getVar("MLPREFIX")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 if prefix and var.startswith(prefix):
77 var = var.replace(prefix, "")
78
79 return var
80
81def str_filter(f, str, d):
82 from re import match
Patrick Williamsc0f7c042017-02-23 20:41:17 -060083 return " ".join([x for x in str.split() if match(f, x, 0)])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084
85def str_filter_out(f, str, d):
86 from re import match
Patrick Williamsc0f7c042017-02-23 20:41:17 -060087 return " ".join([x for x in str.split() if not match(f, x, 0)])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050088
89def param_bool(cfg, field, dflt = None):
90 """Lookup <field> in <cfg> map and convert it to a boolean; take
91 <dflt> when this <field> does not exist"""
92 value = cfg.get(field, dflt)
93 strvalue = str(value).lower()
94 if strvalue in ('yes', 'y', 'true', 't', '1'):
95 return True
96 elif strvalue in ('no', 'n', 'false', 'f', '0'):
97 return False
98 raise ValueError("invalid value for boolean parameter '%s': '%s'" % (field, value))
99
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500100def build_depends_string(depends, task):
101 """Append a taskname to a string of dependencies as used by the [depends] flag"""
102 return " ".join(dep + ":" + task for dep in depends.split())
103
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104def inherits(d, *classes):
105 """Return True if the metadata inherits any of the specified classes"""
106 return any(bb.data.inherits_class(cls, d) for cls in classes)
107
108def features_backfill(var,d):
109 # This construct allows the addition of new features to variable specified
110 # as var
111 # Example for var = "DISTRO_FEATURES"
112 # This construct allows the addition of new features to DISTRO_FEATURES
113 # that if not present would disable existing functionality, without
114 # disturbing distributions that have already set DISTRO_FEATURES.
115 # Distributions wanting to elide a value in DISTRO_FEATURES_BACKFILL should
116 # add the feature to DISTRO_FEATURES_BACKFILL_CONSIDERED
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500117 features = (d.getVar(var) or "").split()
118 backfill = (d.getVar(var+"_BACKFILL") or "").split()
119 considered = (d.getVar(var+"_BACKFILL_CONSIDERED") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120
121 addfeatures = []
122 for feature in backfill:
123 if feature not in features and feature not in considered:
124 addfeatures.append(feature)
125
126 if addfeatures:
127 d.appendVar(var, " " + " ".join(addfeatures))
128
129
130def packages_filter_out_system(d):
131 """
132 Return a list of packages from PACKAGES with the "system" packages such as
133 PN-dbg PN-doc PN-locale-eb-gb removed.
134 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500135 pn = d.getVar('PN')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600136 blacklist = [pn + suffix for suffix in ('', '-dbg', '-dev', '-doc', '-locale', '-staticdev')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137 localepkg = pn + "-locale-"
138 pkgs = []
139
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500140 for pkg in d.getVar('PACKAGES').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141 if pkg not in blacklist and localepkg not in pkg:
142 pkgs.append(pkg)
143 return pkgs
144
145def getstatusoutput(cmd):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500146 return subprocess.getstatusoutput(cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147
148
149def trim_version(version, num_parts=2):
150 """
151 Return just the first <num_parts> of <version>, split by periods. For
152 example, trim_version("1.2.3", 2) will return "1.2".
153 """
154 if type(version) is not str:
155 raise TypeError("Version should be a string")
156 if num_parts < 1:
157 raise ValueError("Cannot split to parts < 1")
158
159 parts = version.split(".")
160 trimmed = ".".join(parts[:num_parts])
161 return trimmed
162
163def cpu_count():
164 import multiprocessing
165 return multiprocessing.cpu_count()
166
167def execute_pre_post_process(d, cmds):
168 if cmds is None:
169 return
170
171 for cmd in cmds.strip().split(';'):
172 cmd = cmd.strip()
173 if cmd != '':
174 bb.note("Executing %s ..." % cmd)
175 bb.build.exec_func(cmd, d)
176
177def multiprocess_exec(commands, function):
178 import signal
179 import multiprocessing
180
181 if not commands:
182 return []
183
184 def init_worker():
185 signal.signal(signal.SIGINT, signal.SIG_IGN)
186
187 nproc = min(multiprocessing.cpu_count(), len(commands))
188 pool = bb.utils.multiprocessingpool(nproc, init_worker)
189 imap = pool.imap(function, commands)
190
191 try:
192 res = list(imap)
193 pool.close()
194 pool.join()
195 results = []
196 for result in res:
197 if result is not None:
198 results.append(result)
199 return results
200
201 except KeyboardInterrupt:
202 pool.terminate()
203 pool.join()
204 raise
205
206def squashspaces(string):
207 import re
208 return re.sub("\s+", " ", string).strip()
209
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500210def format_pkg_list(pkg_dict, ret_format=None):
211 output = []
212
213 if ret_format == "arch":
214 for pkg in sorted(pkg_dict):
215 output.append("%s %s" % (pkg, pkg_dict[pkg]["arch"]))
216 elif ret_format == "file":
217 for pkg in sorted(pkg_dict):
218 output.append("%s %s %s" % (pkg, pkg_dict[pkg]["filename"], pkg_dict[pkg]["arch"]))
219 elif ret_format == "ver":
220 for pkg in sorted(pkg_dict):
221 output.append("%s %s %s" % (pkg, pkg_dict[pkg]["arch"], pkg_dict[pkg]["ver"]))
222 elif ret_format == "deps":
223 for pkg in sorted(pkg_dict):
224 for dep in pkg_dict[pkg]["deps"]:
225 output.append("%s|%s" % (pkg, dep))
226 else:
227 for pkg in sorted(pkg_dict):
228 output.append(pkg)
229
230 return '\n'.join(output)
231
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500232def host_gcc_version(d):
233 import re, subprocess
234
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500235 compiler = d.getVar("BUILD_CC")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500236 try:
237 env = os.environ.copy()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500238 env["PATH"] = d.getVar("PATH")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500239 output = subprocess.check_output("%s --version" % compiler, shell=True, env=env).decode("utf-8")
240 except subprocess.CalledProcessError as e:
241 bb.fatal("Error running %s --version: %s" % (compiler, e.output.decode("utf-8")))
242
243 match = re.match(".* (\d\.\d)\.\d.*", output.split('\n')[0])
244 if not match:
245 bb.fatal("Can't get compiler version from %s --version output" % compiler)
246
247 version = match.group(1)
248 return "-%s" % version if version in ("4.8", "4.9") else ""
249
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250#
251# Python 2.7 doesn't have threaded pools (just multiprocessing)
252# so implement a version here
253#
254
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255from queue import Queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500256from threading import Thread
257
258class ThreadedWorker(Thread):
259 """Thread executing tasks from a given tasks queue"""
260 def __init__(self, tasks, worker_init, worker_end):
261 Thread.__init__(self)
262 self.tasks = tasks
263 self.daemon = True
264
265 self.worker_init = worker_init
266 self.worker_end = worker_end
267
268 def run(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600269 from queue import Empty
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500270
271 if self.worker_init is not None:
272 self.worker_init(self)
273
274 while True:
275 try:
276 func, args, kargs = self.tasks.get(block=False)
277 except Empty:
278 if self.worker_end is not None:
279 self.worker_end(self)
280 break
281
282 try:
283 func(self, *args, **kargs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600284 except Exception as e:
285 print(e)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500286 finally:
287 self.tasks.task_done()
288
289class ThreadedPool:
290 """Pool of threads consuming tasks from a queue"""
291 def __init__(self, num_workers, num_tasks, worker_init=None,
292 worker_end=None):
293 self.tasks = Queue(num_tasks)
294 self.workers = []
295
296 for _ in range(num_workers):
297 worker = ThreadedWorker(self.tasks, worker_init, worker_end)
298 self.workers.append(worker)
299
300 def start(self):
301 for worker in self.workers:
302 worker.start()
303
304 def add_task(self, func, *args, **kargs):
305 """Add a task to the queue"""
306 self.tasks.put((func, args, kargs))
307
308 def wait_completion(self):
309 """Wait for completion of all the tasks in the queue"""
310 self.tasks.join()
311 for worker in self.workers:
312 worker.join()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500313
314def write_ld_so_conf(d):
315 # Some utils like prelink may not have the correct target library paths
316 # so write an ld.so.conf to help them
317 ldsoconf = d.expand("${STAGING_DIR_TARGET}${sysconfdir}/ld.so.conf")
318 if os.path.exists(ldsoconf):
319 bb.utils.remove(ldsoconf)
320 bb.utils.mkdirhier(os.path.dirname(ldsoconf))
321 with open(ldsoconf, "w") as f:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500322 f.write(d.getVar("base_libdir") + '\n')
323 f.write(d.getVar("libdir") + '\n')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600324
325class ImageQAFailed(bb.build.FuncFailed):
326 def __init__(self, description, name=None, logfile=None):
327 self.description = description
328 self.name = name
329 self.logfile=logfile
330
331 def __str__(self):
332 msg = 'Function failed: %s' % self.name
333 if self.description:
334 msg = msg + ' (%s)' % self.description
335
336 return msg