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:
@ -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
|
||||
#
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 = ''
|
||||
|
148
BaseTools/Source/Python/Common/MultipleWorkspace.py
Normal file
148
BaseTools/Source/Python/Common/MultipleWorkspace.py
Normal 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
|
||||
|
@ -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
|
||||
#
|
||||
|
Reference in New Issue
Block a user