2024-09-09 08:52:07 +00:00
|
|
|
# ex:ts=4:sw=4:sts=4:et
|
|
|
|
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
|
|
#
|
|
|
|
# BitBake 'Build' implementation
|
|
|
|
#
|
|
|
|
# Core code for function execution and task handling in the
|
|
|
|
# BitBake build tools.
|
|
|
|
#
|
|
|
|
# Copyright (C) 2003, 2004 Chris Larson
|
|
|
|
#
|
|
|
|
# Based on Gentoo's portage.py.
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
|
|
# published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along
|
|
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
#
|
2024-09-09 08:57:42 +00:00
|
|
|
# Based on functions from the base bb module, Copyright 2003 Holger Schurig
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import logging
|
|
|
|
import shlex
|
2024-09-09 08:57:42 +00:00
|
|
|
import glob
|
|
|
|
import time
|
2024-09-09 08:52:07 +00:00
|
|
|
import bb
|
|
|
|
import bb.msg
|
|
|
|
import bb.process
|
|
|
|
from contextlib import nested
|
2024-09-09 08:57:42 +00:00
|
|
|
from bb import event, utils
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
bblogger = logging.getLogger('BitBake')
|
|
|
|
logger = logging.getLogger('BitBake.Build')
|
|
|
|
|
|
|
|
NULL = open(os.devnull, 'r+')
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
# When we execute a Python function, we'd like certain things
|
|
|
|
# in all namespaces, hence we add them to __builtins__.
|
2024-09-09 08:52:07 +00:00
|
|
|
# If we do not do this and use the exec globals, they will
|
|
|
|
# not be available to subfunctions.
|
|
|
|
__builtins__['bb'] = bb
|
|
|
|
__builtins__['os'] = os
|
|
|
|
|
|
|
|
class FuncFailed(Exception):
|
|
|
|
def __init__(self, name = None, logfile = None):
|
|
|
|
self.logfile = logfile
|
|
|
|
self.name = name
|
|
|
|
if name:
|
|
|
|
self.msg = 'Function failed: %s' % name
|
|
|
|
else:
|
|
|
|
self.msg = "Function failed"
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
if self.logfile and os.path.exists(self.logfile):
|
2024-09-09 08:57:42 +00:00
|
|
|
msg = ("%s (log file is located at %s)" %
|
2024-09-09 08:52:07 +00:00
|
|
|
(self.msg, self.logfile))
|
|
|
|
else:
|
|
|
|
msg = self.msg
|
|
|
|
return msg
|
|
|
|
|
|
|
|
class TaskBase(event.Event):
|
|
|
|
"""Base class for task events"""
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def __init__(self, t, logfile, d):
|
2024-09-09 08:52:07 +00:00
|
|
|
self._task = t
|
2024-09-09 08:57:42 +00:00
|
|
|
self._package = d.getVar("PF", True)
|
|
|
|
self.taskfile = d.getVar("FILE", True)
|
|
|
|
self.taskname = self._task
|
|
|
|
self.logfile = logfile
|
|
|
|
self.time = time.time()
|
2024-09-09 08:52:07 +00:00
|
|
|
event.Event.__init__(self)
|
2024-09-09 08:57:42 +00:00
|
|
|
self._message = "recipe %s: task %s: %s" % (d.getVar("PF", True), t, self.getDisplayName())
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
def getTask(self):
|
|
|
|
return self._task
|
|
|
|
|
|
|
|
def setTask(self, task):
|
|
|
|
self._task = task
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def getDisplayName(self):
|
|
|
|
return bb.event.getName(self)[4:]
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
task = property(getTask, setTask, None, "task property")
|
|
|
|
|
|
|
|
class TaskStarted(TaskBase):
|
|
|
|
"""Task execution started"""
|
2024-09-09 08:57:42 +00:00
|
|
|
def __init__(self, t, logfile, taskflags, d):
|
|
|
|
super(TaskStarted, self).__init__(t, logfile, d)
|
|
|
|
self.taskflags = taskflags
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
class TaskSucceeded(TaskBase):
|
|
|
|
"""Task execution completed"""
|
|
|
|
|
|
|
|
class TaskFailed(TaskBase):
|
|
|
|
"""Task execution failed"""
|
|
|
|
|
|
|
|
def __init__(self, task, logfile, metadata, errprinted = False):
|
|
|
|
self.errprinted = errprinted
|
2024-09-09 08:57:42 +00:00
|
|
|
super(TaskFailed, self).__init__(task, logfile, metadata)
|
|
|
|
|
|
|
|
class TaskFailedSilent(TaskBase):
|
|
|
|
"""Task execution failed (silently)"""
|
|
|
|
def getDisplayName(self):
|
|
|
|
# Don't need to tell the user it was silent
|
|
|
|
return "Failed"
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
class TaskInvalid(TaskBase):
|
|
|
|
|
|
|
|
def __init__(self, task, metadata):
|
2024-09-09 08:57:42 +00:00
|
|
|
super(TaskInvalid, self).__init__(task, None, metadata)
|
2024-09-09 08:52:07 +00:00
|
|
|
self._message = "No such task '%s'" % task
|
|
|
|
|
|
|
|
|
|
|
|
class LogTee(object):
|
|
|
|
def __init__(self, logger, outfile):
|
|
|
|
self.outfile = outfile
|
|
|
|
self.logger = logger
|
|
|
|
self.name = self.outfile.name
|
|
|
|
|
|
|
|
def write(self, string):
|
|
|
|
self.logger.plain(string)
|
|
|
|
self.outfile.write(string)
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
self.outfile.__enter__()
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, *excinfo):
|
|
|
|
self.outfile.__exit__(*excinfo)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '<LogTee {0}>'.format(self.name)
|
2024-09-09 08:57:42 +00:00
|
|
|
def flush(self):
|
|
|
|
self.outfile.flush()
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
def exec_func(func, d, dirs = None):
|
2024-09-09 08:57:42 +00:00
|
|
|
"""Execute a BB 'function'"""
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
body = d.getVar(func)
|
2024-09-09 08:52:07 +00:00
|
|
|
if not body:
|
|
|
|
if body is None:
|
|
|
|
logger.warn("Function %s doesn't exist", func)
|
|
|
|
return
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
flags = d.getVarFlags(func)
|
2024-09-09 08:52:07 +00:00
|
|
|
cleandirs = flags.get('cleandirs')
|
|
|
|
if cleandirs:
|
2024-09-09 08:57:42 +00:00
|
|
|
for cdir in d.expand(cleandirs).split():
|
2024-09-09 08:52:07 +00:00
|
|
|
bb.utils.remove(cdir, True)
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.utils.mkdirhier(cdir)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
if dirs is None:
|
|
|
|
dirs = flags.get('dirs')
|
|
|
|
if dirs:
|
2024-09-09 08:57:42 +00:00
|
|
|
dirs = d.expand(dirs).split()
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
if dirs:
|
|
|
|
for adir in dirs:
|
|
|
|
bb.utils.mkdirhier(adir)
|
|
|
|
adir = dirs[-1]
|
|
|
|
else:
|
2024-09-09 08:57:42 +00:00
|
|
|
adir = d.getVar('B', True)
|
2024-09-09 08:52:07 +00:00
|
|
|
bb.utils.mkdirhier(adir)
|
|
|
|
|
|
|
|
ispython = flags.get('python')
|
|
|
|
|
|
|
|
lockflag = flags.get('lockfiles')
|
|
|
|
if lockflag:
|
2024-09-09 08:57:42 +00:00
|
|
|
lockfiles = [f for f in d.expand(lockflag).split()]
|
2024-09-09 08:52:07 +00:00
|
|
|
else:
|
|
|
|
lockfiles = None
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
tempdir = d.getVar('T', True)
|
|
|
|
|
|
|
|
# or func allows items to be executed outside of the normal
|
|
|
|
# task set, such as buildhistory
|
|
|
|
task = d.getVar('BB_RUNTASK', True) or func
|
|
|
|
if task == func:
|
|
|
|
taskfunc = task
|
|
|
|
else:
|
|
|
|
taskfunc = "%s.%s" % (task, func)
|
|
|
|
|
|
|
|
runfmt = d.getVar('BB_RUNFMT', True) or "run.{func}.{pid}"
|
|
|
|
runfn = runfmt.format(taskfunc=taskfunc, task=task, func=func, pid=os.getpid())
|
|
|
|
runfile = os.path.join(tempdir, runfn)
|
|
|
|
bb.utils.mkdirhier(os.path.dirname(runfile))
|
|
|
|
|
|
|
|
# Setup the courtesy link to the runfn, only for tasks
|
|
|
|
# we create the link 'just' before the run script is created
|
|
|
|
# if we create it after, and if the run script fails, then the
|
|
|
|
# link won't be created as an exception would be fired.
|
|
|
|
if task == func:
|
|
|
|
runlink = os.path.join(tempdir, 'run.{0}'.format(task))
|
|
|
|
if runlink:
|
|
|
|
bb.utils.remove(runlink)
|
|
|
|
|
|
|
|
try:
|
|
|
|
os.symlink(runfn, runlink)
|
|
|
|
except OSError:
|
|
|
|
pass
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
with bb.utils.fileslocked(lockfiles):
|
|
|
|
if ispython:
|
|
|
|
exec_func_python(func, d, runfile, cwd=adir)
|
|
|
|
else:
|
|
|
|
exec_func_shell(func, d, runfile, cwd=adir)
|
|
|
|
|
|
|
|
_functionfmt = """
|
|
|
|
def {function}(d):
|
|
|
|
{body}
|
|
|
|
|
|
|
|
{function}(d)
|
|
|
|
"""
|
|
|
|
logformatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
|
|
|
|
def exec_func_python(func, d, runfile, cwd=None):
|
|
|
|
"""Execute a python BB 'function'"""
|
|
|
|
|
|
|
|
bbfile = d.getVar('FILE', True)
|
|
|
|
code = _functionfmt.format(function=func, body=d.getVar(func, True))
|
|
|
|
bb.utils.mkdirhier(os.path.dirname(runfile))
|
|
|
|
with open(runfile, 'w') as script:
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.data.emit_func_python(func, script, d)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
if cwd:
|
|
|
|
try:
|
|
|
|
olddir = os.getcwd()
|
|
|
|
except OSError:
|
|
|
|
olddir = None
|
|
|
|
os.chdir(cwd)
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.debug(2, "Executing python function %s" % func)
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
try:
|
|
|
|
comp = utils.better_compile(code, func, bbfile)
|
|
|
|
utils.better_exec(comp, {"d": d}, code, bbfile)
|
2024-09-09 08:57:42 +00:00
|
|
|
except (bb.parse.SkipRecipe, bb.build.FuncFailed):
|
|
|
|
raise
|
2024-09-09 08:52:07 +00:00
|
|
|
except:
|
|
|
|
raise FuncFailed(func, None)
|
|
|
|
finally:
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.debug(2, "Python function %s finished" % func)
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
if cwd and olddir:
|
|
|
|
try:
|
|
|
|
os.chdir(olddir)
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def shell_trap_code():
|
|
|
|
return '''#!/bin/sh\n
|
|
|
|
# Emit a useful diagnostic if something fails:
|
|
|
|
bb_exit_handler() {
|
|
|
|
ret=$?
|
|
|
|
case $ret in
|
|
|
|
0) ;;
|
|
|
|
*) case $BASH_VERSION in
|
|
|
|
"") echo "WARNING: exit code $ret from a shell command.";;
|
|
|
|
*) echo "WARNING: ${BASH_SOURCE[0]}:${BASH_LINENO[0]} exit $ret from
|
|
|
|
\"$BASH_COMMAND\"";;
|
|
|
|
esac
|
|
|
|
exit $ret
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
trap 'bb_exit_handler' 0
|
|
|
|
set -e
|
|
|
|
'''
|
|
|
|
|
|
|
|
def exec_func_shell(func, d, runfile, cwd=None):
|
2024-09-09 08:52:07 +00:00
|
|
|
"""Execute a shell function from the metadata
|
|
|
|
|
|
|
|
Note on directory behavior. The 'dirs' varflag should contain a list
|
|
|
|
of the directories you need created prior to execution. The last
|
|
|
|
item in the list is where we will chdir/cd to.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# Don't let the emitted shell script override PWD
|
|
|
|
d.delVarFlag('PWD', 'export')
|
|
|
|
|
|
|
|
with open(runfile, 'w') as script:
|
2024-09-09 08:57:42 +00:00
|
|
|
script.write(shell_trap_code())
|
|
|
|
|
|
|
|
bb.data.emit_func(func, script, d)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if bb.msg.loggerVerboseLogs:
|
|
|
|
script.write("set -x\n")
|
2024-09-09 08:52:07 +00:00
|
|
|
if cwd:
|
2024-09-09 08:57:42 +00:00
|
|
|
script.write("cd '%s'\n" % cwd)
|
|
|
|
script.write("%s\n" % func)
|
|
|
|
script.write('''
|
|
|
|
# cleanup
|
|
|
|
ret=$?
|
|
|
|
trap '' 0
|
|
|
|
exit $?
|
|
|
|
''')
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
os.chmod(runfile, 0775)
|
|
|
|
|
|
|
|
cmd = runfile
|
2024-09-09 08:57:42 +00:00
|
|
|
if d.getVarFlag(func, 'fakeroot'):
|
2024-09-09 08:52:07 +00:00
|
|
|
fakerootcmd = d.getVar('FAKEROOT', True)
|
|
|
|
if fakerootcmd:
|
|
|
|
cmd = [fakerootcmd, runfile]
|
|
|
|
|
|
|
|
if bb.msg.loggerDefaultVerbose:
|
|
|
|
logfile = LogTee(logger, sys.stdout)
|
|
|
|
else:
|
|
|
|
logfile = sys.stdout
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.debug(2, "Executing shell function %s" % func)
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
try:
|
2024-09-09 08:57:42 +00:00
|
|
|
with open(os.devnull, 'r+') as stdin:
|
|
|
|
bb.process.run(cmd, shell=False, stdin=stdin, log=logfile)
|
2024-09-09 08:52:07 +00:00
|
|
|
except bb.process.CmdError:
|
|
|
|
logfn = d.getVar('BB_LOGFILE', True)
|
2024-09-09 08:57:42 +00:00
|
|
|
raise FuncFailed(func, logfn)
|
|
|
|
|
|
|
|
bb.debug(2, "Shell function %s finished" % func)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
def _task_data(fn, task, d):
|
2024-09-09 08:57:42 +00:00
|
|
|
localdata = bb.data.createCopy(d)
|
2024-09-09 08:52:07 +00:00
|
|
|
localdata.setVar('BB_FILENAME', fn)
|
|
|
|
localdata.setVar('BB_CURRENTTASK', task[3:])
|
|
|
|
localdata.setVar('OVERRIDES', 'task-%s:%s' %
|
2024-09-09 08:57:42 +00:00
|
|
|
(task[3:].replace('_', '-'), d.getVar('OVERRIDES', False)))
|
2024-09-09 08:52:07 +00:00
|
|
|
localdata.finalize()
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.data.expandKeys(localdata)
|
2024-09-09 08:52:07 +00:00
|
|
|
return localdata
|
|
|
|
|
|
|
|
def _exec_task(fn, task, d, quieterr):
|
|
|
|
"""Execute a BB 'task'
|
|
|
|
|
|
|
|
Execution of a task involves a bit more setup than executing a function,
|
|
|
|
running it with its own local metadata, and with some useful variables set.
|
|
|
|
"""
|
2024-09-09 08:57:42 +00:00
|
|
|
if not d.getVarFlag(task, 'task'):
|
2024-09-09 08:52:07 +00:00
|
|
|
event.fire(TaskInvalid(task, d), d)
|
|
|
|
logger.error("No such task: %s" % task)
|
|
|
|
return 1
|
|
|
|
|
|
|
|
logger.debug(1, "Executing task %s", task)
|
|
|
|
|
|
|
|
localdata = _task_data(fn, task, d)
|
|
|
|
tempdir = localdata.getVar('T', True)
|
|
|
|
if not tempdir:
|
|
|
|
bb.fatal("T variable not set, unable to build")
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
# Change nice level if we're asked to
|
|
|
|
nice = localdata.getVar("BB_TASK_NICE_LEVEL", True)
|
|
|
|
if nice:
|
|
|
|
curnice = os.nice(0)
|
|
|
|
nice = int(nice) - curnice
|
|
|
|
newnice = os.nice(nice)
|
|
|
|
logger.debug(1, "Renice to %s " % newnice)
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
bb.utils.mkdirhier(tempdir)
|
2024-09-09 08:57:42 +00:00
|
|
|
|
|
|
|
# Determine the logfile to generate
|
|
|
|
logfmt = localdata.getVar('BB_LOGFMT', True) or 'log.{task}.{pid}'
|
|
|
|
logbase = logfmt.format(task=task, pid=os.getpid())
|
|
|
|
|
|
|
|
# Document the order of the tasks...
|
|
|
|
logorder = os.path.join(tempdir, 'log.task_order')
|
|
|
|
try:
|
|
|
|
with open(logorder, 'a') as logorderfile:
|
|
|
|
logorderfile.write('{0} ({1}): {2}\n'.format(task, os.getpid(), logbase))
|
|
|
|
except OSError:
|
|
|
|
logger.exception("Opening log file '%s'", logorder)
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Setup the courtesy link to the logfn
|
2024-09-09 08:52:07 +00:00
|
|
|
loglink = os.path.join(tempdir, 'log.{0}'.format(task))
|
2024-09-09 08:57:42 +00:00
|
|
|
logfn = os.path.join(tempdir, logbase)
|
2024-09-09 08:52:07 +00:00
|
|
|
if loglink:
|
|
|
|
bb.utils.remove(loglink)
|
|
|
|
|
|
|
|
try:
|
2024-09-09 08:57:42 +00:00
|
|
|
os.symlink(logbase, loglink)
|
2024-09-09 08:52:07 +00:00
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
prefuncs = localdata.getVarFlag(task, 'prefuncs', expand=True)
|
|
|
|
postfuncs = localdata.getVarFlag(task, 'postfuncs', expand=True)
|
|
|
|
|
|
|
|
class ErrorCheckHandler(logging.Handler):
|
|
|
|
def __init__(self):
|
|
|
|
self.triggered = False
|
|
|
|
logging.Handler.__init__(self, logging.ERROR)
|
|
|
|
def emit(self, record):
|
|
|
|
self.triggered = True
|
|
|
|
|
|
|
|
# Handle logfiles
|
2024-09-09 08:57:42 +00:00
|
|
|
si = open('/dev/null', 'r')
|
2024-09-09 08:52:07 +00:00
|
|
|
try:
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.utils.mkdirhier(os.path.dirname(logfn))
|
|
|
|
logfile = open(logfn, 'w')
|
2024-09-09 08:52:07 +00:00
|
|
|
except OSError:
|
|
|
|
logger.exception("Opening log file '%s'", logfn)
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Dup the existing fds so we dont lose them
|
|
|
|
osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
|
|
|
|
oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
|
|
|
|
ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
|
|
|
|
|
|
|
|
# Replace those fds with our own
|
|
|
|
os.dup2(si.fileno(), osi[1])
|
|
|
|
os.dup2(logfile.fileno(), oso[1])
|
|
|
|
os.dup2(logfile.fileno(), ose[1])
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
# Ensure Python logging goes to the logfile
|
2024-09-09 08:52:07 +00:00
|
|
|
handler = logging.StreamHandler(logfile)
|
|
|
|
handler.setFormatter(logformatter)
|
|
|
|
# Always enable full debug output into task logfiles
|
|
|
|
handler.setLevel(logging.DEBUG - 2)
|
|
|
|
bblogger.addHandler(handler)
|
|
|
|
|
|
|
|
errchk = ErrorCheckHandler()
|
|
|
|
bblogger.addHandler(errchk)
|
|
|
|
|
|
|
|
localdata.setVar('BB_LOGFILE', logfn)
|
2024-09-09 08:57:42 +00:00
|
|
|
localdata.setVar('BB_RUNTASK', task)
|
|
|
|
|
|
|
|
flags = localdata.getVarFlags(task)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
event.fire(TaskStarted(task, logfn, flags, localdata), localdata)
|
2024-09-09 08:52:07 +00:00
|
|
|
try:
|
|
|
|
for func in (prefuncs or '').split():
|
|
|
|
exec_func(func, localdata)
|
|
|
|
exec_func(task, localdata)
|
|
|
|
for func in (postfuncs or '').split():
|
|
|
|
exec_func(func, localdata)
|
|
|
|
except FuncFailed as exc:
|
2024-09-09 08:57:42 +00:00
|
|
|
if quieterr:
|
|
|
|
event.fire(TaskFailedSilent(task, logfn, localdata), localdata)
|
|
|
|
else:
|
2024-09-09 08:52:07 +00:00
|
|
|
errprinted = errchk.triggered
|
|
|
|
logger.error(str(exc))
|
|
|
|
event.fire(TaskFailed(task, logfn, localdata, errprinted), localdata)
|
|
|
|
return 1
|
|
|
|
finally:
|
|
|
|
sys.stdout.flush()
|
|
|
|
sys.stderr.flush()
|
|
|
|
|
|
|
|
bblogger.removeHandler(handler)
|
|
|
|
|
|
|
|
# Restore the backup fds
|
|
|
|
os.dup2(osi[0], osi[1])
|
|
|
|
os.dup2(oso[0], oso[1])
|
|
|
|
os.dup2(ose[0], ose[1])
|
|
|
|
|
|
|
|
# Close the backup fds
|
|
|
|
os.close(osi[0])
|
|
|
|
os.close(oso[0])
|
|
|
|
os.close(ose[0])
|
|
|
|
si.close()
|
|
|
|
|
|
|
|
logfile.close()
|
|
|
|
if os.path.exists(logfn) and os.path.getsize(logfn) == 0:
|
|
|
|
logger.debug(2, "Zero size logfn %s, removing", logfn)
|
|
|
|
bb.utils.remove(logfn)
|
|
|
|
bb.utils.remove(loglink)
|
2024-09-09 08:57:42 +00:00
|
|
|
event.fire(TaskSucceeded(task, logfn, localdata), localdata)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
if not localdata.getVarFlag(task, 'nostamp') and not localdata.getVarFlag(task, 'selfstamp'):
|
|
|
|
make_stamp(task, localdata)
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def exec_task(fn, task, d, profile = False):
|
|
|
|
try:
|
2024-09-09 08:52:07 +00:00
|
|
|
quieterr = False
|
|
|
|
if d.getVarFlag(task, "quieterrors") is not None:
|
|
|
|
quieterr = True
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if profile:
|
|
|
|
profname = "profile-%s.log" % (d.getVar("PN", True) + "-" + task)
|
|
|
|
try:
|
|
|
|
import cProfile as profile
|
|
|
|
except:
|
|
|
|
import profile
|
|
|
|
prof = profile.Profile()
|
|
|
|
ret = profile.Profile.runcall(prof, _exec_task, fn, task, d, quieterr)
|
|
|
|
prof.dump_stats(profname)
|
|
|
|
bb.utils.process_profilelog(profname)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
else:
|
|
|
|
return _exec_task(fn, task, d, quieterr)
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
except Exception:
|
|
|
|
from traceback import format_exc
|
|
|
|
if not quieterr:
|
|
|
|
logger.error("Build of %s failed" % (task))
|
|
|
|
logger.error(format_exc())
|
|
|
|
failedevent = TaskFailed(task, None, d, True)
|
|
|
|
event.fire(failedevent, d)
|
|
|
|
return 1
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def stamp_internal(taskname, d, file_name, baseonly=False):
|
2024-09-09 08:52:07 +00:00
|
|
|
"""
|
|
|
|
Internal stamp helper function
|
|
|
|
Makes sure the stamp directory exists
|
|
|
|
Returns the stamp path+filename
|
|
|
|
|
|
|
|
In the bitbake core, d can be a CacheData and file_name will be set.
|
|
|
|
When called in task context, d will be a data store, file_name will not be set
|
|
|
|
"""
|
|
|
|
taskflagname = taskname
|
|
|
|
if taskname.endswith("_setscene") and taskname != "do_setscene":
|
|
|
|
taskflagname = taskname.replace("_setscene", "")
|
|
|
|
|
|
|
|
if file_name:
|
|
|
|
stamp = d.stamp_base[file_name].get(taskflagname) or d.stamp[file_name]
|
|
|
|
extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or ""
|
|
|
|
else:
|
|
|
|
stamp = d.getVarFlag(taskflagname, 'stamp-base', True) or d.getVar('STAMP', True)
|
|
|
|
file_name = d.getVar('BB_FILENAME', True)
|
|
|
|
extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info', True) or ""
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
if baseonly:
|
|
|
|
return stamp
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
if not stamp:
|
|
|
|
return
|
|
|
|
|
|
|
|
stamp = bb.parse.siggen.stampfile(stamp, file_name, taskname, extrainfo)
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
stampdir = os.path.dirname(stamp)
|
|
|
|
if bb.parse.cached_mtime_noerror(stampdir) == 0:
|
|
|
|
bb.utils.mkdirhier(stampdir)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
return stamp
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def stamp_cleanmask_internal(taskname, d, file_name):
|
|
|
|
"""
|
|
|
|
Internal stamp helper function to generate stamp cleaning mask
|
|
|
|
Returns the stamp path+filename
|
|
|
|
|
|
|
|
In the bitbake core, d can be a CacheData and file_name will be set.
|
|
|
|
When called in task context, d will be a data store, file_name will not be set
|
|
|
|
"""
|
|
|
|
taskflagname = taskname
|
|
|
|
if taskname.endswith("_setscene") and taskname != "do_setscene":
|
|
|
|
taskflagname = taskname.replace("_setscene", "")
|
|
|
|
|
|
|
|
if file_name:
|
|
|
|
stamp = d.stamp_base_clean[file_name].get(taskflagname) or d.stampclean[file_name]
|
|
|
|
extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or ""
|
|
|
|
else:
|
|
|
|
stamp = d.getVarFlag(taskflagname, 'stamp-base-clean', True) or d.getVar('STAMPCLEAN', True)
|
|
|
|
file_name = d.getVar('BB_FILENAME', True)
|
|
|
|
extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info', True) or ""
|
|
|
|
|
|
|
|
if not stamp:
|
|
|
|
return []
|
|
|
|
|
|
|
|
cleanmask = bb.parse.siggen.stampcleanmask(stamp, file_name, taskname, extrainfo)
|
|
|
|
|
|
|
|
return [cleanmask, cleanmask.replace(taskflagname, taskflagname + "_setscene")]
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
def make_stamp(task, d, file_name = None):
|
|
|
|
"""
|
|
|
|
Creates/updates a stamp for a given task
|
|
|
|
(d can be a data dict or dataCache)
|
|
|
|
"""
|
2024-09-09 08:57:42 +00:00
|
|
|
cleanmask = stamp_cleanmask_internal(task, d, file_name)
|
|
|
|
for mask in cleanmask:
|
|
|
|
for name in glob.glob(mask):
|
|
|
|
# Preserve sigdata files in the stamps directory
|
|
|
|
if "sigdata" in name:
|
|
|
|
continue
|
|
|
|
# Preserve taint files in the stamps directory
|
|
|
|
if name.endswith('.taint'):
|
|
|
|
continue
|
|
|
|
os.unlink(name)
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
stamp = stamp_internal(task, d, file_name)
|
|
|
|
# Remove the file and recreate to force timestamp
|
|
|
|
# change on broken NFS filesystems
|
|
|
|
if stamp:
|
|
|
|
bb.utils.remove(stamp)
|
2024-09-09 08:57:42 +00:00
|
|
|
open(stamp, "w").close()
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
# If we're in task context, write out a signature file for each task
|
|
|
|
# as it completes
|
|
|
|
if not task.endswith("_setscene") and task != "do_setscene" and not file_name:
|
2024-09-09 08:57:42 +00:00
|
|
|
stampbase = stamp_internal(task, d, None, True)
|
2024-09-09 08:52:07 +00:00
|
|
|
file_name = d.getVar('BB_FILENAME', True)
|
2024-09-09 08:57:42 +00:00
|
|
|
bb.parse.siggen.dump_sigtask(file_name, task, stampbase, True)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
def del_stamp(task, d, file_name = None):
|
|
|
|
"""
|
|
|
|
Removes a stamp for a given task
|
|
|
|
(d can be a data dict or dataCache)
|
|
|
|
"""
|
|
|
|
stamp = stamp_internal(task, d, file_name)
|
|
|
|
bb.utils.remove(stamp)
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def write_taint(task, d, file_name = None):
|
|
|
|
"""
|
|
|
|
Creates a "taint" file which will force the specified task and its
|
|
|
|
dependents to be re-run the next time by influencing the value of its
|
|
|
|
taskhash.
|
|
|
|
(d can be a data dict or dataCache)
|
|
|
|
"""
|
|
|
|
import uuid
|
|
|
|
if file_name:
|
|
|
|
taintfn = d.stamp[file_name] + '.' + task + '.taint'
|
|
|
|
else:
|
|
|
|
taintfn = d.getVar('STAMP', True) + '.' + task + '.taint'
|
|
|
|
bb.utils.mkdirhier(os.path.dirname(taintfn))
|
|
|
|
# The specific content of the taint file is not really important,
|
|
|
|
# we just need it to be random, so a random UUID is used
|
|
|
|
with open(taintfn, 'w') as taintf:
|
|
|
|
taintf.write(str(uuid.uuid4()))
|
|
|
|
|
2024-09-09 08:52:07 +00:00
|
|
|
def stampfile(taskname, d, file_name = None):
|
|
|
|
"""
|
|
|
|
Return the stamp for a given task
|
|
|
|
(d can be a data dict or dataCache)
|
|
|
|
"""
|
|
|
|
return stamp_internal(taskname, d, file_name)
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
def add_tasks(tasklist, deltasklist, d):
|
|
|
|
task_deps = d.getVar('_task_deps')
|
2024-09-09 08:52:07 +00:00
|
|
|
if not task_deps:
|
|
|
|
task_deps = {}
|
|
|
|
if not 'tasks' in task_deps:
|
|
|
|
task_deps['tasks'] = []
|
|
|
|
if not 'parents' in task_deps:
|
|
|
|
task_deps['parents'] = {}
|
|
|
|
|
|
|
|
for task in tasklist:
|
2024-09-09 08:57:42 +00:00
|
|
|
task = d.expand(task)
|
|
|
|
|
|
|
|
if task in deltasklist:
|
|
|
|
continue
|
|
|
|
|
|
|
|
d.setVarFlag(task, 'task', 1)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
if not task in task_deps['tasks']:
|
|
|
|
task_deps['tasks'].append(task)
|
|
|
|
|
2024-09-09 08:57:42 +00:00
|
|
|
flags = d.getVarFlags(task)
|
2024-09-09 08:52:07 +00:00
|
|
|
def getTask(name):
|
|
|
|
if not name in task_deps:
|
|
|
|
task_deps[name] = {}
|
|
|
|
if name in flags:
|
2024-09-09 08:57:42 +00:00
|
|
|
deptask = d.expand(flags[name])
|
2024-09-09 08:52:07 +00:00
|
|
|
task_deps[name][task] = deptask
|
|
|
|
getTask('depends')
|
2024-09-09 08:57:42 +00:00
|
|
|
getTask('rdepends')
|
2024-09-09 08:52:07 +00:00
|
|
|
getTask('deptask')
|
|
|
|
getTask('rdeptask')
|
|
|
|
getTask('recrdeptask')
|
2024-09-09 08:57:42 +00:00
|
|
|
getTask('recideptask')
|
2024-09-09 08:52:07 +00:00
|
|
|
getTask('nostamp')
|
|
|
|
getTask('fakeroot')
|
|
|
|
getTask('noexec')
|
|
|
|
getTask('umask')
|
|
|
|
task_deps['parents'][task] = []
|
2024-09-09 08:57:42 +00:00
|
|
|
if 'deps' in flags:
|
|
|
|
for dep in flags['deps']:
|
|
|
|
dep = d.expand(dep)
|
|
|
|
task_deps['parents'][task].append(dep)
|
2024-09-09 08:52:07 +00:00
|
|
|
|
|
|
|
# don't assume holding a reference
|
2024-09-09 08:57:42 +00:00
|
|
|
d.setVar('_task_deps', task_deps)
|
|
|
|
|
|
|
|
def addtask(task, before, after, d):
|
|
|
|
if task[:3] != "do_":
|
|
|
|
task = "do_" + task
|
|
|
|
|
|
|
|
d.setVarFlag(task, "task", 1)
|
|
|
|
bbtasks = d.getVar('__BBTASKS') or []
|
|
|
|
if not task in bbtasks:
|
|
|
|
bbtasks.append(task)
|
|
|
|
d.setVar('__BBTASKS', bbtasks)
|
|
|
|
|
|
|
|
existing = d.getVarFlag(task, "deps") or []
|
|
|
|
if after is not None:
|
|
|
|
# set up deps for function
|
|
|
|
for entry in after.split():
|
|
|
|
if entry not in existing:
|
|
|
|
existing.append(entry)
|
|
|
|
d.setVarFlag(task, "deps", existing)
|
|
|
|
if before is not None:
|
|
|
|
# set up things that depend on this func
|
|
|
|
for entry in before.split():
|
|
|
|
existing = d.getVarFlag(entry, "deps") or []
|
|
|
|
if task not in existing:
|
|
|
|
d.setVarFlag(entry, "deps", [task] + existing)
|
|
|
|
|
|
|
|
def deltask(task, d):
|
|
|
|
if task[:3] != "do_":
|
|
|
|
task = "do_" + task
|
|
|
|
|
|
|
|
bbtasks = d.getVar('__BBDELTASKS') or []
|
|
|
|
if not task in bbtasks:
|
|
|
|
bbtasks.append(task)
|
|
|
|
d.setVar('__BBDELTASKS', bbtasks)
|
2024-09-09 08:52:07 +00:00
|
|
|
|