1# 2# BitBake Build System Python Library 3# 4# Copyright (C) 2003 Holger Schurig 5# Copyright (C) 2003, 2004 Chris Larson 6# 7# Based on Gentoo's portage.py. 8# 9# SPDX-License-Identifier: GPL-2.0-only 10# 11 12__version__ = "2.12.0" 13 14import sys 15if sys.version_info < (3, 9, 0): 16 raise RuntimeError("Sorry, python 3.9.0 or later is required for this version of bitbake") 17 18if sys.version_info < (3, 10, 0): 19 # With python 3.8 and 3.9, we see errors of "libgcc_s.so.1 must be installed for pthread_cancel to work" 20 # https://stackoverflow.com/questions/64797838/libgcc-s-so-1-must-be-installed-for-pthread-cancel-to-work 21 # https://bugs.ams1.psf.io/issue42888 22 # so ensure libgcc_s is loaded early on 23 import ctypes 24 libgcc_s = ctypes.CDLL('libgcc_s.so.1') 25 26class BBHandledException(Exception): 27 """ 28 The big dilemma for generic bitbake code is what information to give the user 29 when an exception occurs. Any exception inheriting this base exception class 30 has already provided information to the user via some 'fired' message type such as 31 an explicitly fired event using bb.fire, or a bb.error message. If bitbake 32 encounters an exception derived from this class, no backtrace or other information 33 will be given to the user, its assumed the earlier event provided the relevant information. 34 """ 35 pass 36 37import os 38import logging 39from collections import namedtuple 40 41 42class NullHandler(logging.Handler): 43 def emit(self, record): 44 pass 45 46class BBLoggerMixin(object): 47 def __init__(self, *args, **kwargs): 48 # Does nothing to allow calling super() from derived classes 49 pass 50 51 def setup_bblogger(self, name): 52 if name.split(".")[0] == "BitBake": 53 self.debug = self._debug_helper 54 55 def _debug_helper(self, *args, **kwargs): 56 return self.bbdebug(1, *args, **kwargs) 57 58 def debug2(self, *args, **kwargs): 59 return self.bbdebug(2, *args, **kwargs) 60 61 def debug3(self, *args, **kwargs): 62 return self.bbdebug(3, *args, **kwargs) 63 64 def bbdebug(self, level, msg, *args, **kwargs): 65 loglevel = logging.DEBUG - level + 1 66 if not bb.event.worker_pid: 67 if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]): 68 return 69 if loglevel < bb.msg.loggerDefaultLogLevel: 70 return 71 72 if not isinstance(level, int) or not isinstance(msg, str): 73 mainlogger.warning("Invalid arguments in bbdebug: %s" % repr((level, msg,) + args)) 74 75 return self.log(loglevel, msg, *args, **kwargs) 76 77 def plain(self, msg, *args, **kwargs): 78 return self.log(logging.INFO + 1, msg, *args, **kwargs) 79 80 def verbose(self, msg, *args, **kwargs): 81 return self.log(logging.INFO - 1, msg, *args, **kwargs) 82 83 def verbnote(self, msg, *args, **kwargs): 84 return self.log(logging.INFO + 2, msg, *args, **kwargs) 85 86 def warnonce(self, msg, *args, **kwargs): 87 return self.log(logging.WARNING - 1, msg, *args, **kwargs) 88 89 def erroronce(self, msg, *args, **kwargs): 90 return self.log(logging.ERROR - 1, msg, *args, **kwargs) 91 92 93Logger = logging.getLoggerClass() 94class BBLogger(Logger, BBLoggerMixin): 95 def __init__(self, name, *args, **kwargs): 96 self.setup_bblogger(name) 97 super().__init__(name, *args, **kwargs) 98 99logging.raiseExceptions = False 100logging.setLoggerClass(BBLogger) 101 102class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin): 103 def __init__(self, logger, *args, **kwargs): 104 self.setup_bblogger(logger.name) 105 super().__init__(logger, *args, **kwargs) 106 107logging.LoggerAdapter = BBLoggerAdapter 108 109logger = logging.getLogger("BitBake") 110logger.addHandler(NullHandler()) 111logger.setLevel(logging.DEBUG - 2) 112 113mainlogger = logging.getLogger("BitBake.Main") 114 115class PrefixLoggerAdapter(logging.LoggerAdapter): 116 def __init__(self, prefix, logger): 117 super().__init__(logger, {}) 118 self.__msg_prefix = prefix 119 120 def process(self, msg, kwargs): 121 return "%s%s" %(self.__msg_prefix, msg), kwargs 122 123# This has to be imported after the setLoggerClass, as the import of bb.msg 124# can result in construction of the various loggers. 125import bb.msg 126 127from bb import fetch2 as fetch 128sys.modules['bb.fetch'] = sys.modules['bb.fetch2'] 129 130# Messaging convenience functions 131def plain(*args): 132 """ 133 Prints a message at "plain" level (higher level than a ``bb.note()``). 134 135 Arguments: 136 137 - ``args``: one or more strings to print. 138 """ 139 mainlogger.plain(''.join(args)) 140 141def debug(lvl, *args): 142 """ 143 Prints a debug message. 144 145 Arguments: 146 147 - ``lvl``: debug level. Higher value increases the debug level 148 (determined by ``bitbake -D``). 149 - ``args``: one or more strings to print. 150 """ 151 if isinstance(lvl, str): 152 mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl) 153 args = (lvl,) + args 154 lvl = 1 155 mainlogger.bbdebug(lvl, ''.join(args)) 156 157def note(*args): 158 """ 159 Prints a message at "note" level. 160 161 Arguments: 162 163 - ``args``: one or more strings to print. 164 """ 165 mainlogger.info(''.join(args)) 166 167def verbnote(*args): 168 """ 169 A higher priority note which will show on the console but isn't a warning. 170 171 Use in contexts when something is happening the user should be aware of but 172 they probably did something to make it happen. 173 174 Arguments: 175 176 - ``args``: one or more strings to print. 177 """ 178 mainlogger.verbnote(''.join(args)) 179 180# 181# Warnings - things the user likely needs to pay attention to and fix 182# 183def warn(*args): 184 """ 185 Prints a warning message. 186 187 Arguments: 188 189 - ``args``: one or more strings to print. 190 """ 191 mainlogger.warning(''.join(args)) 192 193def warnonce(*args): 194 """ 195 Prints a warning message like ``bb.warn()``, but only prints the message 196 once. 197 198 Arguments: 199 200 - ``args``: one or more strings to print. 201 """ 202 mainlogger.warnonce(''.join(args)) 203 204def error(*args, **kwargs): 205 """ 206 Prints an error message. 207 208 Arguments: 209 210 - ``args``: one or more strings to print. 211 """ 212 mainlogger.error(''.join(args), extra=kwargs) 213 214def erroronce(*args): 215 """ 216 Prints an error message like ``bb.error()``, but only prints the message 217 once. 218 219 Arguments: 220 221 - ``args``: one or more strings to print. 222 """ 223 mainlogger.erroronce(''.join(args)) 224 225def fatal(*args, **kwargs): 226 """ 227 Prints an error message and stops the BitBake execution. 228 229 Arguments: 230 231 - ``args``: one or more strings to print. 232 """ 233 mainlogger.critical(''.join(args), extra=kwargs) 234 raise BBHandledException() 235 236def deprecated(func, name=None, advice=""): 237 """This is a decorator which can be used to mark functions 238 as deprecated. It will result in a warning being emitted 239 when the function is used.""" 240 import warnings 241 242 if advice: 243 advice = ": %s" % advice 244 if name is None: 245 name = func.__name__ 246 247 def newFunc(*args, **kwargs): 248 warnings.warn("Call to deprecated function %s%s." % (name, 249 advice), 250 category=DeprecationWarning, 251 stacklevel=2) 252 return func(*args, **kwargs) 253 newFunc.__name__ = func.__name__ 254 newFunc.__doc__ = func.__doc__ 255 newFunc.__dict__.update(func.__dict__) 256 return newFunc 257 258# For compatibility 259def deprecate_import(current, modulename, fromlist, renames = None): 260 """Import objects from one module into another, wrapping them with a DeprecationWarning""" 261 262 module = __import__(modulename, fromlist = fromlist) 263 for position, objname in enumerate(fromlist): 264 obj = getattr(module, objname) 265 newobj = deprecated(obj, "{0}.{1}".format(current, objname), 266 "Please use {0}.{1} instead".format(modulename, objname)) 267 if renames: 268 newname = renames[position] 269 else: 270 newname = objname 271 272 setattr(sys.modules[current], newname, newobj) 273 274TaskData = namedtuple("TaskData", [ 275 "pn", 276 "taskname", 277 "fn", 278 "deps", 279 "provides", 280 "taskhash", 281 "unihash", 282 "hashfn", 283 "taskhash_deps", 284]) 285