Example #1
0
    def gen_for_module(self, module):
        # attach VS2010-specific data to the model
        module.solution = self.Solution(self, module)

        for t in module.targets.itervalues():
            with error_context(t):
                prj = self.get_project_object(t)
                if prj is None:
                    # TODO: see the TODO in get_project_object()
                    continue
                if prj.name != t.name:
                    # TODO: This is only for the solution file; we should remap the name instead of
                    #       failure. Note that we don't always control prj.name, it may come from external
                    #       project file.
                    raise Error("project name (\"%s\") differs from target name (\"%s\"), they must be the same" %
                                (prj.name, t.name))
                if prj.version and prj.version not in self.proj_versions:
                    if prj.version > self.proj_versions[-1]:
                        raise Error("project %s is for Visual Studio %.1f and will not work with %.1f" %
                                    (prj.projectfile, prj.version, self.version))
                    else:
                        warning("project %s is for Visual Studio %.1f, not %.1f, will be converted when built",
                                prj.projectfile, prj.version, self.version)

                if self.is_natively_supported(t):
                    self.gen_for_target(t, prj)

                module.solution.add_project(prj)
Example #2
0
 def _do_format_node(self, n, indent):
     attrs = self._get_quoted_nonempty_attrs(n)
     if n.children:
         children_markup = []
         assert not n.text, "nodes with both text and children not implemented"
         subindent = indent + self.indent_step
         for key, value in n.children:
             if isinstance(value, Node):
                 assert key == value.name
                 children_markup.append(self._do_format_node(value, subindent))
             else:
                 try:
                     v = escape(self.format_value(value))
                     if v:
                         children_markup.append("%s<%s>%s</%s>\n" % (subindent, key, v, key))
                     # else: empty value, don't write that
                 except CannotDetermineError as e:
                     with error_context(value):
                         raise Error("cannot set property \"%s\" to non-constant expression \"%s\" (%s)" %
                                     (key, value, e.msg))
         children_markup = "".join(children_markup)
     else:
         children_markup = None
     text = self.format_value(n.text) if n.text else None
     return self.format_node(n.name, attrs, text, children_markup, indent)
Example #3
0
    def add_module(self, ast, parent):
        """
        Adds parsed AST to the model, without doing any optimizations. May be
        called more than once, with different parsed files.

        :param ast: AST of the input file, as returned by
               :func:`bkl.parser.parse_file`.
        """
        logger.info("processing %s", ast.filename)

        submodules = []
        b = Builder(on_submodule=lambda fn, pos: submodules.append((fn, pos)))

        module = b.create_model(ast, parent)

        while submodules:
            sub_filename, sub_pos = submodules[0]
            submodules.pop(0)
            try:
                sub_ast = parse_file(sub_filename)
            except IOError as e:
                if e.filename:
                    msg = "%s: %s" % (e.strerror, e.filename)
                else:
                    msg = e.strerror
                raise Error(msg, pos=sub_pos)
            self.add_module(sub_ast, module)
Example #4
0
 def path(self, e):
     if e.anchor == bkl.expr.ANCHOR_BUILDDIR and self.toolset is not None:
         if self.target is None:
             raise Error("@builddir references are not allowed outside of targets", pos=e.pos)
         bdir = self._builddir(self.target)
         e = bkl.expr.PathExpr(bdir.components + e.components,
                               bdir.anchor, bdir.anchor_file,
                               pos=e.pos)
     if e.anchor == bkl.expr.ANCHOR_SRCDIR:
         assert self.module is not None
         if e.anchor_file:
             source_file = e.anchor_file
         elif e.pos and e.pos.filename:
             source_file = e.pos.filename
         else:
             source_file = self.module.source_file
         prefix = self._src_prefix(source_file)
         components = e.components
         if prefix is not None:
             # Don't mess the path if it starts with user setting and so
             # should be treated as absolute.
             if not e.is_external_absolute():
                 components = prefix + components
         e = bkl.expr.PathExpr(components,
                               bkl.expr.ANCHOR_TOP_SRCDIR, None,
                               pos=e.pos)
     return e
