Beispiel #1
0
def handleOption(e):
    errors.pushCtx("when processing option '%s' at %s" %
                   (e.name, e.location()))

    name = evalConstExpr(e, e.props['name'])
    if name in mk.options:
        raise ReaderError(e, "option '%s' already defined" % name)

    if name in mk.override_vars:
        return  # user hardcoded the value with -D=xxx

    default = None
    force_default = False
    desc = None
    values = None
    values_desc = None
    category = mk.Option.CATEGORY_UNSPECIFICED
    for c in e.children:
        if c.name == 'default-value':
            default = c.value
            force_default = 'force' in c.props and c.props['force'] == '1'
        elif c.name == 'description':
            desc = c.value
        elif c.name == 'values':
            values = evalConstExpr(e, c.value.replace('\n', '')).split(',')
            for i in range(len(values)):
                values[i] = values[i].strip()
        elif c.name == 'values-description':
            values_desc = evalConstExpr(e, c.value).split(',')

    o = mk.Option(name, default, force_default, desc, values, values_desc,
                  errors.getCtx())
    mk.addOption(o)

    if 'never_empty' in e.props and e.props['never_empty'] == '1':
        o.neverEmpty = 1

    if 'category' in e.props:
        category = evalConstExpr(e, e.props['category'])
        if category == mk.Option.CATEGORY_PATH:
            o.category = category
            o.neverEmpty = 1

            def __pathOptionCallb(var, func, caller):
                if caller == 'nativePaths':
                    return '$(%s)' % var
                else:
                    return None

            utils.addSubstituteCallback(o.name, __pathOptionCallb)
        else:
            raise ReaderError(e, "unknown category '%s'" % category)

    errors.popCtx()
Beispiel #2
0
def handleModifyTarget(e, dict=None):
    tg = mk.evalExpr(e.props['target'], use_options=0, add_dict=dict)
    if tg not in mk.targets:
        raise ReaderError(e, "unknown target '%s'" % tg)
    target = mk.targets[tg]
    tags = rules[target.type].getTagsDict()
    _processTargetNodes(e, target, tags, dict)
Beispiel #3
0
def handleTagInfo(e):
    name = e.props['name']
    if name in tagInfos:
        info = tagInfos[name]
    else:
        info = TagInfo()

    if 'exclusive' in e.props:
        info.exclusive = e.props['exclusive'] == '1'
    if 'position' in e.props:
        tokens = e.props['position'].split(',')
        for token in tokens:
            pos = token.find(':')
            if pos == -1:
                keyword = token
            else:
                keyword = token[:pos]
                param = token[pos + 1:]

            if keyword == 'before':
                if param not in info.before:
                    info.before.append(param)
            elif keyword == 'after':
                if param not in tagInfos:
                    tagInfos[param] = TagInfo()
                if name not in tagInfos[param].before:
                    tagInfos[param].before.append(name)
            else:
                raise ReaderError(e,
                                  "unrecognized position token '%s'" % token)

    tagInfos[name] = info
Beispiel #4
0
def checkConditionsSupport(e):
    """Raises exception of the output format does not support some form
       of conditions (e.g. DigitalMars)."""
    if mk.vars['FORMAT_SUPPORTS_CONDITIONS'] != '1' and \
       mk.vars['FORMAT_SUPPORTS_CONFIGURATIONS'] != '1':
        raise ReaderError(
            e, 'output format does not support conditional processing')
Beispiel #5
0
def __doProcess(file=None, strdata=None, xmldata=None):
    if xmldata != None:
        m = xmldata
    else:
        # FIXME: validity checking
        try:
            if file != None:
                m = xmlparser.parseFile(file)
            else:
                m = xmlparser.parseString(strdata)
        except xmlparser.ParsingError:
            raise ReaderError(None, "file '%s' is invalid" % file)

    def processNodes(list):
        for e in list:
            if e.name == 'if':
                if evalWeakCondition(e):
                    processNodes(e.children)
            else:
                try:
                    h = HANDLERS[e.name]
                except (KeyError):
                    raise ReaderError(e, "unknown tag '%s'" % e.name)
                h(e)

    try:
        processNodes(m.children)
    except ReaderError:
        reraise()
