# Part of the A-A-P recipe executive: Add default rules and dependencies

# Copyright (C) 2002 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 Dictlist import str2dictlist, varname2dictlist, dictlist2str, dictlistattr2str
from Rule import Rule, find_rule
from RecPos import RecPos
from Util import *
from Depend import Depend
from Dictlist import get_attrdict
from Message import *


def add_def_rule(work, targetcheck, target, sourcecheck, source,
			    build_attr, commands):
    if find_rule(work, targetcheck, sourcecheck):
        return	# rule for this target-source already exists

    # Add a default rule; Expand the source and target into dictlists.
    rpstack = [RecPos("Default rule")]
    targetlist = str2dictlist(rpstack, target)
    buildcheck, i = get_attrdict(rpstack, None, build_attr, 0, 0)
    sourcelist = str2dictlist(rpstack, source)
    work.add_rule(Rule(targetlist, buildcheck, sourcelist,
					      rpstack, "  " + commands + "\n"))


def doadddef(work):
    """
    Add default rules and dependencies, depending on what was defined in the
    recipe(s) read.
    """

    #
    # Add rules that are not covered by recipes.
    # TODO: put this separately somehow
    #
    add_def_rule(work, "%.o", "%.o",
		    "%.c", "%.c",
		    "{buildcheck = $CC $CFLAGS $CPPFLAGS}",
		    ":do compile {target = $target} $source")
    add_def_rule(work, "%.obj", "%.obj",
		    "%.c", "%.c",
		    "{buildcheck = $CC $CFLAGS $CPPFLAGS}",
		    ":do compile {target = $target} $source")
    add_def_rule(work, "%.o", "%.o",
		    "%.cpp", "%.cpp",
		    "{buildcheck = $CXX $CXXFLAGS $CPPFLAGS}",
		    ":do compile {target = $target} $source")
    add_def_rule(work, "%.obj", "%.obj",
		    "%.cpp", "%.cpp",
		    "{buildcheck = $CXX $CXXFLAGS $CPPFLAGS}",
		    ":do compile {target = $target} $source")


    # Add a dependency from $SOURCE and $TARGET if appropriate.
    add_source_target(work, work.recdict)

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


def add_source_target(work, recdict):
    """If $SOURCE and $TARGET are defined, $TARGET is one item and there is no
       dependency with $TARGET as target, 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, "TARGET")
	if len(targets) == 1:
	    target = work.find_node(targets[0]["name"])
	    if not target or not target.get_first_build_dependency():
		# Add a dependency with a link command in # the form:
		#   $TARGET : {buildcheck = xxx} $SOURCE
		#	do compile {target = $object[i]} $source[i]
		#       do build {target = $target} $objects
		sources = varname2dictlist(recdict, "SOURCE")
		sources_len = len(sources)

		# Create a node for all items in $SOURCE and $TARGET, makes
		# sure the attributes are carried over.
		work.add_dictlist_nodes(sources)
		work.add_dictlist_nodes(targets)

		# 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.
		from Action import has_action

		rpstack = [RecPos("Default target")]
		if sources_len == 1 and has_action(recdict, "build",
								   sources[0]):
		    # Can build directly from source.
		    build_sources = sources
		else:
		    # For each source item make the object name by prepending
		    # $BDIR and changing the extension to $OBJSUF.  Add a
		    # dependency between the object and the source.
		    build_sources = []
		    for si in sources:
			n = srcitem2obj(recdict, si["name"], attrdict = si)
			bsi = {"name" : n}
			work.add_dependency(rpstack,
				Depend([ bsi ], {}, [ si ], work, rpstack,
				    "  :do compile {target = %s} %s\n"
							% (n, si["name"]),
							recdict = recdict))
			build_sources.append(bsi)

		build_sources_str = dictlist2str(build_sources)
		targets_str = dictlist2str(targets) 
		cmd = ("  :do build {target = $+target} %s"
							   % build_sources_str)
		msg_depend(recdict, _('Adding dependency from $TARGET and $SOURCE:\n\t%s : %s\n\t%s')
			 % (targets_str, build_sources_str, cmd))
		work.add_dependency(rpstack,
			   Depend(targets, {}, build_sources, work,
				       rpstack, cmd + '\n', recdict = recdict))

		# May also add a "clean" target.
		target = work.find_node("clean")
		if not target or not target.get_first_build_dependency():
		    cmd = ("  :del {force} %s %s"
					    % (build_sources_str, targets_str))
		    msg_depend(recdict,
			       _('Adding dependency for "clean":\n\t%s') % cmd)
		    work.add_dependency(rpstack,
			    Depend([{"name" : "clean"}], {}, [], work, rpstack,
						cmd + '\n', recdict = recdict))


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