Example #5
0
    def generate(self):
        """
        Generates output files.
        """
        # collect all requested toolsets:
        toolsets = set()
        for module in self.model.modules:
            module_toolsets = module.get_variable("toolsets")
            if module_toolsets:
                toolsets.update(module_toolsets.value.as_py())

        if self.toolsets_to_use:
            for t in self.toolsets_to_use:
                if t not in toolsets:
                    try:
                        bkl.api.Toolset.get(t)
                    except KeyError:
                        raise Error(
                            "unknown toolset \"%s\" given on command line" % t)
                    warning(
                        "toolset \"%s\" is not supported by the project, there may be issues",
                        t)
                    # Add the forced toolset to all submodules:
                    for module in self.model.modules:
                        module_toolsets = module.get_variable("toolsets")
                        if module_toolsets:
                            module_toolsets.value.items.append(
                                bkl.expr.LiteralExpr(t))
            toolsets = self.toolsets_to_use

        toolsets = list(toolsets)
        logger.debug("toolsets to generate for: %s", toolsets)

        if not toolsets:
            raise Error("nothing to generate, \"toolsets\" property is empty")

        # call any custom steps first:
        self._call_custom_steps(self.model, "generate")

        # and generate the outputs (notice that we can avoid making a
        # (expensive!) deepcopy of the model for one of the toolsets and can
        # reuse the current model):
        for toolset in toolsets[:-1]:
            self.generate_for_toolset(toolset)
        self.generate_for_toolset(toolsets[-1], skip_making_copy=True)
Example #6
0
 def version(self):
     v = self.xml.get("Version")
     if v and "," in v:
         # vcproj files written under some locales (French, Czech) may use
         # ',' as decimal point character.
         v = v.replace(",", ".")
     if   v == "7.10": return 7.1
     elif v == "8.00": return 8
     elif v == "9.00": return 9
     else:
         raise Error("unrecognized version of Visual Studio project %s: Version=\"%s\"" % (
                     self.projectfile, v))
Example #7
0
 def _format_dep(t):
     g = build_graphs[t].main
     if len(g.outputs) == 0:
         assert g.name
         if t.parent is not module:
             raise Error("cross-module dependencies on phony targets (\"%s\") not supported yet" % t.name) # TODO
         out = g.name
     else:
         # FIXME: handle multi-output nodes too
         assert len(g.outputs) == 1
         out = g.outputs[0]
     return expr_fmt.format(out)
Example #8
0
def load_from_file(filename):
    """
    Load a Bakefile plugin from given file.
    """
    import os.path
    import imp
    from bkl.error import Error
    basename = os.path.splitext(os.path.basename(filename))[0]
    if basename.startswith("bkl.plugins."):
        modname = basename
    else:
        modname = "bkl.plugins.%s" % basename.replace(".", "_")

    if modname in sys.modules:
        prev_file = sys.modules[modname].__file__
        if filename == prev_file or filename == prev_file[:-1]:  #.pyc->.py
            # plugin already loaded from this file, skip it
            __logger.debug(
                "plugin %s from %s is already loaded, nothing to do", modname,
                filename)
            return
        else:
            raise Error(
                "cannot load plugin %s from %s: plugin with the same name already loaded from %s"
                % (modname, filename, prev_file))

    try:
        global __all__
        __logger.debug("loading plugin %s from %s", modname, filename)
        globals()[basename] = imp.load_source(modname, filename)
        __all__.append(basename)
    except Error:
        raise
    except IOError as e:
        raise Error("failed to load plugin %s:\n%s" % (filename, e))
    except Exception:
        import traceback
        raise Error("failed to load plugin %s:\n%s" %
                    (filename, traceback.format_exc()))