Beispiel #6
0
def handleDefineGlobalTag(e):
    name = e.props['name']

    if name in HANDLERS:
        raise ReaderError(e, "global tag '%s' is already defined" % name)

    globalTags[name] = e
    HANDLERS[name] = handleGlobalTag
Beispiel #7
0
def checkTagDefinitions():
    if len(__tagsWaitingForRules) > 0:
        errors = []
        for r in __tagsWaitingForRules:
            errors.append("  target '%s':" % r)
            for t in __tagsWaitingForRules[r]:
                errors.append('    at %s' % t.location())
        errors = '\n'.join(errors)
        raise ReaderError(
            None, "tag definitions for nonexistent rules:\n%s" % errors)
Beispiel #8
0
def evalConstExpr(e, str, target=None, add_dict=None):
    try:
        return mk.evalExpr(str,
                           use_options=0,
                           target=target,
                           add_dict=add_dict)
    except NameError, err:
        raise ReaderError(
            e,
            "can't use options or conditional variables in this context (%s)" %
            err)
Beispiel #9
0
 def processNodes(list):
     for e in list:
         if e.name == 'if':
             if evalWeakCondition(e):
                 processNodes(e.children)
         else:
             try:
                 h = HANDLERS[e.name]
             except (KeyError):
                 raise ReaderError(e, "unknown tag '%s'" % e.name)
             h(e)
Beispiel #10
0
def evalWeakCondition(e, target=None, add_dict=None):
    """Evaluates e's 'cond' property, if present, and returns 0 or 1 if it
       can be evaluated to a constant. If it can't (i.e. it is a strong
       condition) do it, raises exception."""
    x = evalWeakConditionDontRaise(e, target=target, add_dict=add_dict)
    if x == None:
        raise ReaderError(e,
                "'%s': only weak condition allowed in this context" % \
                        e.props['cond'])
    else:
        return x
Beispiel #11
0
def handleDefineRule(e):
    rule = Rule(evalConstExpr(e, e.props['name']))

    # check that the rule name is valid
    if rule.name in HANDLERS:
        raise ReaderError(
            e, "global tag or rule '%s' already defined" % rule.name)

    rules[rule.name] = rule
    HANDLERS[rule.name] = handleTarget

    if 'pseudo' in e.props and e.props['pseudo'] == '1':
        rule.pseudo = 1

    if 'extends' in e.props:
        baserules = [
            evalConstExpr(e, x) for x in e.props['extends'].split(',')
        ]
        rule.baserules = []
        for baserule in baserules:
            if baserule == '': continue
            if baserule not in rules:
                raise ReaderError(e, "unknown rule '%s'" % baserule)
            rule.baserules.append(rules[baserule])

    if rule.name in __tagsWaitingForRules:
        for t in __tagsWaitingForRules[rule.name]:
            __addTagToRule(rule, t)
        del __tagsWaitingForRules[rule.name]

    for node in e.children:
        if node.name == 'define-tag':
            handleDefineTag(node, rule=rule)
        elif node.name == 'template':
            rule.template += applyTemplates(node, extractTemplates(node,
                                                                   post=0),
                                            extractTemplates(node,
                                                             post=1)).children
        else:
            raise ReaderError(
                node, "unknown element '%s' in <define-rule>" % node.name)
Beispiel #12
0
def handleRequires(e):
    if 'version' in e.props:
        if not utils.checkBakefileVersion(e.props['version']):
            sys.stderr.write("""
-----------------------------------------------------------------------
This file cannot be processed with Bakefile version older than %s.
You are using Bakefile version %s. Please install the newest version
from http://www.bakefile.org.
-----------------------------------------------------------------------

""" % (e.props['version'], mk.vars['BAKEFILE_VERSION']))
            raise ReaderError(e, "Bakefile not new enough")
