BaseTools: Update Build tool to support multiple workspaces
authorLi YangX <yangx.li@intel.com>
Thu, 8 Oct 2015 09:27:14 +0000 (09:27 +0000)
committerlgao4 <lgao4@Edk2>
Thu, 8 Oct 2015 09:27:14 +0000 (09:27 +0000)
WORKSPACE is still kept.
New PACKAGES_PATH is introduced to specify the additional WORKSPACEs.
In PACKAGES_PATH, ';' is separator in Windows, ':' is separator in Linux.

Build directory is in WORKSPACE. Package, BaseTools and Conf directory
will be found from WORKSPACE and PACKAGES_PATH.

In implementation, BaseTools adds MultipleWorkspace class for
the file path conversion from WORKSPACE and PACKAGES_PATH.

Verify two tree layouts.
Root\edk2\MdePkg
Root\edk2\MdeMdeModulePkg
Root\edk2\...
1. set WORKSPACE=Root\edk2
2. set WORKSPACE=Root, and set PACKAGES_PATH=Root\edk2

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Li YangX <yangx.li@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18579 6f19259b-4bc3-4df7-8a09-765794883524

15 files changed:
BaseTools/Source/Python/AutoGen/AutoGen.py
BaseTools/Source/Python/AutoGen/GenMake.py
BaseTools/Source/Python/Common/EdkIIWorkspace.py
BaseTools/Source/Python/Common/FdfParserLite.py
BaseTools/Source/Python/Common/LongFilePathOsPath.py
BaseTools/Source/Python/Common/Misc.py
BaseTools/Source/Python/Common/MultipleWorkspace.py [new file with mode: 0644]
BaseTools/Source/Python/Common/String.py
BaseTools/Source/Python/GenFds/FfsInfStatement.py
BaseTools/Source/Python/GenFds/GenFds.py
BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py
BaseTools/Source/Python/GenFds/Region.py
BaseTools/Source/Python/Workspace/WorkspaceDatabase.py
BaseTools/Source/Python/build/BuildReport.py
BaseTools/Source/Python/build/build.py

index 259abc519b00258600b28db1a38f8eb4a2478ab6..fe565743576bd6bd7688e4e454a60dde1583a3d1 100644 (file)
@@ -40,7 +40,7 @@ from GenPatchPcdTable.GenPatchPcdTable import parsePcdInfoFromMapFile
 import Common.VpdInfoFile as VpdInfoFile\r
 from GenPcdDb import CreatePcdDatabaseCode\r
 from Workspace.MetaFileCommentParser import UsageList\r
-\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 import InfSectionParser\r
 \r
 ## Regular expression for splitting Dependency Expression string into tokens\r
@@ -953,7 +953,7 @@ class PlatformAutoGen(AutoGen):
         self._GuidValue = {}\r
         FdfModuleList = []\r
         for InfName in self._AsBuildInfList:\r
-            InfName = os.path.join(self.WorkspaceDir, InfName)\r
+            InfName = mws.join(self.WorkspaceDir, InfName)\r
             FdfModuleList.append(os.path.normpath(InfName))\r
         for F in self.Platform.Modules.keys():\r
             M = ModuleAutoGen(self.Workspace, F, self.BuildTarget, self.ToolChain, self.Arch, self.MetaFile)\r
@@ -1288,7 +1288,7 @@ class PlatformAutoGen(AutoGen):
     def _GetFdfFile(self):\r
         if self._FdfFile == None:\r
             if self.Workspace.FdfFile != "":\r
-                self._FdfFile= path.join(self.WorkspaceDir, self.Workspace.FdfFile)\r
+                self._FdfFile= mws.join(self.WorkspaceDir, self.Workspace.FdfFile)\r
             else:\r
                 self._FdfFile = ''\r
         return self._FdfFile\r
@@ -2115,8 +2115,11 @@ class PlatformAutoGen(AutoGen):
                         BuildOptions[Tool][Attr] = ""\r
                     # check if override is indicated\r
                     if Value.startswith('='):\r
