File: DoAddDef.py

package info (click to toggle)
aap 1.072-1.1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k, lenny
  • size: 4,976 kB
  • ctags: 2,160
  • sloc: python: 15,113; makefile: 62; sh: 13
file content (482 lines) | stat: -rw-r--r-- 20,212 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# Part of the A-A-P recipe executive: Add default rules and dependencies

# Copyright (C) 2002-2003 Stichting NLnet Labs
# Permission to copy and use this file is specified in the file COPYING.
# If this file is missing you can find it here: http://www.a-a-p.org/COPYING

import string
import os.path

from Action import find_primary_action
from Dictlist import varname2dictlist, dictlist2str
from RecPos import RecPos, rpcopy
from Util import *
from Depend import Depend
from Message import *
from Process import Process, recipe_error
from ParsePos import ParsePos
from Scope import get_build_recdict
from DoBuild import find_autodep_items
from RecPython import srcitem2obj, topdir


def doadddef(work, recdict, toplevel):
    """
    Add default dependencies, depending on what was defined in the
    recipe(s) read.
    """
    # Add a dependency from $SOURCE and $TARGET if appropriate.
    add_source_target(work, recdict)

    # Add a comment to the useful targets we add here.
    caddlist = []
    for n, c in [("install", _("install files to directory $PREFIX")),
                 ("uninstall", _("delete installed files from directory $PREFIX")),
                 ("clean", _("delete all generated files that are not distributed")),
                 ("cleanmore", _("delete all generated files")),
                 ("cleanALL", _("delete all generated files, AAPDIR and build-* directories"))]:
        if not work.find_node(n):
            caddlist.append((n, c))

    # Add "clean" and "cleanmore" target if appropriate.
    add_clean(work, recdict)

    # At the toplevel we add more things.
    if toplevel:

        # Add the stuff for ports if $PORTNAME is defined.
        if recdict.get("PORTNAME"):
            from Port import add_port_defaults
            add_port_defaults(work)

        # Add "cleanALL" when not defined.
        add_optional_target(work, recdict, "cleanALL", [ "clean" ],
                ":tree . {dirname = AAPDIR}\n"
                " :del {f}{r} $name\n"
                ":tree . {dirname = build-.*}\n"
                " :del {f}{r} $name\n")

        # Add "install" and friends when not defined.
        # Also does the # "uninstall" variant.
        add_install_target(work, recdict, "install",
                [ "install-platform",
                  "install-shared" ],
                "@if has_target('install-local'):\n"
                " :update install-local\n")
        add_install_target(work, recdict, "install-platform",
                [ "install-exec",
                  "install-sbin",
                  "install-lib",
                  "install-dll",
                  "install-ltlib",
                  "install-conf" ],
                "@if has_target('install-platform-local'):\n"
                " :update install-platform-local\n")
        add_install_target(work, recdict, "install-shared",
                ["install-data",
                "install-man",
                "install-info",
                "install-include"],
                "@if has_target('install-shared-local'):\n"
                " :update install-shared-local\n")

        # These targets are all alike.
        for t in ["exec", "sbin", "lib", "dll", "ltlib", "conf",
                                             "data", "man", "info", "include"]:
            tup = string.upper(t)
            add_install_target(work, recdict, "install-%s" % t, [],
                    "@if _top.get('INSTALL_%s'):\n"
                    " :update $_top.INSTALL_%s\n"
                    " :do install%s $_top.INSTALL_%s\n" % (tup, tup, t, tup))

        # Add the comments after adding the dependencies.
        for n, c in caddlist:
            work.get_node(n, 1).set_attributes({"comment" : c})


def add_source_target(work, recdict):
    """
    Add build dependencies for $SOURCE and $TARGET for backwards compatibility.
    """

    # If $SOURCE and $TARGET are defined at the toplevel in "recdict", $TARGET
    # is one item and there is no dependency with $TARGET as target that
    # includes build commands, create one from $SOURCE and $TARGET.  Can be
    # used for the main and a child recipe.
    if recdict.get("TARGET") and recdict.get("SOURCE"):
        targets = varname2dictlist(recdict, None, "TARGET")
        if len(targets) == 1:
            msg_warning(recdict, _("Warning: support for $SOURCE and $TARGET will be removed soon"))
            target = work.find_node(targets[0]["name"])
            if not target or not target.get_first_build_dependency():
                sources = varname2dictlist(recdict, None, "SOURCE")
                add_buildrule([RecPos("Default target")], work, recdict,
                                           "program", {}, targets, {}, sources)