Beispiel #13
0
def _extractTargetNodes(parent, list, target, tags, index):
    def _removeNode(n):
        for c in n.children:
            _removeNode(c)
        index[n.node.name].remove(n)
        n.parent.children.remove(n)
        for c in n.parent.children:
            c.updatePosition()

    def _removeDuplicates(n):
        # Eliminate duplicates of exclusive tags:
        name = n.node.name
        if name not in index:
            index[name] = [n]
        else:
            if n.exclusive:
                if len(index[name]) > 0:
                    if config.debug:
                        n2 = index[name][0]
                        print '[dbg] (thrown away <%s> @%s in favor of @%s)' % \
                              (name, n2.node.location(), n.node.location())
                    _removeNode(index[name][0])
                # else: this can happen if _removeNode was called recursively
                index[name] = [n]
            else:
                index[name].append(n)

    for node in list:
        if node.name == 'if':
            condType = evalWeakConditionDontRaise(node, target=target)
            if condType == 1:
                _extractTargetNodes(parent, node.children, target, tags, index)
            elif condType == None:
                n = TgtCmdNode(target, parent, TgtCmdNode.IF, node)
                _removeDuplicates(n)
                _extractTargetNodes(n, node.children, target, tags, index)
            # else: condition evaluated to False, ignore this part
        elif node.name in COMMANDS:
            n = TgtCmdNode(target, parent, TgtCmdNode.COMMAND, node)
            _removeDuplicates(n)
        elif node.name in tags:
            if evalWeakCondition(node) == 0:
                continue
            n = TgtCmdNode(target, parent, TgtCmdNode.TAG, node)
            _removeDuplicates(n)
            _extractTargetNodes(n, tags[node.name], target, tags, index)
        elif node.name in globalTags:
            n = TgtCmdNode(target, parent, TgtCmdNode.COMMAND, node)
            _removeDuplicates(n)
        else:
            raise ReaderError(node, "unknown target tag '%s'" % node.name)
Beispiel #14
0
def handleInclude(e):
    file = evalConstExpr(e, e.props['file'])
    canIgnore = 'ignore_missing' in e.props and e.props['ignore_missing'] == '1'
    justOnce = 'once' in e.props and e.props['once'] == '1'
    lookup = [os.path.dirname(e.filename)] + config.searchPath
    errors.pushCtx("included from %s" % e.location())
    for dir in lookup:
        if processFileIfExists(os.path.join(dir, file), justOnce):
            errors.popCtx()
            return
    if not canIgnore:
        raise ReaderError(
            e, "can't find file '%s' in %s" % (file, string.join(lookup, ':')))
    errors.popCtx()
Beispiel #15
0
def translateSpecialCondition(e, condstr, target=None):
    """If the condition is of form 'target' or 'target and something',
       make it a normal condition by extracting condition from
       target's description."""
    if condstr.startswith('target and '):
        if target == None:
            raise ReaderError(
                e, "'target' condition can't be used at global scope")
        if target.cond != None:
            condstr = '%s and %s' % (target.cond.tostr(),
                                     condstr[len('target and '):])
        else:
            condstr = condstr[len('target and '):]
        return condstr
    elif condstr == 'target':
        if target == None:
            raise ReaderError(
                e, "'target' condition can't be used at global scope")
        if target.cond == None:
            return '1'
        else:
            return target.cond.tostr()
    else:
        return condstr
Beispiel #16
0
def extractTemplates(e, post):
    ch = []
    if post: propname = 'template_append'
    else: propname = 'template'

    if propname in e.props:
        derives = e.props[propname].split(',')
        for d2 in derives:
            d = evalConstExpr(e, d2)
            if d == '': continue
            try:
                ch2 = mk.templates[d]
                ch = ch + ch2
            except KeyError:
                raise ReaderError(e, "unknown template '%s'" % d)
    return ch
