Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Multiple Config Environment Build Support #374

Merged
merged 4 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,29 @@ queries variable storage for any appropriately sized overrides to config knobs.

The platform must define `CONF_AUTOGEN_INCLUDE_PATH` in PlatformBuild.py. This is the absolute path that the autogenerated
header files will be placed under as such: `CONF_AUTOGEN_INCLUDE_PATH\Generated\Config*.h`. The UpdateConfigHdr.py
build plugin will create the `Generated` directory if it does not exist.
build plugin will create the `Generated` directory if it does not exist. If there are multiple environments being built
in one build, e.g. StandaloneMM and DXE environments with separate config, PlatformBuild.py may put a semicolon
delimited list of include paths here such as:

```python
self.env.SetValue("CONF_AUTOGEN_INCLUDE_PATH", "MyPkg/Include;MyPkg/Include/StandaloneMm", "Platform Defined")
```

This list must be the same length as the `MU_SCHEMA_FILE_NAME` and it will be processed in the same order; the first
schema file will get headers generated to the first include directory, etc.

The platform must define `MU_SCHEMA_DIR` and `MU_SCHEMA_FILE_NAME` in PlatformBuild.py. These are the directory
containing the XML configuration file and the file name of the XML configuration file, respectively. These are split
apart to allow the CI build to discover a test schema to validate this process.

`MU_SCHEMA_FILE_NAME` may have multiple schema files that are semicolon delimited if the build has multiple environments
being built at the same time, e.g. StandaloneMM and DXE. If so, `CONF_AUTOGEN_INCLUDE_PATH` must have the same number of
entries, see above. An example is:

```python
self.env.SetValue("MU_SCHEMA_FILE_NAME", "NonSecureConfig.xml;StMMConfig.xml", "Platform Defined")
```

### Autogenerated Header Files

There are four autogenerated headers and one standard structure definition header:
Expand Down
6 changes: 6 additions & 0 deletions SetupDataPkg/Docs/Profiles/Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ self.env.SetValue('CONF_PROFILE_PATHS',
)
```

If `MU_SCHEMA_FILE_NAME` has multiple entries (see
[Platform Integration Steps](../PlatformIntegration/PlatformIntegrationSteps.md)), then there may be a semicolon
delimited list of `CONF_PROFILE_PATHS`. `UpdateConfigHdr.py` will match these in the same order as the schema files,
i.e. `CONF_PROFILE_PATHS` first entry will be applied to the first entry of `MU_SCHEMA_FILE_NAME`. If there is no
corresponding entry, it will be assumed there is no profile override to that schema file.

Platform owners can develop a configuration profile for their use case. Following examples and the format provided in
the [ConfigurationFiles doc](../ConfigurationFiles/ConfigurationFiles.md), these owners can create an XML change file
describing the set of configuration variables and their values that are in the profile that differ from the generic
Expand Down
79 changes: 48 additions & 31 deletions SetupDataPkg/Plugins/UpdateConfigHdr/UpdateConfigHdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@ def do_pre_build(self, thebuilder):
"SetupDataPkg", "Test", "Include"
)

final_dir = thebuilder.env.GetValue("CONF_AUTOGEN_INCLUDE_PATH", default_generated_path)
# we can have a semicolon delimited list of include paths to generate to
dirs = thebuilder.env.GetValue("CONF_AUTOGEN_INCLUDE_PATH", default_generated_path).split(";")
os-d marked this conversation as resolved.
Show resolved Hide resolved
final_dirs = []

# Add Generated dir
final_dir = os.path.join(final_dir, "Generated")
for directory in dirs:
gen_dir = os.path.join(directory, "Generated")
final_dirs.append(gen_dir)

if not os.path.isdir(final_dir):
os.makedirs(final_dir)
if not os.path.isdir(gen_dir):
os.makedirs(gen_dir)

# Add generate routine here
cmd = thebuilder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
Expand All @@ -44,41 +48,54 @@ def do_pre_build(self, thebuilder):
logging.error("MU_SCHEMA_DIR not set")
return -1

schema_file_name = thebuilder.env.GetValue("MU_SCHEMA_FILE_NAME", "testschema.xml")
# This may be a semicolon delimited string
schema_file_names = thebuilder.env.GetValue("MU_SCHEMA_FILE_NAME", "testschema.xml").split(";")
schema_files = []

schema_file = thebuilder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(schema_dir, schema_file_name)
for name in schema_file_names:
file = thebuilder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(schema_dir, name)
schema_files.append(file)

if not os.path.isfile(schema_file):
logging.error(f"XML schema file \"{schema_file}\" specified is not found!!!")
return -1
if not os.path.isfile(file):
logging.error(f"XML schema file \"{file}\" specified is not found!!!")
return -1

# this is a space separated list of paths to CSV files describing the profiles for
# this is a semicolon delimited list of space separated lists of paths to CSV files describing the profiles for
# this platform. It is allowed to be empty if there are no profiles.
profile_paths = thebuilder.env.GetValue("CONF_PROFILE_PATHS", "")
# e.g.: "CONF_PATH_1 CONF_PATH_2 CONF_PATH3;CONF_PATH4 CONF_PATH5 CONF_PATH6;CONF_PATH7 CONF_PATH8 CONF_PATH9"
profile_path_list = thebuilder.env.GetValue("CONF_PROFILE_PATHS", "").split(";")

# this is a semicolon delimited list of comma separated 2 character profile names to pair with CSV files
# identifying the profiles. This field is optional.
profile_names = thebuilder.env.GetValue("CONF_PROFILE_NAMES", "").split(";")
profile_ids = thebuilder.env.GetValue("CONF_PROFILE_IDS", "").split(";")

# this is a comma separated 2 character profile names to pair with CSV files identifying
# the profiles. This field is optional.
profile_names = thebuilder.env.GetValue("CONF_PROFILE_NAMES", "")
profile_ids = thebuilder.env.GetValue("CONF_PROFILE_IDS", "")
if len(schema_files) != len(final_dirs):
logging.error("Differing number of items in CONF_AUTOGEN_INCLUDE_PATH and MU_SCHEMA_FILE_NAME!\
They must be the same")
return -1

params = ["generateheader_efi"]
for i in range(len(schema_files)):
params = ["generateheader_efi"]

params.append(schema_file)
params.append(schema_files[i])

params.append("ConfigClientGenerated.h")
params.append("ConfigServiceGenerated.h")
params.append("ConfigDataGenerated.h")
params.append("ConfigClientGenerated.h")
params.append("ConfigServiceGenerated.h")
params.append("ConfigDataGenerated.h")

if profile_paths != "":
params.append("ConfigProfilesGenerated.h")
params.append(profile_paths)
if len(profile_path_list) > i and profile_path_list[i] != "":
params.append("ConfigProfilesGenerated.h")
params.append(profile_path_list[i])

if profile_names != "":
params.append("-pn")
params.append(profile_names)
if profile_ids != "":
params.append("-pid")
params.append(profile_ids)
if len(profile_names) > i and profile_names[i] != "":
params.append("-pn")
params.append(profile_names[i])
if len(profile_ids) > i and profile_ids[i] != "":
params.append("-pid")
params.append(profile_ids[i])

ret = RunPythonScript(cmd, " ".join(params), workingdir=final_dir)
return ret
ret = RunPythonScript(cmd, " ".join(params), workingdir=final_dirs[i])
if ret != 0:
return ret
return 0
Loading