Exemplo n.º 1
0
class ExternalTargetType(TargetType):
    """
    External build system.

    This target type is used to invoke makefiles or project files not
    implemented in Bakefile, for example to build 3rd party libraries.

    Currently, only Visual Studio projects (vcproj, vcxproj, csproj) are
    supported and only when using a Visual Studio toolset.
    """
    name = "external"

    properties = [
            Property("file",
                 type=PathType(),
                 inheritable=False,
                 doc="File name of the external makefile or project."),
        ]

    def get_build_subgraph(self, toolset, target):
        return self.get_handler(target).get_build_subgraph(toolset, target)

    def vs_project(self, toolset, target):
        return self.get_handler(target).vs_project(toolset, target)

    def get_handler(self, target):
        with error_context(target["file"]):
            return ExternalBuildHandler.get_for_file(target["file"].as_native_path_for_output(target))
Exemplo n.º 2
0
 def properties_target(cls):
     yield Property("%s.projectfile" % cls.name,
                    type=PathType(),
                    default=update_wrapper(partial(_project_name_from_solution, cls), _project_name_from_solution),
                    inheritable=False,
                    doc="File name of the project for the target.")
     yield Property("%s.guid" % cls.name,
                    # TODO: use custom GUID type, so that user-provided GUIDs can be validated (and upper-cased)
                    # TODO: make this vs.guid and share among VS toolsets
                    type=StringType(),
                    default=_default_guid_for_project,
                    inheritable=False,
                    doc="GUID of the project.")
Exemplo n.º 3
0
 def properties_module(cls):
     yield Property("%s.solutionfile" % cls.name,
                    type=PathType(),
                    default=_default_solution_name,
                    inheritable=False,
                    doc="File name of the solution file for the module.")
     yield Property("%s.generate-solution" % cls.name,
                    type=BoolType(),
                    default=True,
                    inheritable=False,
                    doc="""
                        Whether to generate solution file for the module. Set to
                        ``false`` if you want to omit the solution, e.g. for some
                        submodules with only a single target.
                        """)