Beispiel #17
0
def processFile(filename, onlyOnce=False):
    if not os.path.isfile(filename):
        raise ReaderError(None, "file '%s' doesn't exist" % filename)
    filename = os.path.abspath(filename)
    if onlyOnce and filename in includedFiles:
        if config.verbose:
            print "file %s already included, skipping..." % filename
        return
    includedFiles.append(filename)
    if config.verbose:
        print 'loading %s...' % filename
    if config.track_deps:
        dependencies.addDependency(mk.vars['INPUT_FILE'], config.format,
                                   filename)
    newdir = os.path.dirname(filename)
    if newdir not in sys.path:
        sys.path.append(newdir)
    __doProcess(file=filename)
Beispiel #18
0
def handleDefineTag(e, rule=None):
    name = e.props['name']
    if rule == None:
        if 'rules' in e.props:
            rs = e.props['rules'].split(',')
        else:
            raise ReaderError(e, "external <define-tag> must list rules")
    else:
        rs = [rule.name]

    for rn in rs:
        if not rn in rules:
            # delayed tags addition, rule not defined yet
            if rn in __tagsWaitingForRules:
                __tagsWaitingForRules[rn].append(e)
            else:
                __tagsWaitingForRules[rn] = [e]
        else:
            __addTagToRule(rules[rn], e)
Beispiel #19
0
 def _loadFile(filename):
     if verbose:
         print 'loading task description from %s...' % filename
     try:
         root = xmlparser.parseFile(filename, xmlparser.NS_BAKEFILE_GEN)
     except xmlparser.ParsingError:
         raise errors.Error("can't load file '%s'" % filename)
     ret = []
     for cmd in root.children:
         if cmd.name == 'include':
             inc = os.path.join(os.path.dirname(filename),
                                cmd.props['file'])
             if os.path.isfile(inc):
                 r2 = _loadFile(inc)
                 ret += r2.children
             else:
                 if ('ignore_missing' not in cmd.props) or \
                    (cmd.props['ignore_missing'] == '0'):
                     raise ReaderError(cmd, "file '%s' doesn't exist" % inc)
         else:
             ret.append(cmd)
     root.children = ret
     return root
Beispiel #20
0
def handleEcho(e, target=None, add_dict=None):
    text = evalConstExpr(e, e.value, target=target, add_dict=add_dict)

    # extract echo level
    if 'level' in e.props:
        level = e.props['level']
        if level not in ['verbose', 'warning', 'normal', 'debug']:
            raise ReaderError(e, "unknown echo level '%s'" % level)
    else:
        level = 'normal'

    if level == 'normal':
        print text
    elif level == 'verbose' and config.verbose:
        print text
    elif level == 'debug' and config.debug:
        print text
    elif level == 'warning':
        # FIXME: DEPRECATED (since 0.2.3)
        _printWarning(None, text)
        _printWarning(
            e,
            '<echo level="warning"> syntax is deprecated, use <warning> instead'
        )
Beispiel #21
0
def loadModule(m):
    if m in loadedModules:
        return
    if config.verbose: print "loading module '%s'..." % m
    loadedModules.append(m)

    # set USING_<MODULENAME> variable:
    mk.setVar('USING_%s' % m.upper(), '1')

    # import module's py utilities:
    imported = mk.importPyModule(m)

    # include module-specific makefiles:
    global availableFiles
    for f in availableFiles:
        if m in f.modules:
            f.modules.remove(m)
            if len(f.modules) == 0:
                processFile(f.file)
                imported = True
    availableFiles = [f for f in availableFiles if len(f.modules) > 0]

    if not imported:
        raise ReaderError(None, "unknown module '%s'" % m)