def add_clean(work, recdict):
    """
    Add "clean" build dependency for the current recipe if there isn't one.
    Do the same for "cleanmore", but it also depends on "clean".
    """
    for (trg, TRG, srclist) in [("clean", "CLEAN", []),
                              ("cleanmore", "CLEANMORE", [{"name": "clean"}])]:
        target = work.find_node(trg)
        if not target or not target.get_recipe_build_dependency(recdict):
            cmd = (   ("@if _recipe.get('%sFILES'):\n" % TRG)
                    + (" :del {f} $_recipe.%sFILES\n" % TRG)
                    + ("@if _recipe.get('%sDIRS'):\n" % TRG)
                    + (" :del {f}{r} $_recipe.%sDIRS\n" % TRG))
            msg_depend(recdict, _('Adding default dependency for "%s"') % trg)
            rpstack = [RecPos("Default target")]
            dep = Depend([{"name" : trg}], {}, srclist,
                                         work, rpstack, cmd, recdict = recdict)
            work.add_dependency(rpstack, dep)

    # Add the generated recipes for automatic dependencies to $CLEANFILES.
    # Go through all the dependencies and handle the ones defined in this
    # recipe.
    # TODO: this doesn't find automatic dependencies from rules and assumes
    # dependencies are done recursively.
    for dep in work.dependencies:
        if (dep.buildrecdict
                        and dep.buildrecdict["_recipe"] is recdict["_recipe"]):
            for src in dep.sourcelist:
                node = work.find_node(src["name"])
                if node and not node.did_add_clean:
                    node.did_add_clean = 1
                    ftype = node.get_ftype(recdict)
                    if ftype and ftype != "ignore":
                        action, recipe = find_autodep_items(work, recdict,
                                                               ftype, node, {})
                        if action:
                            add_cleanfiles(recdict, recipe.get_name())

    # Remove duplicates from CLEANFILES.
    if recdict["_recipe"].get("CLEANFILES"):
        recdict["_recipe"]["CLEANFILES"] = rem_dup(
                                              recdict["_recipe"]["CLEANFILES"])


def add_install_target(work, recdict, targetname, sourcenames, cmd):
    """
    Call add_optional_target() twice, the second time with "install" changed to
    "uninstall".
    """
    add_optional_target(work, recdict, targetname, sourcenames, cmd)

    untargetname = re.sub("install", "uninstall", targetname)
    unsourcenames = map(lambda x: re.sub("install", "uninstall", x),
                                                                   sourcenames)
    # In the uninstall command change all "install" to "uninstall".
    # When using INSTALL.* remove the ":update" line and then double the
    # command to also use the UNINSTALL variable.
    uncmd = re.sub("install", "uninstall", cmd)
    if string.find(uncmd, "INSTALL") >= 0:
        uncmd = re.sub(":update.*\n", "", uncmd)
        uncmd = uncmd + re.sub("INSTALL", "UNINSTALL", uncmd)
    add_optional_target(work, recdict, untargetname, unsourcenames, uncmd)


def add_optional_target(work, recdict, targetname, sourcenames, cmd):
    """
    Add build dependency for "targetname" if there isn't one.
    To be used at the toplevel.
    """
    target = work.find_node(targetname)
    if target and target.get_dependencies():
        msg_depend(recdict, _('Not adding default dependency for "%s"')
                                                                  % targetname)
    else:
        rpstack = [RecPos("Default target")]
        if sourcenames:
            sourcelist = map(lambda x: {"name": x}, sourcenames)
        else:
            sourcelist = []
        dep = Depend([{"name" : targetname}], {}, sourcelist, work, rpstack,
                                                        cmd, recdict = recdict)
        work.add_dependency(rpstack, dep)