Example #9
0
 def reference(self, e):
     var = e.get_variable()
     if var is None:
         # reference to default value of a property
         return
     if var in self.stack:
         # TODO: include complete stack of messages+positions
         raise Error(
             'variable "%s" is defined recursively, references itself' %
             var.name,
             pos=e.pos)
     else:
         self.check(var)
Example #10
0
 def version(self):
     v = self.xml.get("ToolsVersion")
     if v == "14.0":
         return 14
     elif v != "4.0":
         raise Error("unrecognized version of Visual Studio project %s: ToolsVersion=\"%s\"" %(
                     self.projectfile, v))
     # TODO-PY26: use "PropertyGroup[@Label='Configuration']"
     t = self.xml.findtext("{%(ms)s}PropertyGroup/{%(ms)s}PlatformToolset" % XMLNS)
     if t == "v110":
         return 11
     else:
         return 10
Example #11
0
    def multifile_target(self, outputs, outfiles, deps, commands):
        """
        Returns string with target definition for targets that produce multiple
        files. A typical example is Bison parser generator, which produces both
        .c and .h files.

        :param outputs:  List of output files of the rule, as objects.
        :param outfiles: List of output files of the rule, as strings.
        :param deps:     See target()
        :param commands: See target()
        """
        # TODO: Implement these. Could you pattern rules with GNU make,
        #       or stamp files.
        raise Error("rules with multiple output files not implemented yet (%s from %s)" % (outfiles, deps))
Example #12
0
 def multifile_target(self, outputs, outfiles, deps, commands):
     # Use a helper intermediate target to handle multiple outputs of a rule,
     # because we can't easily use GNU Make's pattern rules matching. The
     # absence of an intermediate file is not a problem and does not cause
     # spurious builds. See for details:
     #   http://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
     #   http://stackoverflow.com/a/10609434/237188
     for c in commands:
         if '$@' in c:
             raise Error("The use of $@ or %%(out) not supported with multiple outputs (in \"%s\")" % c)
     inter_name = ".dummy_" + "_".join("_".join(c.as_py() for c in f.components) for f in outputs)
     return "\n".join([
         "%s: %s" % (" ".join(outfiles), inter_name),
         ".INTERMEDIATE: %s" % inter_name,
         self.target(inter_name, deps, commands)
         ])
Example #13
0
 def configurations(self):
     known = self._project.configurations
     lst = []
     for name in filter_duplicates(self._extract_configurations_names()):
         try:
             lst.append(known[name])
         except KeyError:
             if "Debug" in name:
                 base = known["Debug"]
             elif "Release" in name:
                 base = known["Release"]
             else:
                 raise Error("don't know whether the \"%s\" configuration from external %s is debug or release; please define it in your bakefile explicitly" % (name, self.projectfile),
                             pos=self.source_pos)
             cfg = base.create_derived(name)
             self._project.add_configuration(cfg)
             lst.append(cfg)
     return lst
Example #14
0
    def __init__(self, filename, eol, charset="utf-8",
                 creator=None, create_for=None):
        """
        Creates output file.

        :param filename: Name of the output file. Should be either relative
                         to CWD or absolute; the latter is recommended.
        :param eol:      Line endings to use. One of EOL_WINDOWS and EOL_UNIX.
        :param charset:  Charset to use if Unicode string is passed to write().
        :param creator:  Who is creating the file; typically toolset object.
        :param create_for: Object the file is created for, e.g. a module or a target.
        """
        if filename in _all_written_files:
            creator1, create_for1 = _all_written_files[filename]
            from bkl.error import Error
            raise Error("conflict in file %(filename)s, generated both by %(creator1)s for %(create_for1)s and %(creator)s for %(create_for)s" % locals())
        _all_written_files[filename] = (creator, create_for)

        self.filename = filename
        self.eol = eol
        self.charset = charset
        self.text = ""
Example #15
0
 def placeholder(self, e):
     name = e.var
     if name == "arch":
         raise Error("multi-arch builds are not supported by makefiles ($(arch) referenced)", pos=e.pos)
     return "$(%s)" % name