Beispiel #22
0
def loadTargets(filename, defaultFlags=[]):
    def _loadFile(filename):
        if verbose:
            print 'loading task description from %s...' % filename
        try:
            root = xmlparser.parseFile(filename, xmlparser.NS_BAKEFILE_GEN)
        except xmlparser.ParsingError:
            raise errors.Error("can't load file '%s'" % filename)
        ret = []
        for cmd in root.children:
            if cmd.name == 'include':
                inc = os.path.join(os.path.dirname(filename),
                                   cmd.props['file'])
                if os.path.isfile(inc):
                    r2 = _loadFile(inc)
                    ret += r2.children
                else:
                    if ('ignore_missing' not in cmd.props) or \
                       (cmd.props['ignore_missing'] == '0'):
                        raise ReaderError(cmd, "file '%s' doesn't exist" % inc)
            else:
                ret.append(cmd)
        root.children = ret
        return root

    def _findMatchingFiles(node):
        """Returns list of FileInfo objects from 'files' variable that match
           node's file matching properties ("files"=comma-sep list of wildcards,
           "formats"=comma-separated list of formats)."""
        global files
        # match filenames:
        if 'files' in node.props:
            matches1 = []
            globs = node.props['files'].replace('/', os.sep).split(',')
            for g in globs:
                for f in [x for x in files if _matchesWildcard(x, g)]:
                    matches1.append(files[f])
        else:
            matches1 = files.values()
        # match formats:
        if 'formats' in node.props:
            formats = node.props['formats'].split(',')
            matches2 = []
            for f in matches1:
                formats2 = [x for x in formats if x in f.formats]
                matches2.append((f, formats2))
        else:
            matches2 = []
            for f in matches1:
                matches2.append((f, f.formats))
        return matches2

    def _parseFlags(cmdline):
        """Splits command line into individual flag arguments. Handles quoting
           with " properly."""
        # findall returns list of tuples, 1st or 2nd item is empty, depending
        # on which subexpression was matched:
        return [a or b for a, b in re.findall(r'"(.*?)"|(\S+)', cmdline)]

    root = _loadFile(filename)

    if root.name != 'bakefile-gen':
        raise ReaderError(root,
                          'incorrect root node (not a bakefile_gen file?)')

    if verbose:
        print 'scanning directories for bakefiles...'

    for cmd in [x for x in root.children if x.name == 'input']:
        globs = cmd.value.replace('/', os.sep).split()
        for g in globs:
            for f in glob.glob(g):
                files[f] = FileInfo(f)

    if verbose:
        print 'building rules...'

    for cmd in root.children:
        if cmd.name == 'disable-formats':
            formats = cmd.value.split(',')
            for f in formats:
                if f not in disabled_formats:
                    disabled_formats.append(f)
        elif cmd.name == 'enable-formats':
            formats = cmd.value.split(',')
            for f in formats:
                if f in disabled_formats:
                    disabled_formats.remove(f)

    for cmd in root.children:
        if cmd.name == 'add-formats':
            formats = [
                x for x in cmd.value.split(',') if x not in disabled_formats
            ]
            for file, fl in _findMatchingFiles(cmd):
                for f in formats:
                    if f not in file.formats:
                        file.formats.append(f)
                        file.flags[f] = [x for x in defaultFlags]  # make copy
        elif cmd.name == 'del-formats':
            formats = [
                x for x in cmd.value.split(',') if x not in disabled_formats
            ]
            for file, fl in _findMatchingFiles(cmd):
                for f in formats:
                    if f in file.formats:
                        file.formats.remove(f)
                        del file.flags[f]

    for cmd in root.children:
        if cmd.name == 'add-flags':
            flagsList = _parseFlags(cmd.value)
            for file, formats in _findMatchingFiles(cmd):
                for f in flagsList:
                    flags = f
                    flags = flags.replace('$(INPUT_FILE)', file.filename)
                    flags = flags.replace('$(INPUT_FILE_BASENAME)',
                                          os.path.basename(file.filename))
                    flags = flags.replace(
                        '$(INPUT_FILE_BASENAME_NOEXT)',
                        os.path.splitext(os.path.basename(file.filename))[0])
                    inputdir = os.path.dirname(file.filename)
                    if inputdir == '': inputdir = '.'
                    flags = flags.replace('$(INPUT_FILE_DIR)', inputdir)

                    for fmt in formats:
                        file.flags[fmt].append(flags)

        elif cmd.name == 'del-flags':
            flagsList = _parseFlags(cmd.value)
            for file, formats in _findMatchingFiles(cmd):
                for fmt in formats:
                    for f in flagsList:
                        try:
                            file.flags[fmt].remove(f)
                        except ValueError:
                            sys.stderr.write(
                                "Warning: trying to remove flags '%s' that weren't added at %s (current flags on file %s, format %s: '%s')\n"
                                % (f, cmd.location(), file.filename, fmt,
                                   ' '.join(file.flags[fmt])))