Exemplo n.º 4
0
class VS201xToolsetBase(VSToolsetBase):
    """Base class for VS2010, VS2012, VS2013, VS2015 and VS2017 toolsets."""

    #: XML formatting class
    XmlFormatter = VS201xXmlFormatter

    #: Extension of format files
    proj_extension = "vcxproj"

    #: PlatformToolset property
    platform_toolset = None

    #: ToolsVersion property
    tools_version = "4.0"

    properties_target_vs201x = [
            Property("vs.property-sheets",
                     type=ListType(PathType()),
                     default=bkl.expr.NullExpr(),
                     inheritable=False,
                     doc="""
                         May contain paths to one or more property sheets files
                         that will be imported from the generated project if they
                         exist.
                         """)
        ]

    @classmethod
    def properties_target(cls):
        for p in cls.properties_target_vsbase():
            yield p
        for p in cls.properties_target_vs201x:
            yield p

    def gen_for_target(self, target, project):
        rc_files = []
        cl_files = []
        idl_files = []
        for sfile in target.sources:
            ext = sfile.filename.get_extension()
            # TODO: share this code with VS200x
            # FIXME: make this more solid
            if ext == 'rc':
                rc_files.append(sfile)
            elif ext == 'idl':
                idl_files.append(sfile)
            else:
                cl_files.append(sfile)

        root = Node("Project")
        root["DefaultTargets"] = "Build"
        root["ToolsVersion"] = self.tools_version
        root["xmlns"] = "http://schemas.microsoft.com/developer/msbuild/2003"

        n_configs = Node("ItemGroup", Label="ProjectConfigurations")
        for cfg in self.configs_and_platforms(target):
            n = Node("ProjectConfiguration", Include="%s" % cfg.vs_name)
            n.add("Configuration", cfg.name)
            n.add("Platform", cfg.vs_platform)
            n_configs.add(n)
        root.add(n_configs)

        n_globals = Node("PropertyGroup", Label="Globals")
        n_globals.add("ProjectGuid", "{%s}" % project.guid)
        n_globals.add("Keyword", "Win32Proj")
        n_globals.add("RootNamespace", target.name)
        n_globals.add("ProjectName", target.name)
        self._add_extra_options_to_node(target, n_globals)
        root.add(n_globals)

        root.add("Import", Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props")

        for cfg in self.configs_and_platforms(target):
            n = Node("PropertyGroup", Label="Configuration")
            n["Condition"] = "'$(Configuration)|$(Platform)'=='%s'" % cfg.vs_name
            if is_program(target):
                n.add("ConfigurationType", "Application")
            elif is_library(target):
                n.add("ConfigurationType", "StaticLibrary")
            elif is_dll(target):
                n.add("ConfigurationType", "DynamicLibrary")
            else:
                assert False, "this code should only be called for supported target types"

            n.add("UseDebugLibraries", cfg.is_debug)
            if cfg["win32-unicode"]:
                n.add("CharacterSet", "Unicode")
            else:
                n.add("CharacterSet", "MultiByte")
            if self.platform_toolset:
                n.add("PlatformToolset", self.platform_toolset)
            self._add_extra_options_to_node(cfg, n)
            root.add(n)

        root.add("Import", Project="$(VCTargetsPath)\\Microsoft.Cpp.props")
        root.add("ImportGroup", Label="ExtensionSettings")

        for cfg in self.configs_and_platforms(target):
            n = Node("ImportGroup", Label="PropertySheets")
            n["Condition"] = "'$(Configuration)|$(Platform)'=='%s'" % cfg.vs_name
            n.add("Import",
                  Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props",
                  Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')",
                  Label="LocalAppDataPlatform")

            for property_sheet in cfg["vs.property-sheets"]:
                # For now, always add exists() condition unconditionally as
                # it's often useful to have it, but we don't provide any way
                # to request it explicitly and not having it would be more
                # problematic than using it unnecessarily (which is not really
                # a problem in practice).
                n.add("Import",
                      Project=property_sheet,
                      Condition=concat("exists('", property_sheet, "')"))

            root.add(n)

        root.add("PropertyGroup", Label="UserMacros")

        for cfg in self.configs_and_platforms(target):
            n = Node("PropertyGroup")
            if not is_library(target):
                n.add("LinkIncremental", cfg.is_debug)
            targetname = cfg["basename"]
            if targetname != target.name:
                n.add("TargetName", targetname)
            if not target.is_variable_null("extension"):
                n.add("TargetExt", target["extension"])
            if is_module_dll(target):
                n.add("IgnoreImportLibrary", True)
            if target.is_variable_explicitly_set("outputdir"):
                n.add("OutDir", concat(cfg["outputdir"], "\\"))
            if self.needs_custom_intermediate_dir(target):
                if cfg.vs_platform != "Win32":
                    intdir = "$(Platform)\\$(Configuration)\\$(ProjectName)\\"
                else:
                    intdir = "$(Configuration)\\$(ProjectName)\\"
                n.add("IntDir", intdir)
            if n.has_children():
                n["Condition"] = "'$(Configuration)|$(Platform)'=='%s'" % cfg.vs_name
            self._add_extra_options_to_node(cfg, n)
            root.add(n)

        for cfg in self.configs_and_platforms(target):
            n = Node("ItemDefinitionGroup")
            n["Condition"] = "'$(Configuration)|$(Platform)'=='%s'" % cfg.vs_name
            n_cl = Node("ClCompile")
            n_cl.add("WarningLevel", self.get_vs_warning_level(cfg))
            if cfg.is_debug:
                n_cl.add("Optimization", "Disabled")
            else:
                n_cl.add("Optimization", "MaxSpeed")
                n_cl.add("FunctionLevelLinking", True)
                n_cl.add("IntrinsicFunctions", True)
            std_defs = self.get_std_defines(target, cfg)
            std_defs.append("%(PreprocessorDefinitions)")
            n_cl.add("PreprocessorDefinitions", list(cfg["defines"]) + std_defs)
            n_cl.add("MultiProcessorCompilation", True)
            n_cl.add("MinimalRebuild", False)
            n_cl.add("AdditionalIncludeDirectories", cfg["includedirs"])

            crt = "MultiThreaded"
            if cfg.is_debug:
                crt += "Debug"
            if cfg["win32-crt-linkage"] == "dll":
                crt += "DLL"
            n_cl.add("RuntimeLibrary", crt)

            # Currently we don't make any distinction between preprocessor, C
            # and C++ flags as they're basically all the same at MSVS level
            # too and all go into the same place in the IDE and same
            # AdditionalOptions node in the project file.
            all_cflags = VSList(" ", cfg["compiler-options"],
                                     cfg["c-compiler-options"],
                                     cfg["cxx-compiler-options"])
            if all_cflags:
                all_cflags.append("%(AdditionalOptions)")
                n_cl.add("AdditionalOptions", all_cflags)

            self._add_extra_options_to_node(cfg, n_cl)
            n.add(n_cl)

            if rc_files:
                n_res = Node("ResourceCompile")
                n_res.add("AdditionalIncludeDirectories", cfg["includedirs"])
                std_defs = []
                if cfg["win32-unicode"]:
                    std_defs.append("_UNICODE")
                    std_defs.append("UNICODE")
                # See the comment in VCResourceCompilerTool in vs200x.py for
                # the explanation of why do we do this even though the native
                # projects don't define _DEBUG/NDEBUG for the RC files.
                std_defs.append("_DEBUG" if cfg.is_debug else "NDEBUG")
                std_defs.append("%(PreprocessorDefinitions)")
                n_res.add("PreprocessorDefinitions", list(cfg["defines"]) + std_defs)
                self._add_extra_options_to_node(cfg, n_res)
                n.add(n_res)

            if idl_files:
                n_idl = Node("Midl")
                n_idl.add("AdditionalIncludeDirectories", cfg["includedirs"])
                self._add_extra_options_to_node(cfg, n_idl)
                n.add(n_idl)

            n_link = Node("Link")
            if is_program(target) and target["win32-subsystem"] == "console":
                n_link.add("SubSystem", "Console")
            else:
                n_link.add("SubSystem", "Windows")
            n_link.add("GenerateDebugInformation", True)
            if not cfg.is_debug:
                n_link.add("EnableCOMDATFolding", True)
                n_link.add("OptimizeReferences", True)
            if not is_library(target):
                libdirs = VSList(";", target.type.get_libdirs(cfg))
                if libdirs:
                    libdirs.append("%(AdditionalLibraryDirectories)")
                    n_link.add("AdditionalLibraryDirectories", libdirs)
                ldflags = VSList(" ", target.type.get_link_options(cfg))
                if ldflags:
                    ldflags.append("%(AdditionalOptions)")
                    n_link.add("AdditionalOptions", ldflags)
                libs = target.type.get_ldlibs(cfg)
                if libs:
                    addlibs = VSList(";", ("%s.lib" % x.as_py() for x in libs if x))
                    addlibs.append("%(AdditionalDependencies)")
                    if is_library(target):
                        n_lib = Node("Lib")
                        self._add_extra_options_to_node(cfg, n_lib)
                        n.add(n_lib)
                        n_lib.add("AdditionalDependencies", addlibs)
                    else:
                        n_link.add("AdditionalDependencies", addlibs)
            self._add_extra_options_to_node(cfg, n_link)
            n.add(n_link)

            n_manifest = Node("Manifest")
            self._add_extra_options_to_node(cfg, n_manifest)
            if n_manifest.has_children():
                n.add(n_manifest)

            pre_build = cfg["pre-build-commands"]
            if pre_build:
                n_script = Node("PreBuildEvent")
                n_script.add("Command", VSList("\n", pre_build))
                n.add(n_script)
            post_build = cfg["post-build-commands"]
            if post_build:
                n_script = Node("PostBuildEvent")
                n_script.add("Command", VSList("\n", post_build))
                n.add(n_script)
            root.add(n)

        # Source files:
        if cl_files:
            items = Node("ItemGroup")
            root.add(items)
            cl_files_map = bkl.compilers.disambiguate_intermediate_file_names(cl_files)
            for sfile in cl_files:
                if sfile["compile-commands"]:
                    self._add_custom_build_file(items, sfile)
                else:
                    ext = sfile.filename.get_extension()
                    # TODO: share this code with VS200x
                    # FIXME: make this more solid
                    if ext in ['cpp', 'cxx', 'cc', 'c']:
                        n_cl_compile = Node("ClCompile", Include=sfile.filename)
                    else:
                        # FIXME: handle both compilation into cpp and c files
                        genfiletype = bkl.compilers.CxxFileType.get()
                        genname = bkl.expr.PathExpr([bkl.expr.LiteralExpr(sfile.filename.get_basename())],
                                                    bkl.expr.ANCHOR_BUILDDIR,
                                                    pos=sfile.filename.pos).change_extension("cpp")

                        ft_from = bkl.compilers.get_file_type(ext)
                        compiler = bkl.compilers.get_compiler(self, ft_from, genfiletype)

                        customBuild = Node("CustomBuild", Include=sfile.filename)
                        customBuild.add("Command", VSList("\n", compiler.commands(self, target, sfile.filename, genname)))
                        customBuild.add("Outputs", genname)
                        items.add(customBuild)
                        n_cl_compile = Node("ClCompile", Include=genname)
                    # Handle files with custom object name:
                    if sfile in cl_files_map:
                        n_cl_compile.add("ObjectFileName",
                                         concat("$(IntDir)\\", cl_files_map[sfile], ".obj"))
                    self._add_per_file_options(sfile, n_cl_compile)
                    items.add(n_cl_compile)

        # Headers files:
        if target.headers:
            items = Node("ItemGroup")
            root.add(items)
            for sfile in target.headers:
                if sfile["compile-commands"]:
                    self._add_custom_build_file(items, sfile)
                else:
                    items.add("ClInclude", Include=sfile.filename)

        # Resources:
        if rc_files:
            items = Node("ItemGroup")
            root.add(items)
            rc_files_map = bkl.compilers.disambiguate_intermediate_file_names(rc_files)
            for sfile in rc_files:
                n_rc_compile = Node("ResourceCompile", Include=sfile.filename)
                # Handle files with custom object name:
                if sfile in rc_files_map:
                    n_rc_compile.add("ResourceOutputFileName",
                                     concat("$(IntDir)\\", rc_files_map[sfile], ".res"))
                self._add_per_file_options(sfile, n_rc_compile)
                items.add(n_rc_compile)

        # IDL files:
        if idl_files:
            items = Node("ItemGroup")
            root.add(items)
            for sfile in idl_files:
                n_midl = Node("Midl", Include=sfile.filename)
                self._add_per_file_options(sfile, n_midl)
                items.add(n_midl)

        filename = project.projectfile.as_native_path_for_output(target) 
        dirname = os.path.dirname( filename )
        targetspath = filename.split('-')[0] + '.Targets'
        targetsfile = ''
        if os.path.exists( targetspath ):
            nothing, targetsfile = os.path.split( targetspath )
        packagesconfig = dirname + '/packages.config'
        othertargets = Node("ItemGroup")
        if os.path.exists( packagesconfig ):
            root.add(othertargets)
            packagesnode = Node("None", Include="packages.config")
            othertargets.add(packagesnode)
            winsparkletargetsnode = Node("None", Include=targetsfile)
            othertargets.add(winsparkletargetsnode)
            subtypedesigner = Node("Subtype", "Designer")
            winsparkletargetsnode.add(subtypedesigner)
				
        # Dependencies:
        target_deps = self._get_references(target)
        if target_deps:
            refs = Node("ItemGroup")
            root.add(refs)
            for dep in target_deps:
                dep_prj = self.get_project_object(dep)
                depnode = Node("ProjectReference", Include=dep_prj.projectfile)
                depnode.add("Project", "{%s}" % dep_prj.guid.lower())
                refs.add(depnode)

        root.add("Import", Project="$(VCTargetsPath)\\Microsoft.Cpp.targets")
        targetsnode = Node("ImportGroup", Label="ExtensionTargets")
        root.add(targetsnode)
        if targetsfile != '':
            # print('adding targetsfile: ' + targetsfile + '\n')
            targetsnode.add("Import", Project=targetsfile )

        paths_info = self.get_project_paths_info(target, project)

        formatter = self.XmlFormatter(target.project.settings, paths_info)
        f = OutputFile(filename, EOL_WINDOWS,
                       creator=self, create_for=target)
        f.write(codecs.BOM_UTF8)
        f.write(formatter.format(root))
        f.commit()
        self._write_filters_file_for(filename, formatter,
                                     target.headers, cl_files, idl_files, rc_files)


    def _add_custom_build_file(self, node, srcfile):
        n = Node("CustomBuild", Include=srcfile.filename)
        for cfg in self.configs_and_platforms(srcfile):
            outputs = cfg["outputs"]
            fmt_dict = {"in": srcfile.filename, "out": outputs}
            idx = 0
            for outN in outputs:
                fmt_dict["out%d" % idx] = outN
                idx += 1
            commands = format_string(cfg["compile-commands"], fmt_dict)
            message = format_string(cfg["compile-message"], fmt_dict)

            cond = "'$(Configuration)|$(Platform)'=='%s'" % cfg.vs_name
            n.add(Node("Command", VSList("\n", commands), Condition=cond))
            n.add(Node("Outputs", outputs, Condition=cond))
            dependencies = cfg["dependencies"]
            if dependencies:
                n.add(Node("AdditionalInputs", dependencies, Condition=cond))
            n.add(Node("Message", message if message else commands, Condition=cond))
        node.add(n)


    def _get_references(self, target):
        if not target["deps"]:
            return None

        # In addition to explicit dependencies, add dependencies of static libraries
        # linked into target to the list of references.
        prj = target.project
        deps = [prj.get_target(t) for t in target["deps"].as_py()]
        try:
            more = [t for t in target.type.get_linkable_deps(target) if t not in deps]
            deps.extend(more)
        except AttributeError:
            pass
        return deps


    def _add_extra_options_to_node(self, target, node):
        """Add extra native options specified in vs2010.option.* properties."""
        try:
            scope = node["Label"]
        except KeyError:
            if node.name == "PropertyGroup":
                scope = ""
            else:
                scope = node.name
        for key, value in self.collect_extra_options_for_node(target, scope):
            node.add_or_replace(key, value)


    def _add_per_file_options(self, srcfile, node):
        """Add options that are set on per-file basis."""
        # TODO: add regular options such as 'defines' here too, not just
        #       the vsXXXX.option.* overrides
        for cfg in self.configs_and_platforms(srcfile):
            cond = "'$(Configuration)|$(Platform)'=='%s'" % cfg.vs_name
            if not cfg.should_build():
                node.add(Node("ExcludedFromBuild", True, Condition=cond))
            for key, value in self.collect_extra_options_for_node(srcfile, node.name, inherit=False):
                node.add(Node(key, value, Condition=cond))


    def _write_filters_file_for(self, filename, formatter,
                                hdr_files, cl_files, idl_files, rc_files):
        root = Node("Project")
        root["ToolsVersion"] = "4.0" # even if tools_version is different (VS2013)
        root["xmlns"] = "http://schemas.microsoft.com/developer/msbuild/2003"
        filters = Node("ItemGroup")
        root.add(filters)
        f = Node("Filter", Include="Source Files")
        filters.add(f)
        f.add("UniqueIdentifier", "{4FC737F1-C7A5-4376-A066-2A32D752A2FF}")
        f.add("Extensions", "cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx")
        f = Node("Filter", Include="Header Files")
        filters.add(f)
        f.add("UniqueIdentifier", "{93995380-89BD-4b04-88EB-625FBE52EBFB}")
        f.add("Extensions", "h;hpp;hxx;hm;inl;inc;xsd")
        f = Node("Filter", Include="Resource Files")
        filters.add(f)
        f.add("UniqueIdentifier", "{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}")
        f.add("Extensions", "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms")

        if hdr_files:
            group = Node("ItemGroup")
            root.add(group)
            for sfile in hdr_files:
                n = Node("ClInclude", Include=sfile.filename)
                group.add(n)
                n.add("Filter", "Header Files")

        if cl_files or idl_files:
            group = Node("ItemGroup")
            root.add(group)
            for sfile in cl_files:
                n = Node("ClCompile", Include=sfile.filename)
                group.add(n)
                n.add("Filter", "Source Files")
            for sfile in idl_files:
                n = Node("Midl", Include=sfile.filename)
                group.add(n)
                n.add("Filter", "Source Files")

        if rc_files:
            group = Node("ItemGroup")
            root.add(group)
            for sfile in rc_files:
                n = Node("ResourceCompile", Include=sfile.filename)
                group.add(n)
                n.add("Filter", "Resource Files")

        f = OutputFile(filename + ".filters", EOL_WINDOWS,
                       creator=self, create_for=filename)
        f.write(codecs.BOM_UTF8)
        f.write(formatter.format(root))
        f.commit()


    def _order_configs_and_archs(self, configs_iter, archs_list):
        for c in configs_iter:
            for a in archs_list:
                yield (c, a)


    def get_vs_warning_level(self, cfg):
        """
        Return MSVS warning level option value corresponding to the warning
        option in the specified config.
        """
        WARNING_LEVELS = { "no": "TurnOffAllWarnings",
                           "minimal": "Level1",
                           "default": "Level3",
                           "all": "Level4",
                           "max": "EnableAllWarnings",
        }
        return WARNING_LEVELS[cfg["warnings"].as_py()]
Exemplo n.º 5
0
 def properties_module(cls):
     yield Property("%s.makefile" % cls.name,
                    type=PathType(),
                    default=cls.default_makefile,
                    inheritable=False,
                    doc="Name of output file for module's makefile.")