-                        BuildOptions[Tool][Attr] = Value[1:]\r
+                        ToolPath = Value[1:]\r
+                        ToolPath = mws.handleWsMacro(ToolPath)\r
+                        BuildOptions[Tool][Attr] = ToolPath\r
                     else:\r
+                        Value = mws.handleWsMacro(Value)\r
                         BuildOptions[Tool][Attr] += " " + Value\r
         if Module.AutoGenVersion < 0x00010005 and self.Workspace.UniFlag != None:\r
             #\r
@@ -2193,8 +2196,7 @@ class ModuleAutoGen(AutoGen):
             return False\r
 \r
         self.SourceDir = self.MetaFile.SubDir\r
-        if self.SourceDir.upper().find(self.WorkspaceDir.upper()) == 0:\r
-            self.SourceDir = self.SourceDir[len(self.WorkspaceDir) + 1:]\r
+        self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir)\r
 \r
         self.SourceOverrideDir = None\r
         # use overrided path defined in DSC file\r
@@ -3042,7 +3044,7 @@ class ModuleAutoGen(AutoGen):
                 self._IncludePathList.append(self.DebugDir)\r
 \r
             for Package in self.Module.Packages:\r
-                PackageDir = path.join(self.WorkspaceDir, Package.MetaFile.Dir)\r
+                PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)\r
                 if PackageDir not in self._IncludePathList:\r
                     self._IncludePathList.append(PackageDir)\r
                 for Inc in Package.Includes:\r
index 0342709a3a6377f8c73c1f4c796d9f4bd9cf5b74..d9b219e1c75fe778f4e485289504c754885a9576 100644 (file)
@@ -19,7 +19,7 @@ import string
 import re\r
 import os.path as path\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
-\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 from Common.BuildToolError import *\r
 from Common.Misc import *\r
 from Common.String import *\r
@@ -559,7 +559,7 @@ cleanlib:
         found = False\r
         while not found and os.sep in package_rel_dir:\r
             index = package_rel_dir.index(os.sep)\r
-            current_dir = os.path.join(current_dir, package_rel_dir[:index])\r
+            current_dir = mws.join(current_dir, package_rel_dir[:index])\r
             for fl in os.listdir(current_dir):\r
                 if fl.endswith('.dec'):\r
                     found = True\r
index 84d89b6c2ef8092ced61a38538782e6bf0b707f9..401efeef3c9438b4f33d514b229c594135b290df 100644 (file)
@@ -17,6 +17,7 @@
 import Common.LongFilePathOs as os, sys, time\r
 from DataType import *\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ## EdkIIWorkspace\r
 #\r
@@ -112,7 +113,7 @@ class EdkIIWorkspace:
     # @retval string  The full path filename\r
     #\r
     def WorkspaceFile(self, FileName):\r
-        return os.path.realpath(os.path.join(self.WorkspaceDir,FileName))\r
+        return os.path.realpath(mws.join(self.WorkspaceDir,FileName))\r
 \r
     ## Convert to a real path filename\r
     #\r
index 54a60a7e8f81c1655c434b29f776edb88ad74b77..a0ee249748e1d8bb0e20aba265b74badc5175cbc 100644 (file)
@@ -20,6 +20,7 @@ import Common.LongFilePathOs as os
 \r
 import CommonDataClass.FdfClass\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ##define T_CHAR_SPACE                ' '\r
 ##define T_CHAR_NULL                 '\0'\r
@@ -485,7 +486,8 @@ class FdfParser(object):
                 IncFileName = self.__Token\r
                 if not os.path.isabs(IncFileName):\r
                     if IncFileName.startswith('$(WORKSPACE)'):\r
-                        Str = IncFileName.replace('$(WORKSPACE)', os.environ.get('WORKSPACE'))\r
+                        Str = mws.handleWsMacro(IncFileName)\r
+                        Str = Str.replace('$(WORKSPACE)', os.environ.get('WORKSPACE'))\r
                         if os.path.exists(Str):\r
                             if not os.path.isabs(Str):\r
                                 Str = os.path.abspath(Str)\r
@@ -494,7 +496,7 @@ class FdfParser(object):
                         # file is in the same dir with FDF file\r
                         FullFdf = self.FileName\r
                         if not os.path.isabs(self.FileName):\r
-                            FullFdf = os.path.join(os.environ.get('WORKSPACE'), self.FileName)\r
+                            FullFdf = mws.join(os.environ.get('WORKSPACE'), self.FileName)\r
                 \r
                         IncFileName = os.path.join(os.path.dirname(FullFdf), IncFileName)\r
                     \r
index cb89b1b81384a862ee510c92007307e821846908..0bba4464195dbe7275605e4142bf241c2c10d05b 100644 (file)
@@ -49,3 +49,5 @@ dirname = os.path.dirname
 islink = os.path.islink\r
 isabs = os.path.isabs\r
 realpath = os.path.realpath\r
+relpath = os.path.relpath\r
+pardir = os.path.pardir\r
index 8ba5819cc1e337af0b26f7c7c7f47f6e0c1954cc..0eedddc861255fedd891e281e89d3edc4e1ac0cf 100644 (file)
@@ -35,6 +35,7 @@ from BuildToolError import *
 from CommonDataClass.DataClass import *\r
 from Parsing import GetSplitValueList\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ## Regular expression used to find out place holders in string template\r
 gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)\r
@@ -1728,6 +1729,7 @@ class PathClass(object):
 \r
         # Remove any '.' and '..' in path\r
         if self.Root:\r
+            self.Root = mws.getWs(self.Root, self.File)\r
             self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
             self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
             # eliminate the side-effect of 'C:'\r
@@ -1838,7 +1840,10 @@ class PathClass(object):
                 RealFile = os.path.join(self.AlterRoot, self.File)\r
             elif self.Root:\r
                 RealFile = os.path.join(self.Root, self.File)\r
-            return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
+            if len (mws.getPkgPath()) == 0:\r
+                return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
+            else:\r
+                return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
 \r
         ErrorCode = 0\r
         ErrorInfo = ''\r
diff --git a/BaseTools/Source/Python/Common/MultipleWorkspace.py b/BaseTools/Source/Python/Common/MultipleWorkspace.py
new file mode 100644 (file)
index 0000000..8088404
--- /dev/null
@@ -0,0 +1,148 @@
+## @file\r
+# manage multiple workspace file.\r
+#\r
+# This file is required to make Python interpreter treat the directory\r
+# as containing package.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+\r
+import Common.LongFilePathOs as os\r
+from Common.DataType import TAB_WORKSPACE\r
+\r
+## MultipleWorkspace\r
+#\r
+# This class manage multiple workspace behavior\r
+# \r
+# @param class:\r
+#\r
+# @var WORKSPACE:      defined the current WORKSPACE\r
+# @var PACKAGES_PATH:  defined the other WORKSAPCE, if current WORKSPACE is invalid, search valid WORKSPACE from PACKAGES_PATH\r
+# \r
+class MultipleWorkspace(object):\r
+    WORKSPACE = ''\r
+    PACKAGES_PATH = None\r
+    \r
+    ## convertPackagePath()\r
+    #\r
+    #   Convert path to match workspace.\r
+    #\r
+    #   @param  cls          The class pointer\r
+    #   @param  Ws           The current WORKSPACE\r
+    #   @param  Path         Path to be converted to match workspace.\r
+    #\r
+    @classmethod\r
+    def convertPackagePath(cls, Ws, Path):\r
+        if str(os.path.normcase (Path)).startswith(Ws):\r
+            return os.path.join(Ws, Path[len(Ws) + 1:])\r
+        return Path\r
+\r
+    ## setWs()\r
+    #\r
+    #   set WORKSPACE and PACKAGES_PATH environment\r
+    #\r
+    #   @param  cls          The class pointer\r
+    #   @param  Ws           initialize WORKSPACE variable\r
+    #   @param  PackagesPath initialize PackagesPath variable\r
+    #\r
+    @classmethod\r
+    def setWs(cls, Ws, PackagesPath=None):\r
+        cls.WORKSPACE = Ws\r
+        if PackagesPath:\r
+            cls.PACKAGES_PATH = [cls.convertPackagePath (Ws, os.path.normpath(Path.strip())) for Path in PackagesPath.split(os.pathsep)]\r
+        else:\r
+            cls.PACKAGES_PATH = []\r
+    \r
+    ## join()\r
+    #\r
+    #   rewrite os.path.join function\r
+    #\r
+    #   @param  cls       The class pointer\r
+    #   @param  Ws        the current WORKSPACE\r
+    #   @param  *p        path of the inf/dec/dsc/fdf/conf file\r
+    #   @retval Path      the absolute path of specified file\r
+    #\r
+    @classmethod\r
+    def join(cls, Ws, *p):\r
+        Path = os.path.join(Ws, *p)\r
+        if not os.path.exists(Path):\r
+            for Pkg in cls.PACKAGES_PATH:\r
+                Path = os.path.join(Pkg, *p)\r
+                if os.path.exists(Path):\r
+                    return Path\r
+            Path = os.path.join(Ws, *p)\r
+        return Path\r
+    \r
+    ## relpath()\r
+    #\r
+    #   rewrite os.path.relpath function\r
+    #\r
+    #   @param  cls       The class pointer\r
+    #   @param  Path      path of the inf/dec/dsc/fdf/conf file\r
+    #   @param  Ws        the current WORKSPACE\r
+    #   @retval Path      the relative path of specified file\r
+    #\r
+    @classmethod\r
+    def relpath(cls, Path, Ws):\r
+        for Pkg in cls.PACKAGES_PATH:\r
+            if Path.lower().startswith(Pkg.lower()):\r
+                Path = os.path.relpath(Path, Pkg)\r
+                return Path\r
+        if Path.lower().startswith(Ws.lower()):\r
+            Path = os.path.relpath(Path, Ws)\r
+        return Path\r
+    \r
+    ## getWs()\r
+    #\r
+    #   get valid workspace for the path\r
+    #\r
+    #   @param  cls       The class pointer\r
+    #   @param  Ws        the current WORKSPACE\r
+    #   @param  Path      path of the inf/dec/dsc/fdf/conf file\r
+    #   @retval Ws        the valid workspace relative to the specified file path\r
+    #\r
+    @classmethod\r
+    def getWs(cls, Ws, Path):\r
+        absPath = os.path.join(Ws, Path)\r
+        if not os.path.exists(absPath):\r
+            for Pkg in cls.PACKAGES_PATH:\r
+                absPath = os.path.join(Pkg, Path)\r
+                if os.path.exists(absPath):\r
+                    return Pkg\r
+        return Ws\r
+    \r
+    ## handleWsMacro()\r
+    #\r
+    #   handle the $(WORKSPACE) tag, if current workspace is invalid path relative the tool, replace it.\r
+    #\r
+    #   @param  cls       The class pointer\r
+    #   @retval PathStr   Path string include the $(WORKSPACE)\r
+    #\r
+    @classmethod\r
+    def handleWsMacro(cls, PathStr):\r
+        if TAB_WORKSPACE in PathStr:\r
+            Path = PathStr.replace(TAB_WORKSPACE, cls.WORKSPACE).strip()\r
+            if not os.path.exists(Path):\r
+                for Pkg in cls.PACKAGES_PATH:\r
+                    Path = PathStr.replace(TAB_WORKSPACE, Pkg).strip()\r
+                    if os.path.exists(Path):\r
+                        return Path\r
+        return PathStr\r
+    \r
+    ## getPkgPath()\r
+    #\r
+    #   get all package pathes.\r
+    #\r
+    #   @param  cls       The class pointer\r
+    #\r
+    @classmethod\r
+    def getPkgPath(cls):\r
+        return cls.PACKAGES_PATH\r
+            
\ No newline at end of file
index 6c9671d5142235f24688e4f745349e2d4d63fdd1..5c8d1e0ded5b86b0463b0d31a1a7776e9f2a493a 100644 (file)
@@ -24,6 +24,7 @@ import GlobalData
 from BuildToolError import *\r
 from CommonDataClass.Exceptions import *\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE)\r
 gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')\r
@@ -305,6 +306,11 @@ def NormPath(Path, Defines={}):
         # To local path format\r
         #\r
         Path = os.path.normpath(Path)\r
+        if Path.startswith(GlobalData.gWorkspace) and not os.path.exists(Path):\r
+            Path = Path[len (GlobalData.gWorkspace):]\r
+            if Path[0] == os.path.sep:\r
+                Path = Path[1:]\r
+            Path = mws.join(GlobalData.gWorkspace, Path)\r
 \r
     if IsRelativePath and Path[0] != '.':\r
         Path = os.path.join('.', Path)\r
@@ -702,7 +708,7 @@ def RaiseParserError(Line, Section, File, Format='', LineNo= -1):
 # @retval string A full path\r
 #\r
 def WorkspaceFile(WorkspaceDir, Filename):\r
-    return os.path.join(NormPath(WorkspaceDir), NormPath(Filename))\r
+    return mws.join(NormPath(WorkspaceDir), NormPath(Filename))\r
 \r
 ## Split string\r
 #\r
index 29dc75f433f4ef51615ed32c4e02f91d06391819..ed767d3fa698f33f607e0d906a183f5d091a6197 100644 (file)
@@ -28,6 +28,7 @@ import Section
 import RuleSimpleFile\r
 import RuleComplexFile\r
 from CommonDataClass.FdfClass import FfsInfStatementClassObject\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 from Common.String import *\r
 from Common.Misc import PathClass\r
 from Common.Misc import GuidStructureByteArrayToGuidString\r
@@ -365,7 +366,7 @@ class FfsInfStatement(FfsInfStatementClassObject):
         #\r
 \r
         self.__InfParse__(Dict)\r
-        SrcFile = os.path.join( GenFdsGlobalVariable.WorkSpaceDir , self.InfFileName);\r
+        SrcFile = mws.join( GenFdsGlobalVariable.WorkSpaceDir , self.InfFileName);\r
         DestFile = os.path.join( self.OutputPath, self.ModuleGuid + '.ffs')\r
         \r
         SrcFileDir = "."\r
@@ -511,7 +512,7 @@ class FfsInfStatement(FfsInfStatementClassObject):
     #\r
     def __GetPlatformArchList__(self):\r
 \r
-        InfFileKey = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName))\r
+        InfFileKey = os.path.normpath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName))\r
         DscArchList = []\r
         PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'IA32', GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]\r
         if  PlatformDataBase != None:\r
@@ -878,7 +879,7 @@ class FfsInfStatement(FfsInfStatementClassObject):
             \r
             if not HasGneratedFlag:\r
                 UniVfrOffsetFileSection = ""    \r
-                ModuleFileName = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)\r
+                ModuleFileName = mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)\r
                 InfData = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(ModuleFileName), self.CurrentArch]\r
                 #\r
                 # Search the source list in InfData to find if there are .vfr file exist.\r
index c2ad4e0e2a7c7f0c766741a090bb70ecd9ca935c..a0beff039132a8eee79073c28b473ac5a72dce01 100644 (file)
@@ -39,6 +39,7 @@ from Common.Misc import SaveFileOnChange
 from Common.Misc import ClearDuplicatedInf\r
 from Common.Misc import GuidStructureStringToGuidString\r
 from Common.BuildVersion import gBUILD_VERSION\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ## Version and Copyright\r
 versionNumber = "1.0" + ' ' + gBUILD_VERSION\r
@@ -94,6 +95,10 @@ def main():
             if (Options.debug):\r
                 GenFdsGlobalVariable.VerboseLogger( "Using Workspace:" + Workspace)\r
         os.chdir(GenFdsGlobalVariable.WorkSpaceDir)\r
+        \r
+        # set multiple workspace\r
+        PackagesPath = os.getenv("PACKAGES_PATH")\r
+        mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath)\r
 \r
         if (Options.filename):\r
             FdfFilename = Options.filename\r
@@ -102,7 +107,7 @@ def main():
             if FdfFilename[0:2] == '..':\r
                 FdfFilename = os.path.realpath(FdfFilename)\r
             if not os.path.isabs (FdfFilename):\r
-                FdfFilename = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)\r
+                FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)\r
             if not os.path.exists(FdfFilename):\r
                 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename)\r
 \r
