xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/data.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun"""
2*4882a593SmuzhiyunBitBake 'Data' implementations
3*4882a593Smuzhiyun
4*4882a593SmuzhiyunFunctions for interacting with the data structure used by the
5*4882a593SmuzhiyunBitBake build tools.
6*4882a593Smuzhiyun
7*4882a593SmuzhiyunThe expandKeys and update_data are the most expensive
8*4882a593Smuzhiyunoperations. At night the cookie monster came by and
9*4882a593Smuzhiyunsuggested 'give me cookies on setting the variables and
10*4882a593Smuzhiyunthings will work out'. Taking this suggestion into account
11*4882a593Smuzhiyunapplying the skills from the not yet passed 'Entwurf und
12*4882a593SmuzhiyunAnalyse von Algorithmen' lecture and the cookie
13*4882a593Smuzhiyunmonster seems to be right. We will track setVar more carefully
14*4882a593Smuzhiyunto have faster update_data and expandKeys operations.
15*4882a593Smuzhiyun
16*4882a593SmuzhiyunThis is a trade-off between speed and memory again but
17*4882a593Smuzhiyunthe speed is more critical here.
18*4882a593Smuzhiyun"""
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun# Copyright (C) 2003, 2004  Chris Larson
21*4882a593Smuzhiyun# Copyright (C) 2005        Holger Hans Peter Freyther
22*4882a593Smuzhiyun#
23*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only
24*4882a593Smuzhiyun#
25*4882a593Smuzhiyun# Based on functions from the base bb module, Copyright 2003 Holger Schurig
26*4882a593Smuzhiyun
27*4882a593Smuzhiyunimport sys, os, re
28*4882a593Smuzhiyunimport hashlib
29*4882a593Smuzhiyunif sys.argv[0][-5:] == "pydoc":
30*4882a593Smuzhiyun    path = os.path.dirname(os.path.dirname(sys.argv[1]))
31*4882a593Smuzhiyunelse:
32*4882a593Smuzhiyun    path = os.path.dirname(os.path.dirname(sys.argv[0]))
33*4882a593Smuzhiyunsys.path.insert(0, path)
34*4882a593Smuzhiyunfrom itertools import groupby
35*4882a593Smuzhiyun
36*4882a593Smuzhiyunfrom bb import data_smart
37*4882a593Smuzhiyunfrom bb import codeparser
38*4882a593Smuzhiyunimport bb
39*4882a593Smuzhiyun
40*4882a593Smuzhiyunlogger = data_smart.logger
41*4882a593Smuzhiyun_dict_type = data_smart.DataSmart
42*4882a593Smuzhiyun
43*4882a593Smuzhiyundef init():
44*4882a593Smuzhiyun    """Return a new object representing the Bitbake data"""
45*4882a593Smuzhiyun    return _dict_type()
46*4882a593Smuzhiyun
47*4882a593Smuzhiyundef init_db(parent = None):
48*4882a593Smuzhiyun    """Return a new object representing the Bitbake data,
49*4882a593Smuzhiyun    optionally based on an existing object"""
50*4882a593Smuzhiyun    if parent is not None:
51*4882a593Smuzhiyun        return parent.createCopy()
52*4882a593Smuzhiyun    else:
53*4882a593Smuzhiyun        return _dict_type()
54*4882a593Smuzhiyun
55*4882a593Smuzhiyundef createCopy(source):
56*4882a593Smuzhiyun    """Link the source set to the destination
57*4882a593Smuzhiyun    If one does not find the value in the destination set,
58*4882a593Smuzhiyun    search will go on to the source set to get the value.
59*4882a593Smuzhiyun    Value from source are copy-on-write. i.e. any try to
60*4882a593Smuzhiyun    modify one of them will end up putting the modified value
61*4882a593Smuzhiyun    in the destination set.
62*4882a593Smuzhiyun    """
63*4882a593Smuzhiyun    return source.createCopy()
64*4882a593Smuzhiyun
65*4882a593Smuzhiyundef initVar(var, d):
66*4882a593Smuzhiyun    """Non-destructive var init for data structure"""
67*4882a593Smuzhiyun    d.initVar(var)
68*4882a593Smuzhiyun
69*4882a593Smuzhiyundef keys(d):
70*4882a593Smuzhiyun    """Return a list of keys in d"""
71*4882a593Smuzhiyun    return d.keys()
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
75*4882a593Smuzhiyun__expand_python_regexp__ = re.compile(r"\${@.+?}")
76*4882a593Smuzhiyun
77*4882a593Smuzhiyundef expand(s, d, varname = None):
78*4882a593Smuzhiyun    """Variable expansion using the data store"""
79*4882a593Smuzhiyun    return d.expand(s, varname)
80*4882a593Smuzhiyun
81*4882a593Smuzhiyundef expandKeys(alterdata, readdata = None):
82*4882a593Smuzhiyun    if readdata is None:
83*4882a593Smuzhiyun        readdata = alterdata
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun    todolist = {}
86*4882a593Smuzhiyun    for key in alterdata:
87*4882a593Smuzhiyun        if not '${' in key:
88*4882a593Smuzhiyun            continue
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun        ekey = expand(key, readdata)
91*4882a593Smuzhiyun        if key == ekey:
92*4882a593Smuzhiyun            continue
93*4882a593Smuzhiyun        todolist[key] = ekey
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun    # These two for loops are split for performance to maximise the
96*4882a593Smuzhiyun    # usefulness of the expand cache
97*4882a593Smuzhiyun    for key in sorted(todolist):
98*4882a593Smuzhiyun        ekey = todolist[key]
99*4882a593Smuzhiyun        newval = alterdata.getVar(ekey, False)
100*4882a593Smuzhiyun        if newval is not None:
101*4882a593Smuzhiyun            val = alterdata.getVar(key, False)
102*4882a593Smuzhiyun            if val is not None:
103*4882a593Smuzhiyun                bb.warn("Variable key %s (%s) replaces original key %s (%s)." % (key, val, ekey, newval))
104*4882a593Smuzhiyun        alterdata.renameVar(key, ekey)
105*4882a593Smuzhiyun
106*4882a593Smuzhiyundef inheritFromOS(d, savedenv, permitted):
107*4882a593Smuzhiyun    """Inherit variables from the initial environment."""
108*4882a593Smuzhiyun    exportlist = bb.utils.preserved_envvars_exported()
109*4882a593Smuzhiyun    for s in savedenv.keys():
110*4882a593Smuzhiyun        if s in permitted:
111*4882a593Smuzhiyun            try:
112*4882a593Smuzhiyun                d.setVar(s, savedenv.getVar(s), op = 'from env')
113*4882a593Smuzhiyun                if s in exportlist:
114*4882a593Smuzhiyun                    d.setVarFlag(s, "export", True, op = 'auto env export')
115*4882a593Smuzhiyun            except TypeError:
116*4882a593Smuzhiyun                pass
117*4882a593Smuzhiyun
118*4882a593Smuzhiyundef emit_var(var, o=sys.__stdout__, d = init(), all=False):
119*4882a593Smuzhiyun    """Emit a variable to be sourced by a shell."""
120*4882a593Smuzhiyun    func = d.getVarFlag(var, "func", False)
121*4882a593Smuzhiyun    if d.getVarFlag(var, 'python', False) and func:
122*4882a593Smuzhiyun        return False
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun    export = d.getVarFlag(var, "export", False)
125*4882a593Smuzhiyun    unexport = d.getVarFlag(var, "unexport", False)
126*4882a593Smuzhiyun    if not all and not export and not unexport and not func:
127*4882a593Smuzhiyun        return False
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun    try:
130*4882a593Smuzhiyun        if all:
131*4882a593Smuzhiyun            oval = d.getVar(var, False)
132*4882a593Smuzhiyun        val = d.getVar(var)
133*4882a593Smuzhiyun    except (KeyboardInterrupt):
134*4882a593Smuzhiyun        raise
135*4882a593Smuzhiyun    except Exception as exc:
136*4882a593Smuzhiyun        o.write('# expansion of %s threw %s: %s\n' % (var, exc.__class__.__name__, str(exc)))
137*4882a593Smuzhiyun        return False
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun    if all:
140*4882a593Smuzhiyun        d.varhistory.emit(var, oval, val, o, d)
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun    if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
143*4882a593Smuzhiyun        return False
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun    varExpanded = d.expand(var)
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun    if unexport:
148*4882a593Smuzhiyun        o.write('unset %s\n' % varExpanded)
149*4882a593Smuzhiyun        return False
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun    if val is None:
152*4882a593Smuzhiyun        return False
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun    val = str(val)
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun    if varExpanded.startswith("BASH_FUNC_"):
157*4882a593Smuzhiyun        varExpanded = varExpanded[10:-2]
158*4882a593Smuzhiyun        val = val[3:] # Strip off "() "
159*4882a593Smuzhiyun        o.write("%s() %s\n" % (varExpanded, val))
160*4882a593Smuzhiyun        o.write("export -f %s\n" % (varExpanded))
161*4882a593Smuzhiyun        return True
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun    if func:
164*4882a593Smuzhiyun        # Write a comment indicating where the shell function came from (line number and filename) to make it easier
165*4882a593Smuzhiyun        # for the user to diagnose task failures. This comment is also used by build.py to determine the metadata
166*4882a593Smuzhiyun        # location of shell functions.
167*4882a593Smuzhiyun        o.write("# line: {0}, file: {1}\n".format(
168*4882a593Smuzhiyun            d.getVarFlag(var, "lineno", False),
169*4882a593Smuzhiyun            d.getVarFlag(var, "filename", False)))
170*4882a593Smuzhiyun        # NOTE: should probably check for unbalanced {} within the var
171*4882a593Smuzhiyun        val = val.rstrip('\n')
172*4882a593Smuzhiyun        o.write("%s() {\n%s\n}\n" % (varExpanded, val))
173*4882a593Smuzhiyun        return 1
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun    if export:
176*4882a593Smuzhiyun        o.write('export ')
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun    # if we're going to output this within doublequotes,
179*4882a593Smuzhiyun    # to a shell, we need to escape the quotes in the var
180*4882a593Smuzhiyun    alter = re.sub('"', '\\"', val)
181*4882a593Smuzhiyun    alter = re.sub('\n', ' \\\n', alter)
182*4882a593Smuzhiyun    alter = re.sub('\\$', '\\\\$', alter)
183*4882a593Smuzhiyun    o.write('%s="%s"\n' % (varExpanded, alter))
184*4882a593Smuzhiyun    return False
185*4882a593Smuzhiyun
186*4882a593Smuzhiyundef emit_env(o=sys.__stdout__, d = init(), all=False):
187*4882a593Smuzhiyun    """Emits all items in the data store in a format such that it can be sourced by a shell."""
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun    isfunc = lambda key: bool(d.getVarFlag(key, "func", False))
190*4882a593Smuzhiyun    keys = sorted((key for key in d.keys() if not key.startswith("__")), key=isfunc)
191*4882a593Smuzhiyun    grouped = groupby(keys, isfunc)
192*4882a593Smuzhiyun    for isfunc, keys in grouped:
193*4882a593Smuzhiyun        for key in sorted(keys):
194*4882a593Smuzhiyun            emit_var(key, o, d, all and not isfunc) and o.write('\n')
195*4882a593Smuzhiyun
196*4882a593Smuzhiyundef exported_keys(d):
197*4882a593Smuzhiyun    return (key for key in d.keys() if not key.startswith('__') and
198*4882a593Smuzhiyun                                      d.getVarFlag(key, 'export', False) and
199*4882a593Smuzhiyun                                      not d.getVarFlag(key, 'unexport', False))
200*4882a593Smuzhiyun
201*4882a593Smuzhiyundef exported_vars(d):
202*4882a593Smuzhiyun    k = list(exported_keys(d))
203*4882a593Smuzhiyun    for key in k:
204*4882a593Smuzhiyun        try:
205*4882a593Smuzhiyun            value = d.getVar(key)
206*4882a593Smuzhiyun        except Exception as err:
207*4882a593Smuzhiyun            bb.warn("%s: Unable to export ${%s}: %s" % (d.getVar("FILE"), key, err))
208*4882a593Smuzhiyun            continue
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun        if value is not None:
211*4882a593Smuzhiyun            yield key, str(value)
212*4882a593Smuzhiyun
213*4882a593Smuzhiyundef emit_func(func, o=sys.__stdout__, d = init()):
214*4882a593Smuzhiyun    """Emits all items in the data store in a format such that it can be sourced by a shell."""
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun    keys = (key for key in d.keys() if not key.startswith("__") and not d.getVarFlag(key, "func", False))
217*4882a593Smuzhiyun    for key in sorted(keys):
218*4882a593Smuzhiyun        emit_var(key, o, d, False)
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun    o.write('\n')
221*4882a593Smuzhiyun    emit_var(func, o, d, False) and o.write('\n')
222*4882a593Smuzhiyun    newdeps = bb.codeparser.ShellParser(func, logger).parse_shell(d.getVar(func))
223*4882a593Smuzhiyun    newdeps |= set((d.getVarFlag(func, "vardeps") or "").split())
224*4882a593Smuzhiyun    seen = set()
225*4882a593Smuzhiyun    while newdeps:
226*4882a593Smuzhiyun        deps = newdeps
227*4882a593Smuzhiyun        seen |= deps
228*4882a593Smuzhiyun        newdeps = set()
229*4882a593Smuzhiyun        for dep in sorted(deps):
230*4882a593Smuzhiyun            if d.getVarFlag(dep, "func", False) and not d.getVarFlag(dep, "python", False):
231*4882a593Smuzhiyun               emit_var(dep, o, d, False) and o.write('\n')
232*4882a593Smuzhiyun               newdeps |=  bb.codeparser.ShellParser(dep, logger).parse_shell(d.getVar(dep))
233*4882a593Smuzhiyun               newdeps |= set((d.getVarFlag(dep, "vardeps") or "").split())
234*4882a593Smuzhiyun        newdeps -= seen
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun_functionfmt = """
237*4882a593Smuzhiyundef {function}(d):
238*4882a593Smuzhiyun{body}"""
239*4882a593Smuzhiyun
240*4882a593Smuzhiyundef emit_func_python(func, o=sys.__stdout__, d = init()):
241*4882a593Smuzhiyun    """Emits all items in the data store in a format such that it can be sourced by a shell."""
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun    def write_func(func, o, call = False):
244*4882a593Smuzhiyun        body = d.getVar(func, False)
245*4882a593Smuzhiyun        if not body.startswith("def"):
246*4882a593Smuzhiyun            body = _functionfmt.format(function=func, body=body)
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun        o.write(body.strip() + "\n\n")
249*4882a593Smuzhiyun        if call:
250*4882a593Smuzhiyun            o.write(func + "(d)" + "\n\n")
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun    write_func(func, o, True)
253*4882a593Smuzhiyun    pp = bb.codeparser.PythonParser(func, logger)
254*4882a593Smuzhiyun    pp.parse_python(d.getVar(func, False))
255*4882a593Smuzhiyun    newdeps = pp.execs
256*4882a593Smuzhiyun    newdeps |= set((d.getVarFlag(func, "vardeps") or "").split())
257*4882a593Smuzhiyun    seen = set()
258*4882a593Smuzhiyun    while newdeps:
259*4882a593Smuzhiyun        deps = newdeps
260*4882a593Smuzhiyun        seen |= deps
261*4882a593Smuzhiyun        newdeps = set()
262*4882a593Smuzhiyun        for dep in deps:
263*4882a593Smuzhiyun            if d.getVarFlag(dep, "func", False) and d.getVarFlag(dep, "python", False):
264*4882a593Smuzhiyun               write_func(dep, o)
265*4882a593Smuzhiyun               pp = bb.codeparser.PythonParser(dep, logger)
266*4882a593Smuzhiyun               pp.parse_python(d.getVar(dep, False))
267*4882a593Smuzhiyun               newdeps |= pp.execs
268*4882a593Smuzhiyun               newdeps |= set((d.getVarFlag(dep, "vardeps") or "").split())
269*4882a593Smuzhiyun        newdeps -= seen
270*4882a593Smuzhiyun
271*4882a593Smuzhiyundef update_data(d):
272*4882a593Smuzhiyun    """Performs final steps upon the datastore, including application of overrides"""
273*4882a593Smuzhiyun    d.finalize(parent = True)
274*4882a593Smuzhiyun
275*4882a593Smuzhiyundef build_dependencies(key, keys, shelldeps, varflagsexcl, ignored_vars, d):
276*4882a593Smuzhiyun    deps = set()
277*4882a593Smuzhiyun    try:
278*4882a593Smuzhiyun        if key[-1] == ']':
279*4882a593Smuzhiyun            vf = key[:-1].split('[')
280*4882a593Smuzhiyun            if vf[1] == "vardepvalueexclude":
281*4882a593Smuzhiyun                return deps, ""
282*4882a593Smuzhiyun            value, parser = d.getVarFlag(vf[0], vf[1], False, retparser=True)
283*4882a593Smuzhiyun            deps |= parser.references
284*4882a593Smuzhiyun            deps = deps | (keys & parser.execs)
285*4882a593Smuzhiyun            return deps, value
286*4882a593Smuzhiyun        varflags = d.getVarFlags(key, ["vardeps", "vardepvalue", "vardepsexclude", "exports", "postfuncs", "prefuncs", "lineno", "filename"]) or {}
287*4882a593Smuzhiyun        vardeps = varflags.get("vardeps")
288*4882a593Smuzhiyun        exclusions = varflags.get("vardepsexclude", "").split()
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun        def handle_contains(value, contains, exclusions, d):
291*4882a593Smuzhiyun            newvalue = []
292*4882a593Smuzhiyun            if value:
293*4882a593Smuzhiyun                newvalue.append(str(value))
294*4882a593Smuzhiyun            for k in sorted(contains):
295*4882a593Smuzhiyun                if k in exclusions or k in ignored_vars:
296*4882a593Smuzhiyun                    continue
297*4882a593Smuzhiyun                l = (d.getVar(k) or "").split()
298*4882a593Smuzhiyun                for item in sorted(contains[k]):
299*4882a593Smuzhiyun                    for word in item.split():
300*4882a593Smuzhiyun                        if not word in l:
301*4882a593Smuzhiyun                            newvalue.append("\n%s{%s} = Unset" % (k, item))
302*4882a593Smuzhiyun                            break
303*4882a593Smuzhiyun                    else:
304*4882a593Smuzhiyun                        newvalue.append("\n%s{%s} = Set" % (k, item))
305*4882a593Smuzhiyun            return "".join(newvalue)
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun        def handle_remove(value, deps, removes, d):
308*4882a593Smuzhiyun            for r in sorted(removes):
309*4882a593Smuzhiyun                r2 = d.expandWithRefs(r, None)
310*4882a593Smuzhiyun                value += "\n_remove of %s" % r
311*4882a593Smuzhiyun                deps |= r2.references
312*4882a593Smuzhiyun                deps = deps | (keys & r2.execs)
313*4882a593Smuzhiyun            return value
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun        if "vardepvalue" in varflags:
316*4882a593Smuzhiyun            value = varflags.get("vardepvalue")
317*4882a593Smuzhiyun        elif varflags.get("func"):
318*4882a593Smuzhiyun            if varflags.get("python"):
319*4882a593Smuzhiyun                value = d.getVarFlag(key, "_content", False)
320*4882a593Smuzhiyun                parser = bb.codeparser.PythonParser(key, logger)
321*4882a593Smuzhiyun                parser.parse_python(value, filename=varflags.get("filename"), lineno=varflags.get("lineno"))
322*4882a593Smuzhiyun                deps = deps | parser.references
323*4882a593Smuzhiyun                deps = deps | (keys & parser.execs)
324*4882a593Smuzhiyun                value = handle_contains(value, parser.contains, exclusions, d)
325*4882a593Smuzhiyun            else:
326*4882a593Smuzhiyun                value, parsedvar = d.getVarFlag(key, "_content", False, retparser=True)
327*4882a593Smuzhiyun                parser = bb.codeparser.ShellParser(key, logger)
328*4882a593Smuzhiyun                parser.parse_shell(parsedvar.value)
329*4882a593Smuzhiyun                deps = deps | shelldeps
330*4882a593Smuzhiyun                deps = deps | parsedvar.references
331*4882a593Smuzhiyun                deps = deps | (keys & parser.execs) | (keys & parsedvar.execs)
332*4882a593Smuzhiyun                value = handle_contains(value, parsedvar.contains, exclusions, d)
333*4882a593Smuzhiyun                if hasattr(parsedvar, "removes"):
334*4882a593Smuzhiyun                    value = handle_remove(value, deps, parsedvar.removes, d)
335*4882a593Smuzhiyun            if vardeps is None:
336*4882a593Smuzhiyun                parser.log.flush()
337*4882a593Smuzhiyun            if "prefuncs" in varflags:
338*4882a593Smuzhiyun                deps = deps | set(varflags["prefuncs"].split())
339*4882a593Smuzhiyun            if "postfuncs" in varflags:
340*4882a593Smuzhiyun                deps = deps | set(varflags["postfuncs"].split())
341*4882a593Smuzhiyun            if "exports" in varflags:
342*4882a593Smuzhiyun                deps = deps | set(varflags["exports"].split())
343*4882a593Smuzhiyun        else:
344*4882a593Smuzhiyun            value, parser = d.getVarFlag(key, "_content", False, retparser=True)
345*4882a593Smuzhiyun            deps |= parser.references
346*4882a593Smuzhiyun            deps = deps | (keys & parser.execs)
347*4882a593Smuzhiyun            value = handle_contains(value, parser.contains, exclusions, d)
348*4882a593Smuzhiyun            if hasattr(parser, "removes"):
349*4882a593Smuzhiyun                value = handle_remove(value, deps, parser.removes, d)
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun        if "vardepvalueexclude" in varflags:
352*4882a593Smuzhiyun            exclude = varflags.get("vardepvalueexclude")
353*4882a593Smuzhiyun            for excl in exclude.split('|'):
354*4882a593Smuzhiyun                if excl:
355*4882a593Smuzhiyun                    value = value.replace(excl, '')
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun        # Add varflags, assuming an exclusion list is set
358*4882a593Smuzhiyun        if varflagsexcl:
359*4882a593Smuzhiyun            varfdeps = []
360*4882a593Smuzhiyun            for f in varflags:
361*4882a593Smuzhiyun                if f not in varflagsexcl:
362*4882a593Smuzhiyun                    varfdeps.append('%s[%s]' % (key, f))
363*4882a593Smuzhiyun            if varfdeps:
364*4882a593Smuzhiyun                deps |= set(varfdeps)
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun        deps |= set((vardeps or "").split())
367*4882a593Smuzhiyun        deps -= set(exclusions)
368*4882a593Smuzhiyun    except bb.parse.SkipRecipe:
369*4882a593Smuzhiyun        raise
370*4882a593Smuzhiyun    except Exception as e:
371*4882a593Smuzhiyun        bb.warn("Exception during build_dependencies for %s" % key)
372*4882a593Smuzhiyun        raise
373*4882a593Smuzhiyun    return deps, value
374*4882a593Smuzhiyun    #bb.note("Variable %s references %s and calls %s" % (key, str(deps), str(execs)))
375*4882a593Smuzhiyun    #d.setVarFlag(key, "vardeps", deps)
376*4882a593Smuzhiyun
377*4882a593Smuzhiyundef generate_dependencies(d, ignored_vars):
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun    keys = set(key for key in d if not key.startswith("__"))
380*4882a593Smuzhiyun    shelldeps = set(key for key in d.getVar("__exportlist", False) if d.getVarFlag(key, "export", False) and not d.getVarFlag(key, "unexport", False))
381*4882a593Smuzhiyun    varflagsexcl = d.getVar('BB_SIGNATURE_EXCLUDE_FLAGS')
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun    deps = {}
384*4882a593Smuzhiyun    values = {}
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun    tasklist = d.getVar('__BBTASKS', False) or []
387*4882a593Smuzhiyun    for task in tasklist:
388*4882a593Smuzhiyun        deps[task], values[task] = build_dependencies(task, keys, shelldeps, varflagsexcl, ignored_vars, d)
389*4882a593Smuzhiyun        newdeps = deps[task]
390*4882a593Smuzhiyun        seen = set()
391*4882a593Smuzhiyun        while newdeps:
392*4882a593Smuzhiyun            nextdeps = newdeps - ignored_vars
393*4882a593Smuzhiyun            seen |= nextdeps
394*4882a593Smuzhiyun            newdeps = set()
395*4882a593Smuzhiyun            for dep in nextdeps:
396*4882a593Smuzhiyun                if dep not in deps:
397*4882a593Smuzhiyun                    deps[dep], values[dep] = build_dependencies(dep, keys, shelldeps, varflagsexcl, ignored_vars, d)
398*4882a593Smuzhiyun                newdeps |=  deps[dep]
399*4882a593Smuzhiyun            newdeps -= seen
400*4882a593Smuzhiyun        #print "For %s: %s" % (task, str(deps[task]))
401*4882a593Smuzhiyun    return tasklist, deps, values
402*4882a593Smuzhiyun
403*4882a593Smuzhiyundef generate_dependency_hash(tasklist, gendeps, lookupcache, ignored_vars, fn):
404*4882a593Smuzhiyun    taskdeps = {}
405*4882a593Smuzhiyun    basehash = {}
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun    for task in tasklist:
408*4882a593Smuzhiyun        data = lookupcache[task]
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun        if data is None:
411*4882a593Smuzhiyun            bb.error("Task %s from %s seems to be empty?!" % (task, fn))
412*4882a593Smuzhiyun            data = []
413*4882a593Smuzhiyun        else:
414*4882a593Smuzhiyun            data = [data]
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun        gendeps[task] -= ignored_vars
417*4882a593Smuzhiyun        newdeps = gendeps[task]
418*4882a593Smuzhiyun        seen = set()
419*4882a593Smuzhiyun        while newdeps:
420*4882a593Smuzhiyun            nextdeps = newdeps
421*4882a593Smuzhiyun            seen |= nextdeps
422*4882a593Smuzhiyun            newdeps = set()
423*4882a593Smuzhiyun            for dep in nextdeps:
424*4882a593Smuzhiyun                if dep in ignored_vars:
425*4882a593Smuzhiyun                    continue
426*4882a593Smuzhiyun                gendeps[dep] -= ignored_vars
427*4882a593Smuzhiyun                newdeps |= gendeps[dep]
428*4882a593Smuzhiyun            newdeps -= seen
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun        alldeps = sorted(seen)
431*4882a593Smuzhiyun        for dep in alldeps:
432*4882a593Smuzhiyun            data.append(dep)
433*4882a593Smuzhiyun            var = lookupcache[dep]
434*4882a593Smuzhiyun            if var is not None:
435*4882a593Smuzhiyun                data.append(str(var))
436*4882a593Smuzhiyun        k = fn + ":" + task
437*4882a593Smuzhiyun        basehash[k] = hashlib.sha256("".join(data).encode("utf-8")).hexdigest()
438*4882a593Smuzhiyun        taskdeps[task] = alldeps
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun    return taskdeps, basehash
441*4882a593Smuzhiyun
442*4882a593Smuzhiyundef inherits_class(klass, d):
443*4882a593Smuzhiyun    val = d.getVar('__inherit_cache', False) or []
444*4882a593Smuzhiyun    needle = os.path.join('classes', '%s.bbclass' % klass)
445*4882a593Smuzhiyun    for v in val:
446*4882a593Smuzhiyun        if v.endswith(needle):
447*4882a593Smuzhiyun            return True
448*4882a593Smuzhiyun    return False
449