def __init__(self, name, text=None, **kwargs): """ Creates an XML node with given element name. If provided, the text is used for its textual content. Any provided keyword arguments are used to add attributes to the node. Examples: >>> Node("ImportGroup", Label="PropertySheets", Foo="A") # creates <ImportGroup Label="PropertySheets" Foo="a"/> >>> Node("LinkIncremental", True) # creates <LinkIncremental>true</LinkIncremental> """ self.name = name self.text = text self.attrs = OrderedDict() self.children = [] for key in sorted(kwargs.keys()): self.attrs[key] = kwargs[key]
def __init__(self, toolset, module): slnfile = module["%s.solutionfile" % toolset.name].as_native_path_for_output(module) self.name = module.name # unlike targets, modules' names aren't globally unique, so use the fully qualified name, which is self.guid = GUID(NAMESPACE_SLN_GROUP, module.project.top_module.name, module.fully_qualified_name) self.projects = OrderedDict() self.subsolutions = [] self.parent_solution = None paths_info = bkl.expr.PathAnchorsInfo( dirsep="\\", outfile=slnfile, builddir=None, model=module) self.formatter = VSExprFormatter(module.project.settings, paths_info) self.generate_outf = module["%s.generate-solution" % toolset.name] if self.generate_outf: self.outf = OutputFile(slnfile, EOL_WINDOWS, creator=toolset, create_for=module) else: self.outf = None
def write(self): """Writes the solution to the file.""" if not self.generate_outf: return # silently do nothing outf = self.outf self.write_header(outf) # Projects: all_own_projects = list(self.all_projects()) additional_deps = self.additional_deps() included_projects = all_own_projects + additional_deps if not included_projects: return # don't write empty solution files configurations = OrderedSet() for prj in all_own_projects: configurations.update(prj.configurations) platforms = OrderedSet() for prj in all_own_projects: platforms.update(prj.platforms) # HACK: Don't use Any CPU for solution config if there are native ones: if "Any CPU" in platforms and len(platforms) > 1: platforms.remove("Any CPU") for prj in included_projects: outf.write('Project("%s") = "%s", "%s", "{%s}"\n' % (prj.kind, prj.name, self.formatter.format(prj.projectfile), str(prj.guid))) if prj.dependencies: outf.write("\tProjectSection(ProjectDependencies) = postProject\n") for d in prj.dependencies: outf.write("\t\t{%(g)s} = {%(g)s}\n" % {'g':self._get_target_guid(d)}) outf.write("\tEndProjectSection\n") outf.write("EndProject\n") # Folders in the solution: all_folders = list(self.all_subsolutions()) if additional_deps: class AdditionalDepsFolder: pass extras = AdditionalDepsFolder() extras.name = "Additional Dependencies" extras.guid = GUID(NAMESPACE_INTERNAL, self.name, extras.name) extras.projects = OrderedDict() for prj in additional_deps: extras.projects[prj.name] = prj extras.subsolutions = [] extras.parent_solution = None all_folders.append(extras) for sln in all_folders: # don't have folders with just one item in them: sln.omit_from_tree = (sln.parent_solution and (len(sln.projects) + len(sln.subsolutions)) <= 1) if sln.omit_from_tree: continue outf.write('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "%s", "%s", "{%s}"\n' % (sln.name, sln.name, sln.guid)) outf.write("EndProject\n") all_folders = list(x for x in all_folders if not x.omit_from_tree) # Global settings: outf.write("Global\n") outf.write("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n") for cfg in configurations: for plat in platforms: outf.write("\t\t%s|%s = %s|%s\n" % (cfg.name, plat, cfg.name, plat)) outf.write("\tEndGlobalSection\n") outf.write("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n") for prj in included_projects: guid = prj.guid for cfg in configurations: cfgp = _get_matching_project_config(cfg, prj) for plat in platforms: platp = _get_matching_project_platform(plat, prj) if platp is None: # Can't build in this solution config. Just use any project platform # and omit the Build.0 node -- VS does the same in this case. platp = prj.platforms[0] outf.write("\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n" % (guid, cfg.name, plat, cfgp.name, platp)) else: outf.write("\t\t{%s}.%s|%s.ActiveCfg = %s|%s\n" % (guid, cfg.name, plat, cfgp.name, platp)) if cfg not in prj.disabled_configurations: outf.write("\t\t{%s}.%s|%s.Build.0 = %s|%s\n" % (guid, cfg.name, plat, cfgp.name, platp)) outf.write("\tEndGlobalSection\n") outf.write("\tGlobalSection(SolutionProperties) = preSolution\n") outf.write("\t\tHideSolutionNode = FALSE\n") outf.write("\tEndGlobalSection\n") # Nesting of projects and folders in the tree: if all_folders: outf.write("\tGlobalSection(NestedProjects) = preSolution\n") def _gather_folder_children(sln): prjs = [p for p in sln.projects.itervalues()] slns = [] for s in sln.subsolutions: if s.omit_from_tree: p2, s2 = _gather_folder_children(s) prjs += p2 slns += s2 else: slns.append(s) return (prjs, slns) for sln in all_folders: prjs, subslns = _gather_folder_children(sln) for prj in prjs: outf.write("\t\t{%s} = {%s}\n" % (prj.guid, sln.guid)) for subsln in subslns: outf.write("\t\t{%s} = {%s}\n" % (subsln.guid, sln.guid)) outf.write("\tEndGlobalSection\n") outf.write("EndGlobal\n") outf.commit()
def _gen_makefile(self, build_graphs, module): # Flag indicating whether this makefile actually builds anything. self.uses_builddir = False output_value = module.get_variable_value("%s.makefile" % self.name) output = output_value.as_native_path_for_output(module) paths_info = expr.PathAnchorsInfo( dirsep="/", # FIXME - format-configurable outfile=output, builddir=None, model=module) mk_fmt = self.Formatter() expr_fmt = self.ExprFormatter(self, paths_info) f = io.OutputFile(output, io.EOL_UNIX, creator=self, create_for=module) self.on_header(f, module) self._gen_settings(module, mk_fmt, expr_fmt, f) #FIXME: make this part of the formatter for (future) IdRefExpr 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) def _get_submodule_deps(main, submodule): """ Return list of dependencies that 'submodule' has on other submodules of 'main'. Submodules have dependency if a target from one depends on a target from another. """ mod_deps = set() project = main.project inspect = [submodule] + [p for p in project.modules if p.is_submodule_of(submodule)] for mod in inspect: for target in mod.targets.itervalues(): for dep in target["deps"]: tdep = project.get_target(dep.as_py()) tmod = tdep.parent if tmod is main: mod_deps.add(_format_dep(tdep)) elif tmod.is_submodule_of(main): while tmod.parent is not main: tmod = tmod.parent if tmod is not submodule: mod_deps.add(tmod.name) return sorted(mod_deps) # Write the "all" target: all_targets = ( [_format_dep(t) for t in module.targets.itervalues()] + [sub.name for sub in module.submodules] ) f.write(mk_fmt.target(name="all", deps=all_targets, commands=None)) phony_targets = ["all", "clean"] targets_from_submodules = OrderedDict() submakefiles = OrderedDict() for sub in module.submodules: subpath = sub.get_variable_value("%s.makefile" % self.name) # FIXME: use $dirname(), $basename() functions, this is hacky subdir = subpath.get_directory_path() subfile = subpath.components[-1] submakefiles[sub] = (sub.name, expr_fmt.format(subdir), expr_fmt.format(subfile), _get_submodule_deps(module, sub)) for subname, subdir, subfile, subdeps in submakefiles.itervalues(): subcmd = mk_fmt.submake_command(subdir, subfile, "all") f.write(mk_fmt.target(name=subname, deps=subdeps, commands=[subcmd])) phony_targets.append(subname) for t in module.targets.itervalues(): with error_context(t): # collect target's dependencies target_deps = [] for dep in t["deps"]: tdep = module.project.get_target(dep.as_py()) tdepstr = _format_dep(tdep) target_deps.append(tdepstr) if tdep.parent is not module: # link external dependencies with submodules to build them tmod = tdep.parent while tmod.parent is not None and tmod.parent is not module: tmod = tmod.parent if tmod in module.submodules: targets_from_submodules[tdepstr] = tmod # generate code for the target's build graph: graph = build_graphs[t] for node in graph.all_nodes(): with error_context(node): if node.outputs: out = node.outputs else: out = [node.name] phony_targets.append(expr_fmt.format(out[0])) deps = [expr_fmt.format(i) for i in node.inputs] if node is graph.main: deps += target_deps out_fmt = [expr_fmt.format(x) for x in out] commands_fmt = [expr_fmt.format(c) for c in node.commands] if len(out_fmt) == 1: text = mk_fmt.target(name=out_fmt[0], deps=deps, commands=commands_fmt) else: text = mk_fmt.multifile_target( outputs=out, outfiles=out_fmt, deps=deps, commands=commands_fmt) f.write(text) all_targets += out_fmt # dependencies on submodules to build targets from them: if targets_from_submodules: f.write("# Targets from sub-makefiles:\n") for t, tsub in targets_from_submodules.iteritems(): f.write(mk_fmt.target(name=t, deps=[submakefiles[tsub][0]], commands=None)) # Write the "clean" target: clean_cmds = self._get_clean_commands( mk_fmt, expr_fmt, (build_graphs[t] for t in module.targets.itervalues()), submakefiles.itervalues()) f.write(mk_fmt.target(name="clean", deps=[], commands=clean_cmds)) self.on_phony_targets(f, phony_targets) self.on_footer(f, module) f.commit()