@@ -129,13 +134,13 @@ def main():
                 ActivePlatform = os.path.realpath(ActivePlatform)\r
 \r
             if not os.path.isabs (ActivePlatform):\r
-                ActivePlatform = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)\r
+                ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)\r
 \r
             if not os.path.exists(ActivePlatform)  :\r
                 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!")\r
 \r
             if os.path.normcase (ActivePlatform).find(Workspace) == 0:\r
-                ActivePlatform = ActivePlatform[len(Workspace):]\r
+                ActivePlatform = mws.relpath(ActivePlatform, Workspace)\r
             if len(ActivePlatform) > 0 :\r
                 if ActivePlatform[0] == '\\' or ActivePlatform[0] == '/':\r
                     ActivePlatform = ActivePlatform[1:]\r
@@ -159,7 +164,7 @@ def main():
                 ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath)\r
         else:\r
             # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf\r
-            ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf')\r
+            ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf')\r
         GenFdsGlobalVariable.ConfDir = ConfDirectoryPath\r
         BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt"))\r
         if os.path.isfile(BuildConfigurationFile) == True:\r
index 04bbc300ceda186a13e9fd8ba5c47188fbe470dc..5bdc1b8288a8445a7691d046ea083b66173df44e 100644 (file)
@@ -31,6 +31,7 @@ from AutoGen.BuildEngine import BuildRule
 import Common.DataType as DataType\r
 from Common.Misc import PathClass\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ## Global variables\r
 #\r
@@ -322,12 +323,13 @@ class GenFdsGlobalVariable:
     #   @param  String           String that may contain macro\r
     #\r
     def ReplaceWorkspaceMacro(String):\r
+        String = mws.handleWsMacro(String)\r
         Str = String.replace('$(WORKSPACE)', GenFdsGlobalVariable.WorkSpaceDir)\r
         if os.path.exists(Str):\r
             if not os.path.isabs(Str):\r
                 Str = os.path.abspath(Str)\r
         else:\r
-            Str = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, String)\r
+            Str = mws.join(GenFdsGlobalVariable.WorkSpaceDir, String)\r
         return os.path.normpath(Str)\r
 \r
     ## Check if the input files are newer than output files\r
index 15b2ecba906aff51a3c2c6eb31d3eec366785867..feb56cb60f27d962a0ecff6c88f2319d53f72d5e 100644 (file)
@@ -24,6 +24,7 @@ from stat import *
 from Common import EdkLogger\r
 from Common.BuildToolError import *\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ## generate Region\r
 #\r
@@ -205,7 +206,7 @@ class Region(RegionClassObject):
             for RegionData in self.RegionDataList:\r
                 RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict)\r
                 if RegionData[1] != ':' :\r
-                    RegionData = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData)\r
+                    RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData)\r
                 if not os.path.exists(RegionData):\r
                     EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData)\r
                 #\r
index fd10c5dfb9a8f4d493da00cd353a788d78841f0a..c84d19243c76e10fd1cef78c98f08c1e6045ee68 100644 (file)
@@ -21,6 +21,7 @@ import uuid
 \r
 import Common.EdkLogger as EdkLogger\r
 import Common.GlobalData as GlobalData\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 from Common.String import *\r
 from Common.DataType import *\r
@@ -166,7 +167,7 @@ class DscBuildData(PlatformBuildClassObject):
             ModuleFile = PathClass(NormPath(Record[0]), GlobalData.gWorkspace, Arch=self._Arch)\r
             RecordList = self._RawData[MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH, self._Arch, None, ModuleId]\r
             if RecordList != []:\r
-                SourceOverridePath = os.path.join(GlobalData.gWorkspace, NormPath(RecordList[0][0]))\r
+                SourceOverridePath = mws.join(GlobalData.gWorkspace, NormPath(RecordList[0][0]))\r
 \r
                 # Check if the source override path exists\r
                 if not os.path.isdir(SourceOverridePath):\r
@@ -2179,8 +2180,11 @@ class InfBuildData(ModuleBuildClassObject):
                 if self.AutoGenVersion < 0x00010005:\r
                     Macros["EDK_SOURCE"] = GlobalData.gEcpSource\r
                     Macros['PROCESSOR'] = self._Arch\r
