def get_compilation_subgraph(toolset, target, ft_to, outfile): """ Given list of source files (as :class:`bkl.expr.ListExpr`), produces build subgraph (:class:`bkl.api.BuildSubgraph`) with appropriate :class:`bkl.api.BuildNode` nodes. :param toolset: The toolset used (as :class:`bkl.api.Toolset`). :param target: The target object for which the invocation is done. :param ft_to: Type of the output file to compile to. :param outfile: Name of the output file (as :class:`bkl.expr.PathExpr`). """ # FIXME: support direct many-files-into-one (e.g. java->jar, .cs->exe) # compilation too objects = [] allnodes = [] files_map = disambiguate_intermediate_file_names(target.sources) for srcfile in target.sources: with error_context(srcfile): if not srcfile.should_build(): # TODO: allow runtime decision continue if srcfile["compile-commands"]: allnodes += _make_build_nodes_for_generated_file(srcfile) else: # FIXME: toolset.object_type shouldn't be needed obj, all = _make_build_nodes_for_file(toolset, target, srcfile, toolset.object_type, files_map) objects += obj allnodes += all for srcfile in target.headers: with error_context(srcfile): if not srcfile.should_build(): # TODO: allow runtime decision continue if srcfile["compile-commands"]: allnodes += _make_build_nodes_for_generated_file(srcfile) linker = get_compiler(toolset, toolset.object_type, ft_to) assert linker object_files = [o.outputs[0] for o in objects] link_commands = linker.commands(toolset, target, expr.ListExpr(object_files), outfile) link_node = BuildNode(commands=link_commands, inputs=object_files, outputs=[outfile], source_pos=target.source_pos) return BuildSubgraph(link_node, allnodes)
def validate(self, e): """ Validates if the expression *e* is of this type. If it isn't, throws :exc:`bkl.error.TypeError` with description of the error. Note that this method transparently handles references and conditional expressions. """ with error_context(e): if isinstance(e, expr.NullExpr): # Null expression is rarely a valid value, but it can happen all # over the place due to conditional processing pass elif isinstance(e, expr.ReferenceExpr): try: # FIXME: Compare referenced var's type with self, do this only if # it is AnyType. Need to handle type promotion then as well. self.validate(e.get_value()) except TypeError as err: # If the error happened in a referenced variable, then # it's location is not interesting -- we want to report # the error at the place where validation was requested. # FIXME: push the old location on a stack instead? err.pos = None raise elif isinstance(e, expr.IfExpr): self.validate(e.value_yes) self.validate(e.value_no) elif isinstance(e, expr.PlaceholderExpr): # FIXME: once settings are implemented, check their types pass # raise TypeError(self, e, "value not determinable") else: # finally, perform actual type-specific validation: self._validate_impl(e)
def get_value(self): """ Returns value of the referenced variable. Throws an exception if the reference couldn't be resolved. """ with error_context(self): return self.context.get_variable_value(self.var)
def get_model_name_from_path(e): """ Give an expression representing filename, return name suitable for model.SourceFile.name. """ with error_context(e): return _ModelNameFromPathVisitor().visit(e)
def get_value(self): """ Returns value of the conditional expression, i.e. either :attr:`value_yes` or :attr:`value_no`, depending on what the condition evaluates to. Throws if the condition cannot be evaluated. """ with error_context(self): return self.value_yes if self.cond.as_py() else self.value_no
def split(e, sep): """ Splits expression *e* into a list of expressions, using *sep* as the delimiter character. Works with conditional expressions and variable references too. """ assert len(sep) == 1 with error_context(e): return _SplitVisitor(sep).visit(e)
def get_variable(self): """ Return the variable object this reference points to. Use this method only if necessary; whenever possible, :meth:`get_value()` should be used instead. Note that the returned value may be None, either if the referenced variable doesn't exist or when the reference is to a property that wasn't explicitly set and uses the default value. """ with error_context(self): return self.context.resolve_variable(self.var)
def split_into_path(e): """ Splits expression *e* into a list of expressions, using '/' as the delimiter character. Returns a PathExpr. Works with conditional expressions and variable references too. """ with error_context(e): visitor = _SplitIntoPathVisitor() components = visitor.visit(e) # filter out empty components (e.g. "foo//bar.c") components = [x for x in components if not isinstance(x, LiteralExpr) or x.value] return PathExpr(components, anchor=visitor.anchor, anchor_file=visitor.anchor_file, pos=e.pos)