def add_buildrule(rpstack, work, recdict,
                           type, cmd_attr, targetlist, build_attr, sourcelist):
    """
    Add a buildrule.  Also used for ":totype".
    "type" is "program", "lib", "ltlib", "dll", "totype" or the first argument
    of ":produce".
    "cmd_attr" are extra attributes for the command itself.
    "targetlist" is a dictlist with the target(s).
    "build_attr" are extra attributes for the build commands.
    "sourcelist" is a dictlist with the sources.
    """
    # TODO: implement "cmd_attr".

    if type != "totype":
        target = work.find_node(targetlist[0]["name"])
        if target and target.get_first_build_dependency():
            msg_error(recdict, _("Both a build rule and a dependency with build commands defined for '%s'") % targetlist[0]["name"])
            return

    # Create a node for all items in sourcelist and targetlist, makes
    # sure the attributes are carried over.
    work.add_dictlist_nodes(sourcelist)
    if type != "totype":
        work.add_dictlist_nodes(targetlist)

    # When there is no direct build action for the source or there
    # are multiple sources, compile each source into an object and
    # build all the objects into the target.
    installvar = cmd_attr.get("installvar")
    onestep = cmd_attr.get("onestep")
    cleanfiles = []
    if type == "dll":
        if installvar is None:
            installvar = "INSTALL_DLL"
    elif type == "lib":
        if installvar is None:
            installvar = "INSTALL_LIB"
    elif type == "ltlib":
        if installvar is None:
            installvar = "INSTALL_LTLIB"
    elif type == "program":
        if installvar is None:
            installvar = "INSTALL_EXEC"

    if onestep and type == "ltlib":
        msg_warning(recdict, _("The 'onestep' attribute is not supported for the :ltlib target."), rpstack = rpstack)
        onestep = None

    if onestep:
        add_onestep_build(rpstack, work, recdict, type, cmd_attr, targetlist,
                            build_attr, sourcelist)
    else:
        a = cmd_attr.get("objecttype")
        if a:
            objtypes = string.split(a, ',')
        else:
            objtypes = None
        buildaction = cmd_attr.get("buildaction")
        if type == "dll":
            if not buildaction:
                buildaction = "builddll"
        elif type == "lib":
            if not buildaction:
                buildaction = "buildlib"
        elif type == "ltlib":
            if not buildaction:
                buildaction = "buildltlib"
        elif type == "program":
            if not buildaction:
                buildaction = "build"
        elif type == "totype":
            objtypes = [ targetlist[0]["name"] ]
        else:
            if not buildaction:
                recipe_error(rpstack, _("Missing buildaction attribute"))
            if installvar is None:
                installvar = "INSTALL_EXEC"

        if not objtypes:
            # Obtain the supported object types from the buildaction.
            act = find_primary_action(buildaction)
            if not act:
                if type not in ["dll", "lib", "ltlib", "program"]:
                    recipe_error(rpstack, _("Missing objecttype attribute"))
                else:
                    recipe_error(rpstack, _("No primary %s action defined")
                                                                 % buildaction)
            objtypes = act.get_in_types()

        objectsuffix = cmd_attr.get("objectsuffix")
        if type == "totype" and targetlist[0].get("suffix"):
            objectsuffix = targetlist[0].get("suffix")
        objectprefix = cmd_attr.get("objectprefix")
        if type == "totype" and targetlist[0].get("prefix"):
            objectprefix = targetlist[0].get("prefix")

        # Go over all source files and figure out a way to turn each one
        # into an object file.
        build_obj = []
        for si in sourcelist:
            node = work.get_node(si["name"], 1, si)
            in_ftype = node.get_ftype(recdict)

            if in_ftype in objtypes:
                # The source is supported by the build action: add it directly.
                build_obj.append(si)
            else:
                # Loop over the types that the build action supports, turn
                # the source in the first one that is possible.
                names = ''

                for objtype in objtypes:
                    if objtype == "default":
                        continue
                    objname = add_build_one(rpstack, work, recdict, node, si, in_ftype, objtype, objectprefix, objectsuffix, build_attr, cleanfiles)
                    if objname:
                        break
                    if names:
                        names = names + '/'
                    names = names + objtype

                if not objname:
                    recipe_error(rpstack, _('Do not know how to make an %s out of "%s"') % (names, si["name"]))

                build_obj.append({"name" : objname})


    if type != "totype":
        targets_str = dictlist2str(targetlist)
        if not onestep:
            # Add a dependency to build the program or library in the form:
            #   targetlist : {buildcheck = xxx} sourcelist
            #       do buildaction {target = $target} $source
            build_obj_str = dictlist2str(build_obj)
            cmd = ("  :do %s {target = $+target} $source" % buildaction)

            msg_depend(recdict, _('Adding dependency:\n\t%s : %s\n\t%s')
                                           % (targets_str, build_obj_str, cmd))
            work.add_dependency(rpstack,
                       Depend(targetlist, build_attr, build_obj, work,
                                       rpstack, cmd + '\n', recdict = recdict))

        cleanfiles.extend(targetlist)

        # Add target to INSTALL_EXEC, INSTALL_LIB or INSTALL_DLL.
        # do that relative to the top directory.
        if installvar:
            append2var(recdict, "_top", installvar, topdir(targets_str))

    # Add files to be cleaned to _recipe.CLEANFILES.
    add_cleanfiles(recdict, dictlist2str(cleanfiles, Expand(0)))

    # Add files to be distributed to _recipe.DISTFILES.  Skip the ones with a
    # {nodist} attribute.
    l = filter(lambda x: not x.get("nodist"), sourcelist)
    add_distfiles(recdict, dictlist2str(l, Expand(0)))