Beispiel #23
0
def handleError(e, target=None, add_dict=None):
    text = evalConstExpr(e, e.value, target=target, add_dict=add_dict)
    raise ReaderError(e, text)
Beispiel #24
0
def handleSet(e, target=None, add_dict=None):
    try:
        errors.pushCtx("in <set> at %s" % e.location())

        name = basename = evalConstExpr(e, e.props['var'], target)
        if (name in mk.override_vars) and target == None:
            return  # can't change value of variable overriden with -D=xxx

        doEval = not ('eval' in e.props and e.props['eval'] == '0')
        overwrite = not ('overwrite' in e.props
                         and e.props['overwrite'] == '0')
        isCond = (len(e.children) > 0)
        isMakeVar = 'make_var' in e.props and e.props['make_var'] == '1'
        value = e.value
        if 'hints' in e.props:
            hints = e.props['hints']
        else:
            hints = ''

        # Handle conditions:
        if isCond:

            if e.value:
                raise ReaderError(
                    e, "cannot set unconditional value when <if> is used")

            noValueSet = 1
            for e_if in e.children:
                try:
                    errors.pushCtx(e_if)

                    if e_if.name != 'if':
                        raise ReaderError(e_if, "malformed <set> command")

                    # Preprocess always true or always false conditions:

                    condstr = evalConstExpr(e_if,
                                            e_if.props['cond'],
                                            target=target,
                                            add_dict=add_dict)
                    condstr = translateSpecialCondition(e_if, condstr, target)

                    typ = mk.evalCondition(condstr)
                    # Condition never met when generating this target:
                    if typ == '0':
                        if config.debug:
                            print "[dbg] removing never-met condition '%s' for variable '%s'" % (
                                condstr, name)
                        continue
                    # Condition always met:
                    elif typ == '1':
                        if config.debug:
                            print "[dbg] condition '%s' for variable '%s' is always met" % (
                                condstr, name)
                        noValueSet = 0
                        isCond = 0
                        value = e_if.value
                        break
                    elif typ != None:
                        raise ReaderError(
                            e,
                            "malformed condition '%s': doesn't evaluate to boolean value"
                            % condstr)
                    cond = mk.makeCondition(condstr)

                    noValueSet = 0

                    # Real conditions:

                    checkConditionsSupport(e)

                    if 'scope' in e.props:
                        raise ReaderError(
                            e,
                            "conditional variable can't have nondefault scope ('%s')"
                            % e.props['scope'])

                    if target != None:
                        if (not overwrite) and (name in target.vars):
                            return
                        name = '__%s_%s' % (target.id.replace(
                            '-', '_').replace('.', '_').replace('/',
                                                                '_'), basename)
                        mk.setVar(e.props['var'],
                                  '$(%s)' % name,
                                  eval=0,
                                  target=target,
                                  add_dict=add_dict,
                                  hints=hints)
                    if cond == None:
                        raise ReaderError(
                            e,
                            "malformed condition: '%s': must be constant expression, equality test or conjunction of them"
                            % condstr)
                    if name in mk.cond_vars:
                        if not overwrite:
                            return
                        var = mk.cond_vars[name]
                    else:
                        var = mk.CondVar(name, target)
                        mk.addCondVar(var, hints)
                    if doEval:
                        value = mk.evalExpr(e_if.value,
                                            target=target,
                                            add_dict=add_dict)
                    else:
                        value = e_if.value
                    var.add(cond, value)
                finally:
                    errors.popCtx()

            if noValueSet:
                isCond = 0
                value = ''

            if isCond:
                return

        # Non-conditional variables:
        if value == None: value = ''
        if 'append' in e.props and e.props['append'] == '1':
            doAppend = 1
        else:
            doAppend = 0
        if 'prepend' in e.props and e.props['prepend'] == '1':
            doPrepend = 1
        else:
            doPrepend = 0
        store_in = None
        if 'scope' in e.props:
            sc = evalConstExpr(e, e.props['scope'], target=target)
            if sc == 'local':
                pass
            elif sc == 'global':
                store_in = mk.vars
            else:
                if sc in mk.targets:
                    store_in = mk.targets[sc].vars
                else:
                    raise ReaderError(
                        e,
                        "invalid scope '%s': must be 'global', 'local' or target name"
                        % sc)

        if isMakeVar:
            if doAppend or store_in != None or not doEval:
                raise ReaderError(
                    e,
                    "make variable (%s) can't be appended or stored in nondefault scope or not evaluated"
                    % name)

        mk.setVar(name,
                  value,
                  eval=doEval,
                  target=target,
                  add_dict=add_dict,
                  store_in=store_in,
                  append=doAppend,
                  prepend=doPrepend,
                  overwrite=overwrite,
                  makevar=isMakeVar,
                  hints=hints)
    finally:
        errors.popCtx()
