BaseTools: Update Build tool to support multiple workspaces

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
This commit is contained in:
Li YangX
2015-10-08 09:27:14 +00:00
committed by lgao4
parent 6fa04d934b
commit 05cc51ad58
15 changed files with 232 additions and 35 deletions

View File

@ -17,6 +17,7 @@
import Common.LongFilePathOs as os, sys, time
from DataType import *
from Common.LongFilePathSupport import OpenLongFilePath as open
from Common.MultipleWorkspace import MultipleWorkspace as mws
## EdkIIWorkspace
#
@ -112,7 +113,7 @@ class EdkIIWorkspace:
# @retval string The full path filename
#
def WorkspaceFile(self, FileName):
return os.path.realpath(os.path.join(self.WorkspaceDir,FileName))
return os.path.realpath(mws.join(self.WorkspaceDir,FileName))
## Convert to a real path filename
#

View File

@ -20,6 +20,7 @@ import Common.LongFilePathOs as os
import CommonDataClass.FdfClass
from Common.LongFilePathSupport import OpenLongFilePath as open
from Common.MultipleWorkspace import MultipleWorkspace as mws
##define T_CHAR_SPACE ' '
##define T_CHAR_NULL '\0'
@ -485,7 +486,8 @@ class FdfParser(object):
IncFileName = self.__Token
if not os.path.isabs(IncFileName):
if IncFileName.startswith('$(WORKSPACE)'):
Str = IncFileName.replace('$(WORKSPACE)', os.environ.get('WORKSPACE'))
Str = mws.handleWsMacro(IncFileName)
Str = Str.replace('$(WORKSPACE)', os.environ.get('WORKSPACE'))
if os.path.exists(Str):
if not os.path.isabs(Str):
Str = os.path.abspath(Str)
@ -494,7 +496,7 @@ class FdfParser(object):
# file is in the same dir with FDF file
FullFdf = self.FileName
if not os.path.isabs(self.FileName):
FullFdf = os.path.join(os.environ.get('WORKSPACE'), self.FileName)
FullFdf = mws.join(os.environ.get('WORKSPACE'), self.FileName)
IncFileName = os.path.join(os.path.dirname(FullFdf), IncFileName)

View File

@ -49,3 +49,5 @@ dirname = os.path.dirname
islink = os.path.islink
isabs = os.path.isabs
realpath = os.path.realpath
relpath = os.path.relpath
pardir = os.path.pardir

View File

@ -35,6 +35,7 @@ from BuildToolError import *
from CommonDataClass.DataClass import *
from Parsing import GetSplitValueList
from Common.LongFilePathSupport import OpenLongFilePath as open
from Common.MultipleWorkspace import MultipleWorkspace as mws
## Regular expression used to find out place holders in string template
gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)
@ -1728,6 +1729,7 @@ class PathClass(object):
# Remove any '.' and '..' in path
if self.Root:
self.Root = mws.getWs(self.Root, self.File)
self.Path = os.path.normpath(os.path.join(self.Root, self.File))
self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
# eliminate the side-effect of 'C:'
@ -1838,7 +1840,10 @@ class PathClass(object):
RealFile = os.path.join(self.AlterRoot, self.File)
elif self.Root:
RealFile = os.path.join(self.Root, self.File)
return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
if len (mws.getPkgPath()) == 0:
return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
else:
return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))
ErrorCode = 0
ErrorInfo = ''

View File