def add_build_one(rpstack, work, recdict, node, si, in_ftype,
                  objtype, objectprefix, objectsuffix, build_attr, cleanfiles):
    """
    Add build rule to turn one source node into a file of type "objtype".
    If successful return name of target file, None otherwise.
    """
    sufname = None
    if not objectsuffix:
        if objtype == "dllobject":
            sufname = "DLLOBJSUF"
        elif objtype == "libobject":
            sufname = "LIBOBJSUF"
        elif objtype == "ltobject":
            sufname = "LTOBJSUF"
        elif objtype == "object":
            sufname = "OBJSUF"

    # Make the object name by prepending $BDIR and changing the
    # extension to $OBJSUF/$LIBOBJSUF/$DLLOBJSUF/nothing.
    n = srcitem2obj(recdict, si["name"], attrdict = si, sufname = sufname)
    if objectprefix:
        n = os.path.join(os.path.dirname(n), objectprefix + os.path.basename(n))
    if objectsuffix:
        n = n + objectsuffix

    # If there is no build rule for the object file, add one.
    target = work.find_node(n)
    if target and target.get_first_build_dependency():
        # There already is a dependency for this target.
        if len(si) > 1:
            msg_warning(recdict, _('%s: Ignoring attributes for "%s", a build rule already exists') % (str(rpstack[-1]), si["name"]))
    else:

        # Find the route to the object file.
        route = work.find_route(in_ftype, objtype, use_actions = 1)
        if not route:
            return None

        # Add attributes from ":route" to the target node.
        work.get_node(n, add = 1, dict = route.targetattr)

        # Inits to avoid a warning from pychecker.
        trg = None
        out_ftype = None

        # Loop over all steps in the route.
        for i in range(len(route.steplist)):
            # Get the action and filename by processing the line.
            # TODO: catch errors
            route.rpstack[-1].line_nr = route.lnumlist[i] - 1
            fp = ParsePos(route.rpstack, string = "_x = "
                                                    + route.steplist[i] + '\n')
            rd = get_build_recdict(recdict, route.recdict,
                                         route.rpstack, keep_current_scope = 1,
                                              xscope = build_attr.get("scope"))
            rd["source"] = si["name"]
            Process(fp, rd, 0)
            l = string.split(rd["_x"], None, 1)
            action = l[0]

            if i == 0:
                src_dict = si.copy()
                src = si["name"]
                dnode = node
            else:
                src_dict = {"name" : trg}
                src = trg
                in_ftype = out_ftype
                dnode = work.find_node(src)

            # Set "depdir" for the auto-depend recipe.  Required if the source
            # file is built twice with different $BDIR.  Also add the recipe to
            # the files to be cleaned now, because $BDIR may change afterwards.
            if not src_dict.get("depdir"):
                src_dict["depdir"] = get_var_val_int(recdict, "BDIR")
            depaction, recipe = find_autodep_items(work, recdict,
                                                     in_ftype, dnode, src_dict)
            if depaction:
                add_cleanfiles(recdict, recipe.get_name())

            if i == len(route.steplist) - 1:
                trg = n
                out_ftype = objtype
            else:
                trg = l[1]
                out_ftype = route.typelist[i + 1][0]
                if (not os.path.isabs(trg) and string.find(trg, "build-") != 0):
                    trg = os.path.join(get_var_val_int(recdict, "BDIR"), trg)

            # Add a dependency to execute the action.
            cmd = "  :do %s {target = %s} %s" % (action, trg, src)
            msg_depend(recdict, _('Adding dependency:\n\t%s : %s\n\t%s')
                                        % (trg, dictlist2str([src_dict]), cmd))
            src_dict["filetype"] = in_ftype
            trg_dict = {"name": trg, "filetype" : out_ftype}
            work.add_dependency(rpstack,
                   Depend([ trg_dict ], build_attr, [ src_dict ], work,
                                      rpcopy(route.rpstack, route.lnumlist[i]),
                                                cmd + '\n', recdict = recdict))
            cleanfiles.append({"name": trg})

    return n


def add_onestep_build(rpstack, work, recdict,
                           type, cmd_attr, targetlist, build_attr, sourcelist):
    """Adds an onestep build"""

    buildaction = cmd_attr.get("buildaction")
    if type == "dll":
        if not buildaction:
            buildaction = "builddllonestep"
    elif type == "lib":
        if not buildaction:
            buildaction = "buildlibonestep"
    elif type == "program":
        if not buildaction:
            buildaction = "buildonestep"
    cmd = ("   :do %s {target =$+target} $source" % buildaction)
    work.add_dependency(rpstack,
            Depend(targetlist, build_attr, sourcelist, work,
                rpstack, cmd + '\n', recdict = recdict))

# vim: set sw=4 et sts=4 tw=79 fo+=l: