From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.115; helo=mga14.intel.com; envelope-from=bob.c.feng@intel.com; receiver=edk2-devel@lists.01.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 0CDE821190717 for ; Sun, 25 Nov 2018 21:28:29 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Nov 2018 21:28:28 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,280,1539673200"; d="scan'208";a="276823140" Received: from fmsmsx108.amr.corp.intel.com ([10.18.124.206]) by orsmga005.jf.intel.com with ESMTP; 25 Nov 2018 21:28:28 -0800 Received: from shsmsx103.ccr.corp.intel.com (10.239.4.69) by FMSMSX108.amr.corp.intel.com (10.18.124.206) with Microsoft SMTP Server (TLS) id 14.3.408.0; Sun, 25 Nov 2018 21:28:27 -0800 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.102]) by SHSMSX103.ccr.corp.intel.com ([169.254.4.161]) with mapi id 14.03.0415.000; Mon, 26 Nov 2018 13:28:25 +0800 From: "Feng, Bob C" To: "Zhao, ZhiqiangX" , "edk2-devel@lists.01.org" CC: "Gao, Liming" , "Carsey, Jaben" Thread-Topic: [PATCH V2] BaseTools: AutoGen and GenFds share the parser data. Thread-Index: AQHUgvrgXQ+hf88Kf0KciEJMDADyyKVhiskw Date: Mon, 26 Nov 2018 05:28:25 +0000 Message-ID: <08650203BA1BD64D8AD9B6D5D74A85D160001CC7@SHSMSX101.ccr.corp.intel.com> References: <20181123070445.7764-1-zhiqiangx.zhao@intel.com> In-Reply-To: <20181123070445.7764-1-zhiqiangx.zhao@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH V2] BaseTools: AutoGen and GenFds share the parser data. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Nov 2018 05:28:29 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Bob Feng -----Original Message----- From: Zhao, ZhiqiangX=20 Sent: Friday, November 23, 2018 3:05 PM To: edk2-devel@lists.01.org Cc: Zhao, ZhiqiangX ; Gao, Liming ; Carsey, Jaben ; Feng, Bob C Subject: [PATCH V2] BaseTools: AutoGen and GenFds share the parser data. V2: Extract the common part of new API and the original main() function into on= e function. V1: https://bugzilla.tianocore.org/show_bug.cgi?id=3D1288 Currently, AutoGen and GenFds run in different python interpreters. The par= ser are duplicated. This patch is going to create new API for GenFds and ha= ve the build to call that API instead of executing GenFds.py. As such, the = GenFds and build can share the parser data. This patch is expected to save the time of GenFds about 2~3 seconds. More details will be logged in BZ. This is the summary measure data generated from python cProfile for buildin= g Ovmf. Currently: 8379147 function calls (8135450 primitive calls) in 12.580 seconds After applying this patch: 3428712 function calls (3418881 primitive calls) in 8.944 seconds Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: ZhiqiangX Zhao Cc: Liming Gao Cc: Carsey Jaben Cc: Bob Feng --- BaseTools/Source/Python/AutoGen/AutoGen.py | 4 + BaseTools/Source/Python/GenFds/GenFds.py | 141 ++++++++++++++++++-------= ---- BaseTools/Source/Python/build/build.py | 6 +- 3 files changed, 94 insertions(+), 57 deletions(-) diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py b/BaseTools/Source/= Python/AutoGen/AutoGen.py index f3560bfc78..10ce7eb962 100644 --- a/BaseTools/Source/Python/AutoGen/AutoGen.py +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py @@ -935,6 +935,10 @@ class WorkspaceAutoGen(AutoGen): def GenFdsCommand(self): return (GenMake.TopLevelMakefile(self)._TEMPLATE_.Replace(GenMake.= TopLevelMakefile(self)._TemplateDict)).strip() =20 + @property + def GenFdsCommandDict(self): + return GenMake.TopLevelMakefile(self)._TemplateDict + ## Create makefile for the platform and modules in it # # @param CreateDepsMakeFile Flag indicating if the makefil= e for diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Py= thon/GenFds/GenFds.py index 0c8091b798..d24091c06c 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -35,7 +35,7 @@ from Common.Misc import DirCache, PathClass, GuidStructur= eStringToGuidString from Common.Misc import SaveFileOnChange, ClearDuplica= tedInf from Common.BuildVersion import gBUILD_VERSION from Common.Multipl= eWorkspace import MultipleWorkspace as mws -from Common.BuildToolError impo= rt FatalError, GENFDS_ERROR, CODE_ERROR, FORMAT_INVALID, RESOURCE_NOT_AVAIL= ABLE, FILE_NOT_FOUND, OPTION_MISSING, FORMAT_NOT_SUPPORTED,OPTION_VALUE_INV= ALID +from Common.BuildToolError import FatalError, GENFDS_ERROR, CODE_ERROR,=20 +FORMAT_INVALID, RESOURCE_NOT_AVAILABLE, FILE_NOT_FOUND, OPTION_MISSING,=20 +FORMAT_NOT_SUPPORTED, OPTION_VALUE_INVALID, PARAMETER_INVALID from Workspace.WorkspaceDatabase import WorkspaceDatabase =20 from .FdfParser import FdfParser, Warning @@ -59,43 +59,45 @@ __copyright_= _ =3D "Copyright (c) 2007 - 2018, Intel Corporation All rights reserv def= main(): global Options Options =3D myOptionParser() + EdkLogger.Initialize() + return GenFdsApi(OptionsToCommandDict(Options)) =20 +def GenFdsApi(FdsCommandDict, WorkSpaceDataBase=3DNone): global Workspace Workspace =3D "" ArchList =3D None ReturnCode =3D 0 =20 - EdkLogger.Initialize() try: - if Options.verbose: + if FdsCommandDict.get("verbose"): EdkLogger.SetLevel(EdkLogger.VERBOSE) GenFdsGlobalVariable.VerboseMode =3D True =20 - if Options.FixedAddress: + if FdsCommandDict.get("FixedAddress"): GenFdsGlobalVariable.FixedLoadAddress =3D True =20 - if Options.quiet: + if FdsCommandDict.get("quiet"): EdkLogger.SetLevel(EdkLogger.QUIET) - if Options.debug: - EdkLogger.SetLevel(Options.debug + 1) - GenFdsGlobalVariable.DebugLevel =3D Options.debug + if FdsCommandDict.get("debug"): + EdkLogger.SetLevel(FdsCommandDict.get("debug") + 1) + GenFdsGlobalVariable.DebugLevel =3D=20 + FdsCommandDict.get("debug") else: EdkLogger.SetLevel(EdkLogger.INFO) =20 - if not Options.Workspace: + if not FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE'))= : EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defin= ed", ExtraData=3D"Please use '-w' switch to pass it= or set the WORKSPACE environment variable.") - elif not os.path.exists(Options.Workspace): + elif not os.path.exists(FdsCommandDict.get("Workspace",os.environ.= get('WORKSPACE'))): EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is inv= alid", ExtraData=3D"Please use '-w' switch to pass it= or set the WORKSPACE environment variable.") else: - Workspace =3D os.path.normcase(Options.Workspace) + Workspace =3D=20 + os.path.normcase(FdsCommandDict.get("Workspace",os.environ.get('WORKSP + ACE'))) GenFdsGlobalVariable.WorkSpaceDir =3D Workspace if 'EDK_SOURCE' in os.environ: GenFdsGlobalVariable.EdkSourceDir =3D os.path.normcase(os.= environ['EDK_SOURCE']) - if Options.debug: + if FdsCommandDict.get("debug"): GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Wo= rkspace) - if Options.GenfdsMultiThread: + if FdsCommandDict.get("GenfdsMultiThread"): GenFdsGlobalVariable.EnableGenfdsMultiThread =3D True os.chdir(GenFdsGlobalVariable.WorkSpaceDir) =20 @@ -103,8 +105,8 @@ def main(): PackagesPath =3D os.getenv("PACKAGES_PATH") mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath) =20 - if Options.filename: - FdfFilename =3D Options.filename + if FdsCommandDict.get("fdf_file"): + FdfFilename =3D FdsCommandDict.get("fdf_file")[0].Path FdfFilename =3D GenFdsGlobalVariable.ReplaceWorkspaceMacro(Fdf= Filename) =20 if FdfFilename[0:2] =3D=3D '..': @@ -119,14 +121,14 @@ def main(): else: EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filenam= e") =20 - if Options.BuildTarget: - GenFdsGlobalVariable.TargetName =3D Options.BuildTarget + if FdsCommandDict.get("build_target"): + GenFdsGlobalVariable.TargetName =3D=20 + FdsCommandDict.get("build_target") =20 - if Options.ToolChain: - GenFdsGlobalVariable.ToolChainTag =3D Options.ToolChain + if FdsCommandDict.get("toolchain_tag"): + GenFdsGlobalVariable.ToolChainTag =3D=20 + FdsCommandDict.get("toolchain_tag") =20 - if Options.activePlatform: - ActivePlatform =3D Options.activePlatform + if FdsCommandDict.get("active_platform"): + ActivePlatform =3D FdsCommandDict.get("active_platform") ActivePlatform =3D GenFdsGlobalVariable.ReplaceWorkspaceMacro(= ActivePlatform) =20 if ActivePlatform[0:2] =3D=3D '..': @@ -140,12 +142,12 @@ def main(): else: EdkLogger.error("GenFds", OPTION_MISSING, "Missing active plat= form") =20 - GlobalData.BuildOptionPcd =3D Options.OptionPcd if Options.OptionP= cd else {} + GlobalData.BuildOptionPcd =3D FdsCommandDict.get("OptionPcd") if=20 + FdsCommandDict.get("OptionPcd") else {} GenFdsGlobalVariable.ActivePlatform =3D PathClass(NormPath(ActiveP= latform)) =20 - if Options.ConfDirectory: + if FdsCommandDict.get("conf_directory"): # Get alternate Conf location, if it is absolute, then just us= e the absolute directory name - ConfDirectoryPath =3D os.path.normpath(Options.ConfDirectory) + ConfDirectoryPath =3D=20 + os.path.normpath(FdsCommandDict.get("conf_directory")) if ConfDirectoryPath.startswith('"'): ConfDirectoryPath =3D ConfDirectoryPath[1:] if ConfDirectoryPath.endswith('"'): @@ -169,14 +171,14 @@ def main(): TargetTxt.LoadTargetTxtFile(BuildConfigurationFile) # if no build target given in command line, get it from target= .txt if not GenFdsGlobalVariable.TargetName: - BuildTargetList =3D TargetTxt.TargetTxtDictionary[DataType= .TAB_TAT_DEFINES_TARGET] + BuildTargetList =3D=20 + TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET] if len(BuildTargetList) !=3D 1: EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraD= ata=3D"Only allows one instance for Target.") GenFdsGlobalVariable.TargetName =3D BuildTargetList[0] =20 # if no tool chain given in command line, get it from target.t= xt if not GenFdsGlobalVariable.ToolChainTag: - ToolChainList =3D TargetTxt.TargetTxtDictionary[DataType.T= AB_TAT_DEFINES_TOOL_CHAIN_TAG] + ToolChainList =3D=20 + TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG] if ToolChainList is None or len(ToolChainList) =3D=3D 0: EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, Extr= aData=3D"No toolchain given. Don't know how to build.") if len(ToolChainList) !=3D 1: @@ -186,10 +188,10 @@ def main(): EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=3DBuildCon= figurationFile) =20 #Set global flag for build mode - GlobalData.gIgnoreSource =3D Options.IgnoreSources + GlobalData.gIgnoreSource =3D FdsCommandDict.get("IgnoreSources") =20 - if Options.Macros: - for Pair in Options.Macros: + if FdsCommandDict.get("macro"): + for Pair in FdsCommandDict.get("macro"): if Pair.startswith('"'): Pair =3D Pair[1:] if Pair.endswith('"'): @@ -224,8 +226,11 @@ def main(): =20 """call Workspace build create database""" GlobalData.gDatabasePath =3D os.path.normpath(os.path.join(ConfDir= ectoryPath, GlobalData.gDatabasePath)) - BuildWorkSpace =3D WorkspaceDatabase(GlobalData.gDatabasePath) - BuildWorkSpace.InitDatabase() + if WorkSpaceDataBase: + BuildWorkSpace =3D WorkSpaceDataBase + else: + BuildWorkSpace =3D WorkspaceDatabase(GlobalData.gDatabasePath) + BuildWorkSpace.InitDatabase() =20 # # Get files real name in workspace dir @@ -233,23 +238,23 @@ def m= ain(): GlobalData.gAllFiles =3D DirCache(Workspace) GlobalData.gWorkspace =3D Workspace =20 - if Options.archList: - ArchList =3D Options.archList.split(',') + if FdsCommandDict.get("build_architecture_list"): + ArchList =3D=20 + FdsCommandDict.get("build_architecture_list").split(',') else: - ArchList =3D BuildWorkSpace.BuildObject[GenFdsGlobalVariable.A= ctivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].SupArchL= ist + ArchList =3D=20 + BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform,=20 + TAB_COMMON, FdsCommandDict.get("build_target"),=20 + FdsCommandDict.get("toolchain_tag")].SupArchList =20 - TargetArchList =3D set(BuildWorkSpace.BuildObject[GenFdsGlobalVari= able.ActivePlatform, TAB_COMMON, Options.BuildTarget, Options.ToolChain].Su= pArchList) & set(ArchList) + TargetArchList =3D=20 + set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform,=20 + TAB_COMMON, FdsCommandDict.get("build_target"),=20 + FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList) if len(TargetArchList) =3D=3D 0: EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in= platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObje= ct[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList))) =20 for Arch in ArchList: - GenFdsGlobalVariable.OutputDirFromDscDict[Arch] =3D NormPath(B= uildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, Option= s.BuildTarget, Options.ToolChain].OutputDirectory) + GenFdsGlobalVariable.OutputDirFromDscDict[Arch] =3D=20 + NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatfor + m, Arch, FdsCommandDict.get("build_target"),=20 + FdsCommandDict.get("toolchain_tag")].OutputDirectory) =20 # assign platform name based on last entry in ArchList - GenFdsGlobalVariable.PlatformName =3D BuildWorkSpace.BuildObject[G= enFdsGlobalVariable.ActivePlatform, ArchList[-1], Options.BuildTarget, Opti= ons.ToolChain].PlatformName + GenFdsGlobalVariable.PlatformName =3D=20 + BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform,=20 + ArchList[-1], FdsCommandDict.get("build_target"),=20 + FdsCommandDict.get("toolchain_tag")].PlatformName =20 - if Options.outputDir: - OutputDirFromCommandLine =3D GenFdsGlobalVariable.ReplaceWorks= paceMacro(Options.outputDir) + if FdsCommandDict.get("platform_build_directory"): + OutputDirFromCommandLine =3D=20 + GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platfor + m_build_directory")) if not os.path.isabs (OutputDirFromCommandLine): OutputDirFromCommandLine =3D os.path.join(GenFdsGlobalVari= able.WorkSpaceDir, OutputDirFromCommandLine) for Arch in ArchList: @@ -271,32 +276,35 @@ def main(): GenFdsGlobalVariable.OutputDirDict[Key] =3D OutputDir =20 """ Parse Fdf file, has to place after build Workspace as FDF may = contain macros from DSC file """ - FdfParserObj =3D FdfParser(FdfFilename) - FdfParserObj.ParseFile() + if WorkSpaceDataBase: + FdfParserObj =3D GlobalData.gFdfParser + else: + FdfParserObj =3D FdfParser(FdfFilename) + FdfParserObj.ParseFile() =20 if FdfParserObj.CycleReferenceCheck(): EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Referen= ce Detected in FDF file") =20 - if Options.uiFdName: - if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict: - GenFds.OnlyGenerateThisFd =3D Options.uiFdName + if FdsCommandDict.get("fd"): + if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile= .FdDict: + GenFds.OnlyGenerateThisFd =3D FdsCommandDict.get("fd")[0] else: EdkLogger.error("GenFds", OPTION_VALUE_INVALID, - "No such an FD in FDF file: %s" % Options.= uiFdName) + "No such an FD in FDF file: %s" %=20 + FdsCommandDict.get("fd")[0]) =20 - if Options.uiFvName: - if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict: - GenFds.OnlyGenerateThisFv =3D Options.uiFvName + if FdsCommandDict.get("fv"): + if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile= .FvDict: + GenFds.OnlyGenerateThisFv =3D FdsCommandDict.get("fv")[0] else: EdkLogger.error("GenFds", OPTION_VALUE_INVALID, - "No such an FV in FDF file: %s" % Options.= uiFvName) + "No such an FV in FDF file: %s" %=20 + FdsCommandDict.get("fv")[0]) =20 - if Options.uiCapName: - if Options.uiCapName.upper() in FdfParserObj.Profile.CapsuleDi= ct: - GenFds.OnlyGenerateThisCap =3D Options.uiCapName + if FdsCommandDict.get("cap"): + if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profil= e.CapsuleDict: + GenFds.OnlyGenerateThisCap =3D=20 + FdsCommandDict.get("cap")[0] else: EdkLogger.error("GenFds", OPTION_VALUE_INVALID, - "No such a Capsule in FDF file: %s" % Opti= ons.uiCapName) + "No such a Capsule in FDF file: %s" %=20 + FdsCommandDict.get("cap")[0]) =20 GenFdsGlobalVariable.WorkSpace =3D BuildWorkSpace if ArchList: @@ -337,7 +345,7 @@ def main(): EdkLogger.error(X.ToolName, FORMAT_INVALID, File=3DX.FileName, Lin= e=3DX.LineNumber, ExtraData=3DX.Message, RaiseError=3DFalse) ReturnCode =3D FORMAT_INVALID except FatalError as X: - if Options.debug is not None: + if FdsCommandDict.get("debug") is not None: import traceback EdkLogger.quiet(traceback.format_exc()) ReturnCode =3D X.args[0] @@ -356,6 +364,30 @@ def main(): ClearDuplicatedInf() return ReturnCode =20 +def OptionsToCommandDict(Options): + FdsCommandDict =3D {} + FdsCommandDict["verbose"] =3D Options.verbose + FdsCommandDict["FixedAddress"] =3D Options.FixedAddress + FdsCommandDict["quiet"] =3D Options.quiet + FdsCommandDict["debug"] =3D Options.debug + FdsCommandDict["Workspace"] =3D Options.Workspace + FdsCommandDict["GenfdsMultiThread"] =3D Options.GenfdsMultiThread + FdsCommandDict["fdf_file"] =3D [PathClass(Options.filename)] if Option= s.filename else [] + FdsCommandDict["build_target"] =3D Options.BuildTarget + FdsCommandDict["toolchain_tag"] =3D Options.ToolChain + FdsCommandDict["active_platform"] =3D Options.activePlatform + FdsCommandDict["OptionPcd"] =3D Options.OptionPcd + FdsCommandDict["conf_directory"] =3D Options.ConfDirectory + FdsCommandDict["IgnoreSources"] =3D Options.IgnoreSources + FdsCommandDict["macro"] =3D Options.Macros + FdsCommandDict["build_architecture_list"] =3D Options.archList + FdsCommandDict["platform_build_directory"] =3D Options.outputDir + FdsCommandDict["fd"] =3D [Options.uiFdName] if Options.uiFdName else [= ] + FdsCommandDict["fv"] =3D [Options.uiFvName] if Options.uiFvName else [= ] + FdsCommandDict["cap"] =3D [Options.uiCapName] if Options.uiCapName els= e [] + return FdsCommandDict + + gParamCheck =3D [] def SingleCheckCallback(option, opt_str, value, parser): if option not in gParamCheck: @@ -716,6 +748,7 @@ class GenFds(object): os.remove(GuidXRefFileName) GuidXRefFile.close() =20 + if __name__ =3D=3D '__main__': r =3D main() ## 0-127 is a safe return range, and 1 is a standard default error dif= f --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/= build/build.py index d74082fc26..d87b13c090 100644 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -52,7 +52,7 @@ from PatchPcdValue.PatchPcdValue import * =20 import Common.EdkLogger import Common.GlobalData as GlobalData -from GenFds.GenFds import GenFds +from GenFds.GenFds import GenFds, GenFdsApi =20 from collections import OrderedDict, defaultdict =20 @@ -1392,7 +1392,7 @@ class Build(): =20 # genfds if Target =3D=3D 'fds': - LaunchCommand(AutoGenObject.GenFdsCommand, AutoGenObject.MakeF= ileDir) + GenFdsApi(AutoGenObject.GenFdsCommandDict, self.Db) return True =20 # run @@ -2136,7 +2136,7 @@ class Build(): # Generate FD image if there's a FDF file found # GenFdsStart =3D time.time() - LaunchCommand(Wa.GenFdsCommand, os.getcwd()) + GenFdsApi(Wa.GenFdsCommandDict, self.Db) =20 # # Create MAP file for all platform FVs after GenFd= s. -- 2.14.1.windows.1