Skip to content

Settings manager

Each edk2 invocable has an abstract definition of a Settings Manager class that provides needed information such as scope, repositories, command-line options, and other things. This allows scopes to be dynamic but in a standardized way. Below is a sample implementation of a settings manager for your reference.

This is an implementation of both UpdateSettingsManager and SetupSettingsManager using multiple inheritance. You can see that they add their own command line argument --production that is used to toggle the use of the production scope. For any given invocable, you can pass -h or --help to show a list of available command line options. If you call -c <path> --help this list will also include command line options provided from the settings file you provided.

These examples are for building a platform, which needs instances of UpdateSettingsManager, SetupSettingsManager, BuildSettingsManager, and UefiBuilder. The instances can be grouped together in a single class, or separated into different classes.

Examples

All settings grouped together

class SettingsManager(UpdateSettingsManager, SetupSettingsManager, BuildSettingsManager):
    def __init__(self):
        SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
        self.WORKSPACE_PATH = os.path.dirname(os.path.dirname(SCRIPT_PATH))
        self.PRODUCTION_SCOPE = ('production', )
        self.BASE_SCOPE = ('imxfamily', 'imx8')
        self.production = None

    def GetProjectScope(self):
        ''' get scope '''
        SCOPE = self.BASE_SCOPE
        if self.production:
            SCOPE += self.PRODUCTION_SCOPE
        return SCOPE

    def GetWorkspaceRoot(self):
        ''' get WorkspacePath '''
        return self.WORKSPACE_PATH

    def GetPackagesPath(self):
        ''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''
        return ['MU_BASECORE','Silicon/ARM/NXP', 'Common/MU','Common/MU_TIANO', 'Common/MU_OEM_SAMPLE','Silicon/ARM/MU_TIANO']

    def GetRequiredSubmodules(self):
        ''' return iterable containing RequiredSubmodule objects.
        If no RequiredSubmodules return an empty iterable
        '''
        return [RequiredSubmodule('MU_BASECORE'),
                RequiredSubmodule('Silicon/ARM/NXP'),
                RequiredSubmodule('Common/MU'),
                RequiredSubmodule('Common/MU_TIANO'),
                RequiredSubmodule('Common/MU_OEM_SAMPLE'),
                RequiredSubmodule('Silicon/ARM/MU_TIANO') ]

    def AddCommandLineOptions(self, parserObj):
        ''' Add command line options to the argparser '''
        parserObj.add_argument('--production', dest="production", action='store_true', default=False)

    def RetrieveCommandLineOptions(self, args):
        '''  Retrieve command line options from the argparser '''
        self.production = args.production

#--------------------------------------------------------------------------------------------------------
# Subclass the UEFI builder and add platform specific functionality.
#
class PlatformBuilder(UefiBuilder):

    def SetPlatformEnv(self):
        return 0

    def SetPlatformEnvAfterTarget(self):
        return 0

    def PlatformPostBuild(self):
        return 0

    def PlatformPreBuild(self):
        return 0

    def PlatformGatedBuildShouldHappen(self):
        return False

    def ComputeVersionValue(self):
        return 0

    def ValidateVersionValue(self):
        return 0

    def PlatformFlashImage(self):
        raise Exception("Flashing not supported")

Build Settings grouped with UefiBuilder, other settings separate

class SettingsManager(UpdateSettingsManager, SetupSettingsManager):
    def __init__(self):
        SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
        self.WORKSPACE_PATH = os.path.dirname(os.path.dirname(SCRIPT_PATH))
        self.PRODUCTION_SCOPE = ('production', )
        self.BASE_SCOPE = ('imxfamily', 'imx8')
        self.production = None

    def GetProjectScope(self):
        ''' get scope '''
        SCOPE = self.BASE_SCOPE
        if self.production:
            SCOPE += self.PRODUCTION_SCOPE
        return SCOPE

    def GetWorkspaceRoot(self):
        ''' get WorkspacePath '''
        return self.WORKSPACE_PATH

    def GetPackagesPath(self):
        ''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''
        return ['MU_BASECORE','Silicon/ARM/NXP', 'Common/MU','Common/MU_TIANO', 'Common/MU_OEM_SAMPLE','Silicon/ARM/MU_TIANO']

    def GetRequiredSubmodules(self):
        ''' return iterable containing RequiredSubmodule objects.
        If no RequiredSubmodules return an empty iterable
        '''
        return [RequiredSubmodule('MU_BASECORE'),
                RequiredSubmodule('Silicon/ARM/NXP'),
                RequiredSubmodule('Common/MU'),
                RequiredSubmodule('Common/MU_TIANO'),
                RequiredSubmodule('Common/MU_OEM_SAMPLE'),
                RequiredSubmodule('Silicon/ARM/MU_TIANO')]

    def AddCommandLineOptions(self, parserObj):
        ''' Add command line options to the argparser '''
        parserObj.add_argument('--production', dest="production", action='store_true', default=False)

    def RetrieveCommandLineOptions(self, args):
        '''  Retrieve command line options from the argparser '''
        self.production = args.production

class PlatformBuilder(UefiBuilder, BuildSettingsManager):
    def __init__(self):
        UefiBuilder.__init__(self)
        SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
        self.WORKSPACE_PATH = os.path.dirname(os.path.dirname(SCRIPT_PATH))
        self.PRODUCTION_SCOPE = ('production', )
        self.BASE_SCOPE = ('imxfamily', 'imx8')
        MODULE_PKGS = ['MU_BASECORE','Silicon/ARM/NXP', 'Common/MU','Common/MU_TIANO', 'Common/MU_OEM_SAMPLE','Silicon/ARM/MU_TIANO']
        self.MODULE_PKG_PATHS = os.pathsep.join(os.path.join(self.WORKSPACE_PATH, pkg_name) for pkg_name in MODULE_PKGS)
        self.production = None

    def GetProjectScope(self):
        ''' return tuple containing scopes that should be active for this process '''
        SCOPE = self.BASE_SCOPE
        if self.production:
            SCOPE += self.PRODUCTION_SCOPE
        return SCOPE

    def GetWorkspaceRoot(self):
        ''' get WorkspacePath '''
        return self.WORKSPACE_PATH

    def GetPackagesPath(self):
        ''' Return a list of workspace relative paths that should be mapped as edk2 PackagesPath '''
        return ['MU_BASECORE','Silicon/ARM/NXP', 'Common/MU','Common/MU_TIANO', 'Common/MU_OEM_SAMPLE','Silicon/ARM/MU_TIANO']

    def AddCommandLineOptions(self, parserObj):
        ''' Add command line options to the argparser '''
        UefiBuilder.AddCommandLineOptions(self, parserObj)
        parserObj.add_argument('--production', dest="production", action='store_true', default=False)

    def RetrieveCommandLineOptions(self, args):
        '''  Retrieve command line options from the argparser '''
        UefiBuilder.RetrieveCommandLineOptions(self, args)
        self.production = args.production

A note on multi-inheritance

If you implement several classes, you might wonder how the system knows which AddCommandLineOptions to call when it's doing update vs setup? The answer is that it doesn't. It's a classic case of the diamond problem and python's answer for this is the MRO. Currently, our advice is to not call super into the settings classes in this package. You can call super to your classes that you have implemented that subclass pytool settings classes.