+                    SourceFile = NormPath(Record[0], Macros)\r
+                    if SourceFile[0] == os.path.sep:\r
+                        SourceFile = mws.join(GlobalData.gWorkspace, SourceFile[1:])\r
                     # old module source files (Edk)\r
-                    File = PathClass(NormPath(Record[0], Macros), self._ModuleDir, self._SourceOverridePath,\r
+                    File = PathClass(SourceFile, self._ModuleDir, self._SourceOverridePath,\r
                                      '', False, self._Arch, ToolChainFamily, '', TagName, ToolCode)\r
                     # check the file validation\r
                     ErrorCode, ErrorInfo = File.Validate(CaseSensitive=False)\r
@@ -2343,10 +2347,21 @@ class InfBuildData(ModuleBuildClassObject):
                     if File[0] == '.':\r
                         File = os.path.join(self._ModuleDir, File)\r
                     else:\r
-                        File = os.path.join(GlobalData.gWorkspace, File)\r
+                        File = mws.join(GlobalData.gWorkspace, File)\r
                     File = RealPath(os.path.normpath(File))\r
                     if File:\r
                         self._Includes.append(File)\r
+                    if not File and Record[0].find('EFI_SOURCE') > -1:\r
+                        # tricky to regard WorkSpace as EFI_SOURCE\r
+                        Macros['EFI_SOURCE'] = GlobalData.gWorkspace\r
+                        File = NormPath(Record[0], Macros)\r
+                        if File[0] == '.':\r
+                            File = os.path.join(self._ModuleDir, File)\r
+                        else:\r
+                            File = os.path.join(GlobalData.gWorkspace, File)\r
+                        File = RealPath(os.path.normpath(File))\r
+                        if File:\r
+                            self._Includes.append(File)\r
         return self._Includes\r
 \r
     ## Retrieve packages this module depends on\r
@@ -2797,7 +2812,7 @@ class WorkspaceDatabase(object):
     def __init__(self, DbPath, RenewDb=False):\r
         self._DbClosedFlag = False\r
         if not DbPath:\r
-            DbPath = os.path.normpath(os.path.join(GlobalData.gWorkspace, 'Conf', GlobalData.gDatabasePath))\r
+            DbPath = os.path.normpath(mws.join(GlobalData.gWorkspace, 'Conf', GlobalData.gDatabasePath))\r
 \r
         # don't create necessary path for db in memory\r
         if DbPath != ':memory:':\r
index 264607b0036002da0f25223ec7218da7b46dd854..60e976c169a17989a3e0abfb9571a00e646106a7 100644 (file)
@@ -41,6 +41,7 @@ from Common.DataType import TAB_BRG_PCD
 from Common.DataType import TAB_BRG_LIBRARY\r
 from Common.DataType import TAB_BACK_SLASH\r
 from Common.LongFilePathSupport import OpenLongFilePath as open\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 ## Pattern to extract contents in EDK DXS files\r
 gDxsDependencyPattern = re.compile(r"DEPENDENCY_START(.+)DEPENDENCY_END", re.DOTALL)\r
@@ -1255,7 +1256,7 @@ class FdRegionReport(object):
         for Pa in Wa.AutoGenObjectList:\r
             for ModuleKey in Pa.Platform.Modules:\r
                 M = Pa.Platform.Modules[ModuleKey].M\r
-                InfPath = os.path.join(Wa.WorkspaceDir, M.MetaFile.File)\r
+                InfPath = mws.join(Wa.WorkspaceDir, M.MetaFile.File)\r
                 self._GuidsDb[M.Guid.upper()] = "%s (%s)" % (M.Module.BaseName, InfPath)\r
 \r
         #\r
@@ -1277,7 +1278,7 @@ class FdRegionReport(object):
                             Guid = GuidStructureByteArrayToGuidString(GuidValue).upper()\r
                     for Section in Ffs.SectionList:\r
                         try:\r
-                            ModuleSectFile = os.path.join(Wa.WorkspaceDir, Section.SectFileName)\r
+                            ModuleSectFile = mws.join(Wa.WorkspaceDir, Section.SectFileName)\r
                             self._GuidsDb[Guid] = ModuleSectFile\r
                         except AttributeError:\r
                             pass\r
index 33b45ba26717ac19018e272e7c6f1424f4603039..b5df773f08d9a715536e238d6fa586ab14636c7e 100644 (file)
@@ -41,6 +41,7 @@ from Common.BuildVersion import gBUILD_VERSION
 from AutoGen.AutoGen import *\r
 from Common.BuildToolError import *\r
 from Workspace.WorkspaceDatabase import *\r
+from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 \r
 from BuildReport import BuildReport\r
 from GenPatchPcdTable.GenPatchPcdTable import *\r
@@ -104,12 +105,16 @@ def CheckEnvVariable():
         EdkLogger.error("build", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path",\r
                         ExtraData=WorkspaceDir)\r
     os.environ["WORKSPACE"] = WorkspaceDir\r
+    \r
+    # set multiple workspace\r
+    PackagesPath = os.getenv("PACKAGES_PATH")\r
+    mws.setWs(WorkspaceDir, PackagesPath)\r
 \r
     #\r
     # Check EFI_SOURCE (Edk build convention). EDK_SOURCE will always point to ECP\r
     #\r
     if "ECP_SOURCE" not in os.environ:\r
-        os.environ["ECP_SOURCE"] = os.path.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
+        os.environ["ECP_SOURCE"] = mws.join(WorkspaceDir, GlobalData.gEdkCompatibilityPkg)\r
     if "EFI_SOURCE" not in os.environ:\r
         os.environ["EFI_SOURCE"] = os.environ["ECP_SOURCE"]\r
     if "EDK_SOURCE" not in os.environ:\r
@@ -182,7 +187,7 @@ def CheckEnvVariable():
     GlobalData.gGlobalDefines["EDK_SOURCE"] = EdkSourceDir\r
     GlobalData.gGlobalDefines["ECP_SOURCE"] = EcpSourceDir\r
     GlobalData.gGlobalDefines["EDK_TOOLS_PATH"] = os.environ["EDK_TOOLS_PATH"]\r
-\r
+    \r
 ## Get normalized file path\r
 #\r
 # Convert the path to be local format, and remove the WORKSPACE path at the\r
@@ -198,7 +203,8 @@ def NormFile(FilePath, Workspace):
     if os.path.isabs(FilePath):\r
         FileFullPath = os.path.normpath(FilePath)\r
     else:\r
-        FileFullPath = os.path.normpath(os.path.join(Workspace, FilePath))\r
+        FileFullPath = os.path.normpath(mws.join(Workspace, FilePath))\r
+        Workspace = mws.getWs(Workspace, FilePath)\r
 \r
     # check if the file path exists or not\r
     if not os.path.isfile(FileFullPath):\r
@@ -748,10 +754,10 @@ class Build():
             if not os.path.isabs(ConfDirectoryPath):\r
                 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE\r
                 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf\r
-                ConfDirectoryPath = os.path.join(self.WorkspaceDir, ConfDirectoryPath)\r
+                ConfDirectoryPath = mws.join(self.WorkspaceDir, ConfDirectoryPath)\r
         else:\r
             # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf\r
-            ConfDirectoryPath = os.path.join(self.WorkspaceDir, 'Conf')\r
+            ConfDirectoryPath = mws.join(self.WorkspaceDir, 'Conf')\r
         GlobalData.gConfDirectory = ConfDirectoryPath\r
         GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath))\r
 \r
@@ -796,7 +802,7 @@ class Build():
             ToolDefinitionFile = self.TargetTxt.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF]\r
             if ToolDefinitionFile == '':\r
                 ToolDefinitionFile = gToolsDefinition\r
-                ToolDefinitionFile = os.path.normpath(os.path.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
+                ToolDefinitionFile = os.path.normpath(mws.join(self.WorkspaceDir, 'Conf', ToolDefinitionFile))\r
             if os.path.isfile(ToolDefinitionFile) == True:\r
                 StatusCode = self.ToolDef.LoadToolDefFile(ToolDefinitionFile)\r
             else:\r