1# @file CompilerPlugin.py
2##
3# Copyright (c) Microsoft Corporation.
4# SPDX-License-Identifier: BSD-2-Clause-Patent
5##
6
7import logging
8import os
9import re
10from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
11from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
12from edk2toolext.environment.uefi_build import UefiBuilder
13from edk2toolext import edk2_logging
14from edk2toolext.environment.var_dict import VarDict
15
16
17class CompilerPlugin(ICiBuildPlugin):
18    """
19    A CiBuildPlugin that compiles the package dsc
20    from the package being tested.
21
22    Configuration options:
23    "CompilerPlugin": {
24        "DscPath": "<path to dsc from root of pkg>"
25    }
26    """
27
28    def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
29        """ Provide the testcase name and classname for use in reporting
30
31            Args:
32              packagename: string containing name of package to build
33              environment: The VarDict for the test to run in
34            Returns:
35                a tuple containing the testcase name and the classname
36                (testcasename, classname)
37        """
38        target = environment.GetValue("TARGET")
39        return ("Compile " + packagename + " " + target, packagename + ".Compiler." + target)
40
41    def RunsOnTargetList(self):
42        return ["DEBUG", "RELEASE"]
43
44    ##
45    # External function of plugin.  This function is used to perform the task of the ICiBuildPlugin Plugin
46    #
47    #   - package is the edk2 path to package.  This means workspace/packagepath relative.
48    #   - edk2path object configured with workspace and packages path
49    #   - PkgConfig Object (dict) for the pkg
50    #   - EnvConfig Object
51    #   - Plugin Manager Instance
52    #   - Plugin Helper Obj Instance
53    #   - Junit Logger
54    #   - output_stream the StringIO output stream from this plugin via logging
55    def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
56        self._env = environment
57
58        # Parse the config for required DscPath element
59        if "DscPath" not in pkgconfig:
60            tc.SetSkipped()
61            tc.LogStdError("DscPath not found in config file.  Nothing to compile.")
62            return -1
63
64        AP = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
65
66        APDSC = os.path.join(AP, pkgconfig["DscPath"].strip())
67        AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC)
68        if AP is None or AP_Path is None or not os.path.isfile(APDSC):
69            tc.SetSkipped()
70            tc.LogStdError("Package Dsc not found.")
71            return -1
72
73        logging.info("Building {0}".format(AP_Path))
74        self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Plugin")
75
76        # Parse DSC to check for SUPPORTED_ARCHITECTURES
77        dp = DscParser()
78        dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
79        dp.SetPackagePaths(Edk2pathObj.PackagePathList)
80        dp.ParseFile(AP_Path)
81        if "SUPPORTED_ARCHITECTURES" in dp.LocalVars:
82            SUPPORTED_ARCHITECTURES = dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|')
83            TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(' ')
84
85            # Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES
86            if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES)) == 0:
87                tc.SetSkipped()
88                tc.LogStdError("No supported architecutres to build")
89                return -1
90
91        uefiBuilder = UefiBuilder()
92        # do all the steps
93        # WorkSpace, PackagesPath, PInHelper, PInManager
94        ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath, os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM)
95        if ret != 0:  # failure:
96            tc.SetFailed("Compile failed for {0}".format(packagename), "Compile_FAILED")
97            tc.LogStdError("{0} Compile failed with error code {1} ".format(AP_Path, ret))
98            return 1
99
100        else:
101            tc.SetSuccess()
102            return 0
103