blob: 643ab78df7a5c4280dfbda6312dae1b87ce7251a [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
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500129def all_distro_features(d, features, truevalue="1", falsevalue=""):
130 """
131 Returns truevalue if *all* given features are set in DISTRO_FEATURES,
132 else falsevalue. The features can be given as single string or anything
133 that can be turned into a set.
134
135 This is a shorter, more flexible version of
136 bb.utils.contains("DISTRO_FEATURES", features, truevalue, falsevalue, d).
137
138 Without explicit true/false values it can be used directly where
139 Python expects a boolean:
140 if oe.utils.all_distro_features(d, "foo bar"):
141 bb.fatal("foo and bar are mutually exclusive DISTRO_FEATURES")
142
143 With just a truevalue, it can be used to include files that are meant to be
144 used only when requested via DISTRO_FEATURES:
145 require ${@ oe.utils.all_distro_features(d, "foo bar", "foo-and-bar.inc")
146 """
147 return bb.utils.contains("DISTRO_FEATURES", features, truevalue, falsevalue, d)
148
149def any_distro_features(d, features, truevalue="1", falsevalue=""):
150 """
151 Returns truevalue if at least *one* of the given features is set in DISTRO_FEATURES,
152 else falsevalue. The features can be given as single string or anything
153 that can be turned into a set.
154
155 This is a shorter, more flexible version of
156 bb.utils.contains_any("DISTRO_FEATURES", features, truevalue, falsevalue, d).
157
158 Without explicit true/false values it can be used directly where
159 Python expects a boolean:
160 if not oe.utils.any_distro_features(d, "foo bar"):
161 bb.fatal("foo, bar or both must be set in DISTRO_FEATURES")
162
163 With just a truevalue, it can be used to include files that are meant to be
164 used only when requested via DISTRO_FEATURES:
165 require ${@ oe.utils.any_distro_features(d, "foo bar", "foo-or-bar.inc")
166
167 """
168 return bb.utils.contains_any("DISTRO_FEATURES", features, truevalue, falsevalue, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500169
170def packages_filter_out_system(d):
171 """
172 Return a list of packages from PACKAGES with the "system" packages such as
173 PN-dbg PN-doc PN-locale-eb-gb removed.
174 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500175 pn = d.getVar('PN')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600176 blacklist = [pn + suffix for suffix in ('', '-dbg', '-dev', '-doc', '-locale', '-staticdev')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500177 localepkg = pn + "-locale-"
178 pkgs = []
179
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500180 for pkg in d.getVar('PACKAGES').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 if pkg not in blacklist and localepkg not in pkg:
182 pkgs.append(pkg)
183 return pkgs
184
185def getstatusoutput(cmd):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500186 return subprocess.getstatusoutput(cmd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187
188
189def trim_version(version, num_parts=2):
190 """
191 Return just the first <num_parts> of <version>, split by periods. For
192 example, trim_version("1.2.3", 2) will return "1.2".
193 """
194 if type(version) is not str:
195 raise TypeError("Version should be a string")
196 if num_parts < 1:
197 raise ValueError("Cannot split to parts < 1")
198
199 parts = version.split(".")
200 trimmed = ".".join(parts[:num_parts])
201 return trimmed
202
203def cpu_count():
204 import multiprocessing
205 return multiprocessing.cpu_count()
206
207def execute_pre_post_process(d, cmds):
208 if cmds is None:
209 return
210
211 for cmd in cmds.strip().split(';'):
212 cmd = cmd.strip()
213 if cmd != '':
214 bb.note("Executing %s ..." % cmd)
215 bb.build.exec_func(cmd, d)
216
217def multiprocess_exec(commands, function):
218 import signal
219 import multiprocessing
220
221 if not commands:
222 return []
223
224 def init_worker():
225 signal.signal(signal.SIGINT, signal.SIG_IGN)
226
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500227 fails = []
228
229 def failures(res):
230 fails.append(res)
231
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232 nproc = min(multiprocessing.cpu_count(), len(commands))
233 pool = bb.utils.multiprocessingpool(nproc, init_worker)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500234
235 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500236 mapresult = pool.map_async(function, commands, error_callback=failures)
237
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500238 pool.close()
239 pool.join()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500240 results = mapresult.get()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500241 except KeyboardInterrupt:
242 pool.terminate()
243 pool.join()
244 raise
245
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500246 if fails:
247 raise fails[0]
248
249 return results
250
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500251def squashspaces(string):
252 import re
253 return re.sub("\s+", " ", string).strip()
254
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500255def format_pkg_list(pkg_dict, ret_format=None):
256 output = []
257
258 if ret_format == "arch":
259 for pkg in sorted(pkg_dict):
260 output.append("%s %s" % (pkg, pkg_dict[pkg]["arch"]))
261 elif ret_format == "file":
262 for pkg in sorted(pkg_dict):
263 output.append("%s %s %s" % (pkg, pkg_dict[pkg]["filename"], pkg_dict[pkg]["arch"]))
264 elif ret_format == "ver":
265 for pkg in sorted(pkg_dict):
266 output.append("%s %s %s" % (pkg, pkg_dict[pkg]["arch"], pkg_dict[pkg]["ver"]))
267 elif ret_format == "deps":
268 for pkg in sorted(pkg_dict):
269 for dep in pkg_dict[pkg]["deps"]:
270 output.append("%s|%s" % (pkg, dep))
271 else:
272 for pkg in sorted(pkg_dict):
273 output.append(pkg)
274
275 return '\n'.join(output)
276
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500277def host_gcc_version(d):
278 import re, subprocess
279
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500280 compiler = d.getVar("BUILD_CC")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500281 try:
282 env = os.environ.copy()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500283 env["PATH"] = d.getVar("PATH")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500284 output = subprocess.check_output("%s --version" % compiler, shell=True, env=env).decode("utf-8")
285 except subprocess.CalledProcessError as e:
286 bb.fatal("Error running %s --version: %s" % (compiler, e.output.decode("utf-8")))
287
288 match = re.match(".* (\d\.\d)\.\d.*", output.split('\n')[0])
289 if not match:
290 bb.fatal("Can't get compiler version from %s --version output" % compiler)
291
292 version = match.group(1)
293 return "-%s" % version if version in ("4.8", "4.9") else ""
294
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295#
296# Python 2.7 doesn't have threaded pools (just multiprocessing)
297# so implement a version here
298#
299
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600300from queue import Queue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301from threading import Thread
302
303class ThreadedWorker(Thread):
304 """Thread executing tasks from a given tasks queue"""
305 def __init__(self, tasks, worker_init, worker_end):
306 Thread.__init__(self)
307 self.tasks = tasks
308 self.daemon = True
309
310 self.worker_init = worker_init
311 self.worker_end = worker_end
312
313 def run(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600314 from queue import Empty
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500315
316 if self.worker_init is not None:
317 self.worker_init(self)
318
319 while True:
320 try:
321 func, args, kargs = self.tasks.get(block=False)
322 except Empty:
323 if self.worker_end is not None:
324 self.worker_end(self)
325 break
326
327 try:
328 func(self, *args, **kargs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600329 except Exception as e:
330 print(e)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500331 finally:
332 self.tasks.task_done()
333
334class ThreadedPool:
335 """Pool of threads consuming tasks from a queue"""
336 def __init__(self, num_workers, num_tasks, worker_init=None,
337 worker_end=None):
338 self.tasks = Queue(num_tasks)
339 self.workers = []
340
341 for _ in range(num_workers):
342 worker = ThreadedWorker(self.tasks, worker_init, worker_end)
343 self.workers.append(worker)
344
345 def start(self):
346 for worker in self.workers:
347 worker.start()
348
349 def add_task(self, func, *args, **kargs):
350 """Add a task to the queue"""
351 self.tasks.put((func, args, kargs))
352
353 def wait_completion(self):
354 """Wait for completion of all the tasks in the queue"""
355 self.tasks.join()
356 for worker in self.workers:
357 worker.join()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500358
359def write_ld_so_conf(d):
360 # Some utils like prelink may not have the correct target library paths
361 # so write an ld.so.conf to help them
362 ldsoconf = d.expand("${STAGING_DIR_TARGET}${sysconfdir}/ld.so.conf")
363 if os.path.exists(ldsoconf):
364 bb.utils.remove(ldsoconf)
365 bb.utils.mkdirhier(os.path.dirname(ldsoconf))
366 with open(ldsoconf, "w") as f:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500367 f.write(d.getVar("base_libdir") + '\n')
368 f.write(d.getVar("libdir") + '\n')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600369
370class ImageQAFailed(bb.build.FuncFailed):
371 def __init__(self, description, name=None, logfile=None):
372 self.description = description
373 self.name = name
374 self.logfile=logfile
375
376 def __str__(self):
377 msg = 'Function failed: %s' % self.name
378 if self.description:
379 msg = msg + ' (%s)' % self.description
380
381 return msg