DoAddDef.py :  » Build » A-A-P » aap-1.091 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Build » A A P 
A A P » aap 1.091 » DoAddDef.py
# 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 = ''

                objname = None
                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 objname is None:
                    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:
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.