Beispiel #25
0
def handleUnset(e):
    name = e.props['var']
    if not mk.unsetVar(name):
        raise ReaderError(e, "'%s' is not a variable" % name)
Beispiel #26
0
def handleTemplate(e):
    id = e.props['id']
    if id in mk.templates:
        raise ReaderError(e, "template ID '%s' already used" % id)
    mk.templates[id] = applyTemplates(e, extractTemplates(e, post=0),
                                      extractTemplates(e, post=1)).children
Beispiel #27
0
def handleTarget(e):
    if e.name not in rules:
        raise ReaderError(e, "unknown target type")

    rule = rules[e.name]
    if rule.pseudo and 'id' not in e.props:
        global _pseudoTargetLastID
        id = 'pseudotgt%i' % _pseudoTargetLastID
        _pseudoTargetLastID += 1
    else:
        if 'id' not in e.props:
            raise ReaderError(e, "target doesn't have id")
        id = e.props['id']

    cond = None
    if 'cond' in e.props:
        isCond = 1
        # Handle conditional targets:
        condstr = evalConstExpr(e, e.props['cond'])
        typ = mk.evalCondition(condstr)
        # Condition never met, ignore the target:
        if typ == '0':
            utils.deadTargets.append(id)
            return
        # Condition always met:
        elif typ == '1':
            isCond = 0
        elif typ != None:
            raise ReaderError(e, "malformed condition: '%s'" % condstr)

        if isCond:
            checkConditionsSupport(e)
            cond = mk.makeCondition(condstr)
            if cond == None:
                raise ReaderError(e, "malformed condition: '%s'" % condstr)

    tags = rule.getTagsDict()
    e = applyTemplates(e,
                       rule.getTemplates() + extractTemplates(e, post=0),
                       extractTemplates(e, post=1))

    if id in mk.targets:
        raise ReaderError(e, "duplicate target name '%s'" % id)

    if 'category' in e.props:
        try:
            cats = {
                'all': mk.Target.CATEG_ALL,
                'normal': mk.Target.CATEG_NORMAL,
                'automatic': mk.Target.CATEG_AUTOMATIC
            }
            category = cats[e.props['category']]
        except KeyError:
            raise ReaderError(e, "unknown category '%s'" % e.props['category'])
    else:
        category = mk.Target.CATEG_NORMAL

    target = mk.Target(e.name, id, cond, rule.pseudo, category)
    mk.addTarget(target)

    errors.pushCtx("when processing target '%s' at %s" %
                   (target.id, e.location()))
    _processTargetNodes(e, target, tags, None)
    errors.popCtx()