@ -0,0 +1,148 @@
## @file
# manage multiple workspace file.
#
# This file is required to make Python interpreter treat the directory
# as containing package.
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
# 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.
#
import Common.LongFilePathOs as os
from Common.DataType import TAB_WORKSPACE
## MultipleWorkspace
#
# This class manage multiple workspace behavior
#
# @param class:
#
# @var WORKSPACE: defined the current WORKSPACE
# @var PACKAGES_PATH: defined the other WORKSAPCE, if current WORKSPACE is invalid, search valid WORKSPACE from PACKAGES_PATH
#
class MultipleWorkspace(object):
WORKSPACE = ''
PACKAGES_PATH = None
## convertPackagePath()
#
# Convert path to match workspace.
#
# @param cls The class pointer
# @param Ws The current WORKSPACE
# @param Path Path to be converted to match workspace.
#
@classmethod
def convertPackagePath(cls, Ws, Path):
if str(os.path.normcase (Path)).startswith(Ws):
return os.path.join(Ws, Path[len(Ws) + 1:])
return Path
## setWs()
#
# set WORKSPACE and PACKAGES_PATH environment
#
# @param cls The class pointer
# @param Ws initialize WORKSPACE variable
# @param PackagesPath initialize PackagesPath variable
#
@classmethod
def setWs(cls, Ws, PackagesPath=None):
cls.WORKSPACE = Ws
if PackagesPath:
cls.PACKAGES_PATH = [cls.convertPackagePath (Ws, os.path.normpath(Path.strip())) for Path in PackagesPath.split(os.pathsep)]
else:
cls.PACKAGES_PATH = []
## join()
#
# rewrite os.path.join function
#
# @param cls The class pointer
# @param Ws the current WORKSPACE
# @param *p path of the inf/dec/dsc/fdf/conf file
# @retval Path the absolute path of specified file
#
@classmethod
def join(cls, Ws, *p):
Path = os.path.join(Ws, *p)
if not os.path.exists(Path):
for Pkg in cls.PACKAGES_PATH:
Path = os.path.join(Pkg, *p)
if os.path.exists(Path):
return Path
Path = os.path.join(Ws, *p)
return Path
## relpath()
#
# rewrite os.path.relpath function
#
# @param cls The class pointer
# @param Path path of the inf/dec/dsc/fdf/conf file
# @param Ws the current WORKSPACE
# @retval Path the relative path of specified file
#
@classmethod
def relpath(cls, Path, Ws):
for Pkg in cls.PACKAGES_PATH:
if Path.lower().startswith(Pkg.lower()):
Path = os.path.relpath(Path, Pkg)
return Path
if Path.lower().startswith(Ws.lower()):
Path = os.path.relpath(Path, Ws)
return Path
## getWs()
#
# get valid workspace for the path
#
# @param cls The class pointer
# @param Ws the current WORKSPACE
# @param Path path of the inf/dec/dsc/fdf/conf file
# @retval Ws the valid workspace relative to the specified file path
#
@classmethod
def getWs(cls, Ws, Path):
absPath = os.path.join(Ws, Path)
if not os.path.exists(absPath):
for Pkg in cls.PACKAGES_PATH:
absPath = os.path.join(Pkg, Path)
if os.path.exists(absPath):
return Pkg
return Ws
## handleWsMacro()
#
# handle the $(WORKSPACE) tag, if current workspace is invalid path relative the tool, replace it.
#
# @param cls The class pointer
# @retval PathStr Path string include the $(WORKSPACE)
#
@classmethod
def handleWsMacro(cls, PathStr):
if TAB_WORKSPACE in PathStr:
Path = PathStr.replace(TAB_WORKSPACE, cls.WORKSPACE).strip()
if not os.path.exists(Path):
for Pkg in cls.PACKAGES_PATH:
Path = PathStr.replace(TAB_WORKSPACE, Pkg).strip()
if os.path.exists(Path):
return Path
return PathStr
## getPkgPath()
#
# get all package pathes.
#
# @param cls The class pointer
#
@classmethod
def getPkgPath(cls):
return cls.PACKAGES_PATH

View File

@ -24,6 +24,7 @@ import GlobalData
from BuildToolError import *
from CommonDataClass.Exceptions import *
from Common.LongFilePathSupport import OpenLongFilePath as open
from Common.MultipleWorkspace import MultipleWorkspace as mws
gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE)
gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')
@ -305,6 +306,11 @@ def NormPath(Path, Defines={}):
# To local path format
#
Path = os.path.normpath(Path)
if Path.startswith(GlobalData.gWorkspace) and not os.path.exists(Path):
Path = Path[len (GlobalData.gWorkspace):]
if Path[0] == os.path.sep:
Path = Path[1:]
Path = mws.join(GlobalData.gWorkspace, Path)
if IsRelativePath and Path[0] != '.':
Path = os.path.join('.', Path)
@ -702,7 +708,7 @@ def RaiseParserError(Line, Section, File, Format='', LineNo= -1):
# @retval string A full path
#
def WorkspaceFile(WorkspaceDir, Filename):
return os.path.join(NormPath(WorkspaceDir), NormPath(Filename))
return mws.join(NormPath(WorkspaceDir), NormPath(Filename))
## Split string
#