/** @file | |
This file is ANT task FpdParserTask. | |
FpdParserTask is used to parse FPD (Framework Platform Description) and generate | |
build.out.xml. It is for Package or Platform build use. | |
Copyright (c) 2006, Intel Corporation | |
All rights reserved. This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
package org.tianocore.build.fpd; | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.LinkedHashMap; | |
import java.util.LinkedHashSet; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.Vector; | |
import org.apache.tools.ant.BuildException; | |
import org.apache.tools.ant.Task; | |
import org.apache.tools.ant.taskdefs.Ant; | |
import org.apache.tools.ant.taskdefs.Property; | |
import org.apache.xmlbeans.XmlException; | |
import org.apache.xmlbeans.XmlObject; | |
import org.tianocore.common.definitions.EdkDefinitions; | |
import org.tianocore.common.definitions.ToolDefinitions; | |
import org.tianocore.common.exception.EdkException; | |
import org.tianocore.common.logger.EdkLog; | |
import org.tianocore.build.FrameworkBuildTask; | |
import org.tianocore.build.global.GlobalData; | |
import org.tianocore.build.global.OutputManager; | |
import org.tianocore.build.global.SurfaceAreaQuery; | |
import org.tianocore.build.id.FpdModuleIdentification; | |
import org.tianocore.build.id.ModuleIdentification; | |
import org.tianocore.build.id.PackageIdentification; | |
import org.tianocore.build.id.PlatformIdentification; | |
import org.tianocore.build.pcd.action.PlatformPcdPreprocessActionForBuilding; | |
import org.tianocore.build.toolchain.ToolChainElement; | |
import org.tianocore.build.toolchain.ToolChainMap; | |
import org.tianocore.build.toolchain.ToolChainInfo; | |
import org.w3c.dom.NamedNodeMap; | |
import org.w3c.dom.Node; | |
import org.w3c.dom.NodeList; | |
/** | |
<code>FpdParserTask</code> is an ANT task. The main function is parsing Framework | |
Platform Descritpion (FPD) XML file and generating its ANT build script for | |
corresponding platform. | |
<p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR | |
and BUILD_DIR. </p> | |
<p>The task generates ${PLATFORM}_build.xml file which will be called by top level | |
build.xml. The task also generate Fv.inf files (File is for Tool GenFvImage). </p> | |
<p>FpdParserTask task stores all FPD information to GlobalData. And parse | |
tools definition file to set up compiler options for different Target and | |
different ToolChainTag. </p> | |
<p>The method parseFpdFile is also prepared for single module build. </p> | |
@since GenBuild 1.0 | |
**/ | |
public class FpdParserTask extends Task { | |
/// | |
/// Be used to ensure Global data will be initialized only once. | |
/// | |
private static boolean parsed = false; | |
private File fpdFile = null; | |
PlatformIdentification platformId; | |
private String type; | |
/// | |
/// Mapping from modules identification to out put file name | |
/// | |
Map<FpdModuleIdentification, String> outfiles = new LinkedHashMap<FpdModuleIdentification, String>(); | |
/// | |
/// Mapping from FV name to its modules | |
/// | |
Map<String, Set<FpdModuleIdentification>> fvs = new HashMap<String, Set<FpdModuleIdentification>>(); | |
/// | |
/// Mapping from FV apriori file to its type (PEI or DXE) | |
/// | |
Map<String, String> aprioriType = new HashMap<String, String>(); | |
/// | |
/// FpdParserTask can specify some ANT properties. | |
/// | |
private Vector<Property> properties = new Vector<Property>(); | |
SurfaceAreaQuery saq = null; | |
boolean isUnified = true; | |
public static String PEI_APRIORI_GUID = "1b45cc0a-156a-428a-af62-49864da0e6e6"; | |
public static String DXE_APRIORI_GUID = "fc510ee7-ffdc-11d4-bd41-0080c73c8881"; | |
/** | |
Public construct method. It is necessary for ANT task. | |
**/ | |
public FpdParserTask() { | |
} | |
/** | |
ANT task's entry method. The main steps is described as following: | |
<ul> | |
<li>Initialize global information (Framework DB, SPD files and all MSA files | |
listed in SPD). This step will execute only once in whole build process;</li> | |
<li>Parse specified FPD file; </li> | |
<li>Generate FV.inf files; </li> | |
<li>Generate PlatformName_build.xml file for Flatform build; </li> | |
<li>Collect PCD information. </li> | |
</ul> | |
@throws BuildException | |
Surface area is not valid. | |
**/ | |
public void execute() throws BuildException { | |
this.setTaskName("FpdParser"); | |
// | |
// Parse FPD file | |
// | |
parseFpdFile(); | |
// | |
// Prepare BUILD_DIR | |
// | |
isUnified = OutputManager.getInstance().prepareBuildDir(getProject()); | |
String buildDir = getProject().getProperty("BUILD_DIR"); | |
// | |
// For every Target and ToolChain | |
// | |
String[] targetList = GlobalData.getToolChainInfo().getTargets(); | |
for (int i = 0; i < targetList.length; i++) { | |
String[] toolchainList = GlobalData.getToolChainInfo().getTagnames(); | |
for(int j = 0; j < toolchainList.length; j++) { | |
// | |
// Prepare FV_DIR | |
// | |
String ffsCommonDir = buildDir + File.separatorChar | |
+ targetList[i] + "_" | |
+ toolchainList[j]; | |
File fvDir = new File(ffsCommonDir + File.separatorChar + "FV"); | |
fvDir.mkdirs(); | |
getProject().setProperty("FV_DIR", fvDir.getPath().replaceAll("(\\\\)", "/")); | |
// | |
// Gen Fv.inf files | |
// | |
genFvInfFiles(ffsCommonDir); | |
} | |
} | |
// | |
// Gen build.xml | |
// | |
String platformBuildFile = buildDir + File.separatorChar + platformId.getName() + "_build.xml"; | |
PlatformBuildFileGenerator fileGenerator = new PlatformBuildFileGenerator(getProject(), outfiles, fvs, isUnified, saq, platformBuildFile, aprioriType); | |
fileGenerator.genBuildFile(); | |
// | |
// Ant call ${PLATFORM}_build.xml | |
// | |
Ant ant = new Ant(); | |
ant.setProject(getProject()); | |
ant.setAntfile(platformBuildFile); | |
ant.setTarget(type); | |
ant.setInheritAll(true); | |
ant.init(); | |
ant.execute(); | |
} | |
/** | |
Generate Fv.inf files. The Fv.inf file is composed with four | |
parts: Options, Attributes, Components and Files. The Fv.inf files | |
will be under FV_DIR. | |
@throws BuildException | |
File write FV.inf files error. | |
**/ | |
void genFvInfFiles(String ffsCommonDir) throws BuildException { | |
String[] validFv = saq.getFpdValidImageNames(); | |
for (int i = 0; i < validFv.length; i++) { | |
// | |
// Get all global variables from FPD and set them to properties | |
// | |
String[][] globalVariables = saq.getFpdGlobalVariable(); | |
for (int j = 0; j < globalVariables.length; j++) { | |
getProject().setProperty(globalVariables[j][0], globalVariables[j][1]); | |
} | |
getProject().setProperty("FV_FILENAME", validFv[i]); | |
File fvFile = new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File.separatorChar + validFv[i] + ".inf")); | |
if (fvFile.exists() && (fvFile.lastModified() >= fpdFile.lastModified())) { | |
// | |
// don't re-generate FV.inf if fpd has not been changed | |
// | |
continue; | |
} | |
fvFile.getParentFile().mkdirs(); | |
try { | |
FileWriter fw = new FileWriter(fvFile); | |
BufferedWriter bw = new BufferedWriter(fw); | |
// | |
// Options | |
// | |
String[][] options = saq.getFpdOptions(validFv[i]); | |
if (options.length > 0) { | |
bw.write("[options]"); | |
bw.newLine(); | |
for (int j = 0; j < options.length; j++) { | |
StringBuffer str = new StringBuffer(100); | |
str.append(options[j][0]); | |
while (str.length() < 40) { | |
str.append(' '); | |
} | |
str.append("= "); | |
str.append(options[j][1]); | |
bw.write(getProject().replaceProperties(str.toString())); | |
bw.newLine(); | |
} | |
bw.newLine(); | |
} | |
// | |
// Attributes; | |
// | |
String[][] attributes = saq.getFpdAttributes(validFv[i]); | |
if (attributes.length > 0) { | |
bw.write("[attributes]"); | |
bw.newLine(); | |
for (int j = 0; j < attributes.length; j++) { | |
StringBuffer str = new StringBuffer(100); | |
str.append(attributes[j][0]); | |
while (str.length() < 40) { | |
str.append(' '); | |
} | |
str.append("= "); | |
str.append(attributes[j][1]); | |
bw.write(getProject().replaceProperties(str.toString())); | |
bw.newLine(); | |
} | |
bw.newLine(); | |
} | |
// | |
// Components | |
// | |
String[][] components = saq.getFpdComponents(validFv[i]); | |
if (components.length > 0) { | |
bw.write("[components]"); | |
bw.newLine(); | |
for (int j = 0; j < components.length; j++) { | |
StringBuffer str = new StringBuffer(100); | |
str.append(components[j][0]); | |
while (str.length() < 40) { | |
str.append(' '); | |
} | |
str.append("= "); | |
str.append(components[j][1]); | |
bw.write(getProject().replaceProperties(str.toString())); | |
bw.newLine(); | |
} | |
bw.newLine(); | |
} | |
// | |
// Files | |
// | |
Set<FpdModuleIdentification> moduleSeqSet = getModuleSequenceForFv(validFv[i]); | |
Set<FpdModuleIdentification> filesSet = fvs.get(validFv[i]); | |
FpdModuleIdentification[] files = null; | |
if (moduleSeqSet == null) { | |
if (filesSet != null) { | |
files = filesSet.toArray(new FpdModuleIdentification[filesSet.size()]); | |
} | |
} else if (filesSet == null) { | |
if (moduleSeqSet.size() != 0) { | |
throw new BuildException("Can not find any modules belongs to FV[" + validFv[i] + "], but listed some in BuildOptions.UserExtensions[@UserID='IMAGES' @Identifier='1']"); | |
} | |
} else { | |
// | |
// if moduleSeqSet and filesSet is inconsistent, report error | |
// | |
if(moduleSeqSet.size() != filesSet.size()){ | |
throw new BuildException("Modules for FV[" + validFv[i] + "] defined in FrameworkModules and in BuildOptions.UserExtensions[@UserID='IMAGES' @Identifier='1'] are inconsistent. "); | |
} else { | |
// | |
// whether all modules in moduleSeqSet listed in filesSet | |
// | |
Iterator<FpdModuleIdentification> iter = moduleSeqSet.iterator(); | |
while (iter.hasNext()) { | |
FpdModuleIdentification item = iter.next(); | |
if (!filesSet.contains(item)) { | |
throw new BuildException("Can not find " + item + " belongs to FV[" + validFv[i] + "]"); | |
} | |
} | |
} | |
files = moduleSeqSet.toArray(new FpdModuleIdentification[moduleSeqSet.size()]); | |
} | |
if (files != null) { | |
bw.write("[files]"); | |
bw.newLine(); | |
Set<FpdModuleIdentification> modules = null; | |
if ( (modules = getPeiApriori(validFv[i])) != null) { | |
// | |
// Special GUID - validFv[i].FFS | |
// | |
String str = ffsCommonDir + File.separatorChar + "FV" + File.separatorChar + PEI_APRIORI_GUID + "-" + validFv[i] + ".FFS"; | |
bw.write(getProject().replaceProperties("EFI_FILE_NAME = " + str)); | |
bw.newLine(); | |
File aprioriFile = new File(getProject().getProperty("FV_DIR") + File.separatorChar + validFv[i] + ".apr"); | |
aprioriType.put(validFv[i], PEI_APRIORI_GUID); | |
genAprioriFile(modules, aprioriFile); | |
} else if((modules = getDxeApriori(validFv[i])) != null) { | |
// | |
// Special GUID - validFv[i].FFS | |
// | |
String str = ffsCommonDir + File.separatorChar + "FV" + File.separatorChar + DXE_APRIORI_GUID + "-" + validFv[i] + ".FFS"; | |
bw.write(getProject().replaceProperties("EFI_FILE_NAME = " + str)); | |
bw.newLine(); | |
File aprioriFile = new File(getProject().getProperty("FV_DIR") + File.separatorChar + validFv[i] + ".apr"); | |
aprioriType.put(validFv[i], DXE_APRIORI_GUID); | |
genAprioriFile(modules, aprioriFile); | |
} | |
for (int j = 0; j < files.length; j++) { | |
String str = ffsCommonDir + File.separatorChar + outfiles.get(files[j]); | |
bw.write(getProject().replaceProperties("EFI_FILE_NAME = " + str)); | |
bw.newLine(); | |
} | |
} | |
bw.flush(); | |
bw.close(); | |
fw.close(); | |
} catch (IOException ex) { | |
BuildException buildException = new BuildException("Generation of the FV file [" + fvFile.getPath() + "] failed!\n" + ex.getMessage()); | |
buildException.setStackTrace(ex.getStackTrace()); | |
throw buildException; | |
} catch (EdkException ex) { | |
BuildException buildException = new BuildException("Generation of the FV file [" + fvFile.getPath() + "] failed!\n" + ex.getMessage()); | |
buildException.setStackTrace(ex.getStackTrace()); | |
throw buildException; | |
} | |
} | |
} | |
/** | |
This method is used for Single Module Build. | |
@throws BuildException | |
FPD file is not valid. | |
**/ | |
public void parseFpdFile(File fpdFile) throws BuildException, EdkException { | |
this.fpdFile = fpdFile; | |
parseFpdFile(); | |
// | |
// Call Platform_build.xml prebuild firstly in stand-alone build | |
// Prepare BUILD_DIR | |
// | |
isUnified = OutputManager.getInstance().prepareBuildDir(getProject()); | |
String buildDir = getProject().getProperty("BUILD_DIR"); | |
// | |
// For every Target and ToolChain | |
// | |
String[] targetList = GlobalData.getToolChainInfo().getTargets(); | |
for (int i = 0; i < targetList.length; i++) { | |
String[] toolchainList = GlobalData.getToolChainInfo().getTagnames(); | |
for(int j = 0; j < toolchainList.length; j++) { | |
// | |
// Prepare FV_DIR | |
// | |
String ffsCommonDir = buildDir + File.separatorChar | |
+ targetList[i] + "_" | |
+ toolchainList[j]; | |
File fvDir = new File(ffsCommonDir + File.separatorChar + "FV"); | |
fvDir.mkdirs(); | |
} | |
} | |
String platformBuildFile = buildDir + File.separatorChar + platformId.getName() + "_build.xml"; | |
PlatformBuildFileGenerator fileGenerator = new PlatformBuildFileGenerator(getProject(), outfiles, fvs, isUnified, saq, platformBuildFile, aprioriType); | |
fileGenerator.genBuildFile(); | |
Ant ant = new Ant(); | |
ant.setProject(getProject()); | |
ant.setAntfile(platformBuildFile); | |
ant.setTarget("prebuild"); | |
ant.setInheritAll(true); | |
ant.init(); | |
ant.execute(); | |
} | |
/** | |
Parse FPD file. | |
@throws BuildException | |
FPD file is not valid. | |
**/ | |
void parseFpdFile() throws BuildException { | |
try { | |
XmlObject doc = XmlObject.Factory.parse(fpdFile); | |
if (!doc.validate()) { | |
throw new BuildException("Platform Surface Area file [" + fpdFile.getPath() + "] format is invalid!"); | |
} | |
Map<String, XmlObject> map = new HashMap<String, XmlObject>(); | |
map.put("PlatformSurfaceArea", doc); | |
saq = new SurfaceAreaQuery(map); | |
// | |
// Initialize | |
// | |
platformId = saq.getFpdHeader(); | |
platformId.setFpdFile(fpdFile); | |
getProject().setProperty("PLATFORM", platformId.getName()); | |
getProject().setProperty("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/")); | |
getProject().setProperty("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/")); | |
getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/")); | |
if( !FrameworkBuildTask.multithread) { | |
FrameworkBuildTask.originalProperties.put("PLATFORM", platformId.getName()); | |
FrameworkBuildTask.originalProperties.put("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/")); | |
FrameworkBuildTask.originalProperties.put("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/")); | |
FrameworkBuildTask.originalProperties.put("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/")); | |
} | |
// | |
// Build mode. User-defined output dir. | |
// | |
String buildMode = saq.getFpdIntermediateDirectories(); | |
String userDefinedOutputDir = saq.getFpdOutputDirectory(); | |
OutputManager.getInstance().setup(userDefinedOutputDir, buildMode); | |
// | |
// TBD. Deal PCD and BuildOption related Info | |
// | |
GlobalData.setFpdBuildOptions(saq.getFpdBuildOptions()); | |
GlobalData.setToolChainPlatformInfo(saq.getFpdToolChainInfo()); | |
// | |
// Parse all list modules SA | |
// | |
parseModuleSAFiles(); | |
// | |
// TBD. Deal PCD and BuildOption related Info | |
// | |
parseToolChainFamilyOptions(); | |
parseToolChainOptions(); | |
// | |
// check if the tool chain is valid or not | |
// | |
checkToolChain(); | |
saq.push(map); | |
// | |
// Pcd Collection. Call CollectPCDAction to collect pcd info. | |
// | |
if (!parsed) { | |
PlatformPcdPreprocessActionForBuilding ca = new PlatformPcdPreprocessActionForBuilding(); | |
ca.perform(platformId.getFpdFile().getPath()); | |
} | |
} catch (IOException ex) { | |
BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage()); | |
buildException.setStackTrace(ex.getStackTrace()); | |
throw buildException; | |
} catch (XmlException ex) { | |
BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage()); | |
buildException.setStackTrace(ex.getStackTrace()); | |
throw buildException; | |
} catch (EdkException ex) { | |
BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage()); | |
buildException.setStackTrace(ex.getStackTrace()); | |
throw buildException; | |
} | |
if (!parsed) { | |
parsed = true; | |
} | |
} | |
/** | |
Parse all modules listed in FPD file. | |
**/ | |
void parseModuleSAFiles() throws EdkException{ | |
Map<FpdModuleIdentification, Map<String, XmlObject>> moduleSAs = saq.getFpdModules(); | |
// | |
// For every Module lists in FPD file. | |
// | |
Set<FpdModuleIdentification> keys = moduleSAs.keySet(); | |
Iterator iter = keys.iterator(); | |
while (iter.hasNext()) { | |
FpdModuleIdentification fpdModuleId = (FpdModuleIdentification) iter.next(); | |
// | |
// Judge if Module is existed? | |
// TBD | |
GlobalData.registerFpdModuleSA(fpdModuleId, moduleSAs.get(fpdModuleId)); | |
// | |
// Put fpdModuleId to the corresponding FV | |
// | |
saq.push(GlobalData.getDoc(fpdModuleId)); | |
String fvBinding = saq.getModuleFvBindingKeyword(); | |
fpdModuleId.setFvBinding(fvBinding); | |
updateFvs(fvBinding, fpdModuleId); | |
// | |
// Prepare for out put file name | |
// | |
ModuleIdentification moduleId = fpdModuleId.getModule(); | |
String baseName = saq.getModuleOutputFileBasename(); | |
if (baseName == null) { | |
baseName = moduleId.getName(); | |
} | |
outfiles.put(fpdModuleId, fpdModuleId.getArch() + File.separatorChar | |
+ moduleId.getGuid() + "-" + baseName | |
+ getSuffix(moduleId.getModuleType())); | |
// | |
// parse module build options, if any | |
// | |
GlobalData.addModuleToolChainOption(fpdModuleId, parseModuleBuildOptions(false)); | |
GlobalData.addModuleToolChainFamilyOption(fpdModuleId, parseModuleBuildOptions(true)); | |
// | |
// parse MSA build options | |
// | |
GlobalData.addMsaBuildOption(moduleId, parseMsaBuildOptions(false)); | |
GlobalData.addMsaFamilyBuildOption(moduleId, parseMsaBuildOptions(true)); | |
ModuleIdentification[] libraryInstances = saq.getLibraryInstance(null); | |
for (int i = 0; i < libraryInstances.length; i++) { | |
saq.push(GlobalData.getDoc(libraryInstances[i], fpdModuleId.getArch())); | |
GlobalData.addMsaBuildOption(libraryInstances[i], parseMsaBuildOptions(false)); | |
GlobalData.addMsaFamilyBuildOption(libraryInstances[i], parseMsaBuildOptions(true)); | |
saq.pop(); | |
} | |
saq.pop(); | |
} | |
} | |
ToolChainMap parseModuleBuildOptions(boolean toolChainFamilyFlag) throws EdkException { | |
String[][] options = saq.getModuleBuildOptions(toolChainFamilyFlag); | |
if (options == null || options.length == 0) { | |
return new ToolChainMap(); | |
} | |
return parseOptions(options); | |
} | |
private ToolChainMap parsePlatformBuildOptions(boolean toolChainFamilyFlag) throws EdkException { | |
String[][] options = saq.getPlatformBuildOptions(toolChainFamilyFlag); | |
if (options == null || options.length == 0) { | |
return new ToolChainMap(); | |
} | |
return parseOptions(options); | |
} | |
ToolChainMap parseMsaBuildOptions(boolean toolChainFamilyFlag) throws EdkException { | |
String[][] options = saq.getMsaBuildOptions(toolChainFamilyFlag); | |
if (options == null || options.length == 0) { | |
return new ToolChainMap(); | |
} | |
return parseOptions(options); | |
} | |
private ToolChainMap parseOptions(String[][] options) throws EdkException { | |
ToolChainMap map = new ToolChainMap(); | |
int flagIndex = ToolChainElement.ATTRIBUTE.value; | |
for (int i = 0; i < options.length; ++i) { | |
String flagString = options[i][flagIndex]; | |
if (flagString == null) { | |
flagString = ""; | |
} | |
options[i][flagIndex] = ToolDefinitions.TOOLS_DEF_ATTRIBUTE_FLAGS; | |
map.put(options[i], flagString.trim()); | |
} | |
return map; | |
} | |
private void parseToolChainFamilyOptions() throws EdkException { | |
GlobalData.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true)); | |
} | |
private void parseToolChainOptions() throws EdkException { | |
GlobalData.setPlatformToolChainOption(parsePlatformBuildOptions(false)); | |
} | |
/** | |
Add the current module to corresponding FV. | |
@param fvName current FV name | |
@param moduleName current module identification | |
**/ | |
void updateFvs(String fvName, FpdModuleIdentification fpdModuleId) { | |
if (fvName == null || fvName.trim().length() == 0) { | |
fvName = "NULL"; | |
} | |
String[] fvNameArray = fvName.split("[, \t]+"); | |
for (int i = 0; i < fvNameArray.length; i++) { | |
// | |
// Put module to corresponding fvName | |
// | |
if (fvs.containsKey(fvNameArray[i])) { | |
Set<FpdModuleIdentification> set = fvs.get(fvNameArray[i]); | |
set.add(fpdModuleId); | |
} else { | |
Set<FpdModuleIdentification> set = new LinkedHashSet<FpdModuleIdentification>(); | |
set.add(fpdModuleId); | |
fvs.put(fvNameArray[i], set); | |
} | |
} | |
} | |
/** | |
Get the suffix based on module type. Current relationship are listed: | |
<pre> | |
<b>ModuleType</b> <b>Suffix</b> | |
BASE .FFS | |
SEC .SEC | |
PEI_CORE .PEI | |
PEIM .PEI | |
DXE_CORE .DXE | |
DXE_DRIVER .DXE | |
DXE_RUNTIME_DRIVER .DXE | |
DXE_SAL_DRIVER .DXE | |
DXE_SMM_DRIVER .DXE | |
TOOL .FFS | |
UEFI_DRIVER .DXE | |
UEFI_APPLICATION .APP | |
USER_DEFINED .FFS | |
</pre> | |
@param moduleType module type | |
@return | |
@throws BuildException | |
If module type is null | |
**/ | |
public static String getSuffix(String moduleType) throws BuildException { | |
if (moduleType == null) { | |
throw new BuildException("Module type is not specified."); | |
} | |
String[][] suffix = EdkDefinitions.ModuleTypeExtensions; | |
for (int i = 0; i < suffix.length; i++) { | |
if (suffix[i][0].equalsIgnoreCase(moduleType)) { | |
return suffix[i][1]; | |
} | |
} | |
// | |
// Default is '.FFS' | |
// | |
return ".FFS"; | |
} | |
/** | |
Add a property. | |
@param p property | |
**/ | |
public void addProperty(Property p) { | |
properties.addElement(p); | |
} | |
public void setFpdFile(File fpdFile) { | |
this.fpdFile = fpdFile; | |
} | |
public void setType(String type) { | |
this.type = type; | |
} | |
public String getAllArchForModule(ModuleIdentification moduleId) { | |
String archs = ""; | |
Iterator<FpdModuleIdentification> iter = outfiles.keySet().iterator(); | |
while (iter.hasNext()) { | |
FpdModuleIdentification fpdModuleId = iter.next(); | |
if (fpdModuleId.getModule().equals(moduleId)) { | |
archs += fpdModuleId.getArch() + " "; | |
} | |
} | |
return archs; | |
} | |
private void genAprioriFile(Set<FpdModuleIdentification> modules, File file) { | |
try { | |
FileWriter fw = new FileWriter(file); | |
BufferedWriter bw = new BufferedWriter(fw); | |
Iterator<FpdModuleIdentification> iter = modules.iterator(); | |
while(iter.hasNext()) { | |
bw.write(iter.next().getModule().getGuid()); | |
bw.newLine(); | |
} | |
bw.flush(); | |
bw.close(); | |
fw.close(); | |
} catch (IOException ex) { | |
BuildException buildException = new BuildException("Generation of the Apriori file [" + file.getPath() + "] failed!\n" + ex.getMessage()); | |
buildException.setStackTrace(ex.getStackTrace()); | |
throw buildException; | |
} | |
} | |
private Set<FpdModuleIdentification> getPeiApriori(String fvName) throws EdkException { | |
Node node = saq.getPeiApriori(fvName); | |
Set<FpdModuleIdentification> result = new LinkedHashSet<FpdModuleIdentification>(); | |
if (node == null) { | |
return null; | |
} | |
NodeList childNodes = node.getChildNodes(); | |
for (int i = 0; i < childNodes.getLength(); i++) { | |
Node childItem = childNodes.item(i); | |
if (childItem.getNodeType() == Node.ELEMENT_NODE) { | |
// | |
// Find child elements "IncludeModules" | |
// | |
if (childItem.getNodeName().compareTo("IncludeModules") == 0) { | |
// | |
// result will be updated | |
// | |
processNodes(childItem, result); | |
} else if (childItem.getNodeName().compareTo("FvName") == 0) { | |
} else if (childItem.getNodeName().compareTo("InfFileName") == 0) { | |
} else { | |
// | |
// Report Warning | |
// | |
EdkLog.log(this, EdkLog.EDK_WARNING, "Unrecognised element " + childItem.getNodeName() + " under FPD.BuildOptions.UserExtensions[UserID='APRIORI' Identifier='0']"); | |
} | |
} | |
} | |
return result; | |
} | |
private Set<FpdModuleIdentification> getDxeApriori(String fvName) throws EdkException { | |
Node node = saq.getDxeApriori(fvName); | |
Set<FpdModuleIdentification> result = new LinkedHashSet<FpdModuleIdentification>(); | |
if (node == null) { | |
return null; | |
} | |
NodeList childNodes = node.getChildNodes(); | |
for (int i = 0; i < childNodes.getLength(); i++) { | |
Node childItem = childNodes.item(i); | |
if (childItem.getNodeType() == Node.ELEMENT_NODE) { | |
// | |
// Find child elements "IncludeModules" | |
// | |
if (childItem.getNodeName().compareTo("IncludeModules") == 0) { | |
// | |
// result will be updated | |
// | |
processNodes(childItem, result); | |
} else if (childItem.getNodeName().compareTo("FvName") == 0) { | |
} else if (childItem.getNodeName().compareTo("InfFileName") == 0) { | |
} else { | |
// | |
// Report Warning | |
// | |
EdkLog.log(this, EdkLog.EDK_WARNING, "Unrecognised element " + childItem.getNodeName() + " under FPD.BuildOptions.UserExtensions[UserID='APRIORI' Identifier='1']"); | |
} | |
} | |
} | |
return result; | |
} | |
private Set<FpdModuleIdentification> getModuleSequenceForFv(String fvName) throws EdkException { | |
Node node = saq.getFpdModuleSequence(fvName); | |
Set<FpdModuleIdentification> result = new LinkedHashSet<FpdModuleIdentification>(); | |
if ( node == null) { | |
EdkLog.log(this, EdkLog.EDK_WARNING, "FV[" + fvName + "] does not specify module sequence in FPD. Assuming present sequence as default sequence in FV. "); | |
return null; | |
} else { | |
NodeList childNodes = node.getChildNodes(); | |
for (int i = 0; i < childNodes.getLength(); i++) { | |
Node childItem = childNodes.item(i); | |
if (childItem.getNodeType() == Node.ELEMENT_NODE) { | |
// | |
// Find child elements "IncludeModules" | |
// | |
if (childItem.getNodeName().compareTo("IncludeModules") == 0) { | |
// | |
// result will be updated | |
// | |
processNodes(childItem, result); | |
} else if (childItem.getNodeName().compareTo("FvName") == 0) { | |
} else if (childItem.getNodeName().compareTo("InfFileName") == 0) { | |
} else { | |
// | |
// Report Warning | |
// | |
EdkLog.log(this, EdkLog.EDK_WARNING, "Unrecognised element " + childItem.getNodeName() + " under FPD.BuildOptions.UserExtensions[UserID='IMAGES' Identifier='1']"); | |
} | |
} | |
} | |
} | |
return result; | |
} | |
private void processNodes(Node node, Set<FpdModuleIdentification> result) throws EdkException { | |
// | |
// Found out all elements "Module" | |
// | |
NodeList childNodes = node.getChildNodes(); | |
for (int j = 0; j < childNodes.getLength(); j++) { | |
Node childItem = childNodes.item(j); | |
if (childItem.getNodeType() == Node.ELEMENT_NODE) { | |
if (childItem.getNodeName().compareTo("Module") == 0) { | |
String moduleGuid = null; | |
String moduleVersion = null; | |
String packageGuid = null; | |
String packageVersion = null; | |
String arch = null; | |
NamedNodeMap attr = childItem.getAttributes(); | |
for (int i = 0; i < attr.getLength(); i++) { | |
Node attrItem = attr.item(i); | |
if (attrItem.getNodeName().compareTo("ModuleGuid") == 0) { | |
moduleGuid = attrItem.getNodeValue(); | |
} else if (attrItem.getNodeName().compareTo("ModuleVersion") == 0) { | |
moduleVersion = attrItem.getNodeValue(); | |
} else if (attrItem.getNodeName().compareTo("PackageGuid") == 0) { | |
packageGuid = attrItem.getNodeValue(); | |
} else if (attrItem.getNodeName().compareTo("PackageVersion") == 0) { | |
packageVersion = attrItem.getNodeValue(); | |
} else if (attrItem.getNodeName().compareTo("Arch") == 0) { | |
arch = attrItem.getNodeValue(); | |
} else { | |
// | |
// Report warning | |
// | |
EdkLog.log(this, EdkLog.EDK_WARNING, "Unrecognised attribute " + attrItem.getNodeName() + " under FPD.BuildOptions.UserExtensions[UserID='IMAGES' Identifier='1'].IncludeModules.Module"); | |
} | |
} | |
PackageIdentification packageId = new PackageIdentification(packageGuid, packageVersion); | |
GlobalData.refreshPackageIdentification(packageId); | |
ModuleIdentification moduleId = new ModuleIdentification(moduleGuid, moduleVersion); | |
moduleId.setPackage(packageId); | |
GlobalData.refreshModuleIdentification(moduleId); | |
if (arch == null) { | |
throw new EdkException("Attribute [Arch] is required for element FPD.BuildOptions.UserExtensions[UserID='IMAGES' Identifier='1'].IncludeModules.Module. "); | |
} | |
result.add(new FpdModuleIdentification(moduleId, arch)); | |
} else { | |
// | |
// Report Warning | |
// | |
EdkLog.log(this, EdkLog.EDK_WARNING, "Unrecognised element " + childItem.getNodeName() + " under FPD.BuildOptions.UserExtensions[UserID='IMAGES' Identifier='1'].IncludeModules"); | |
} | |
} | |
} | |
} | |
private void checkToolChain() throws EdkException { | |
ToolChainInfo toolChainInfo = GlobalData.getToolChainInfo(); | |
if (toolChainInfo.getTargets().length == 0) { | |
throw new EdkException("No valid target found! "+ | |
"Please check the TARGET definition in Tools/Conf/target.txt, "+ | |
"or the <BuildTarget>, <BuildOptions> in the FPD file."); | |
} | |
if (toolChainInfo.getTagnames().length == 0) { | |
throw new EdkException("No valid tool chain found! "+ | |
"Please check the TOOL_CHAIN_TAG definition in Tools/Conf/target.txt, "+ | |
"or the <BuildOptions> in the FPD file."); | |
} | |
if (toolChainInfo.getArchs().length == 0) { | |
throw new EdkException("No valid architecture found! "+ | |
"Please check the TARGET_ARCH definition in Tools/Conf/target.txt, "+ | |
"or the <SupportedArchitectures>, <BuildOptions> in the FPD file."); | |
} | |
if (toolChainInfo.getCommands().length == 0) { | |
throw new EdkException("No valid COMMAND found! Please check the tool chain definitions "+ | |
"in Tools/Conf/tools_def.txt."); | |
} | |
} | |
} |