]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/AutoGen/AutoGen.py
BaseTools: Fix the bug for CArray PCD override in command line
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / AutoGen.py
index c35f0b2fdb86e52699e393ae55954f7d3dfaad49..736c1ae976333f3b3c345866555f006929ae4efe 100644 (file)
@@ -42,6 +42,7 @@ from GenPcdDb import CreatePcdDatabaseCode
 from Workspace.MetaFileCommentParser import UsageList\r
 from Common.MultipleWorkspace import MultipleWorkspace as mws\r
 import InfSectionParser\r
+import datetime\r
 \r
 ## Regular expression for splitting Dependency Expression string into tokens\r
 gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)")\r
@@ -61,7 +62,10 @@ gMakeTypeMap = {"MSFT":"nmake", "GCC":"gmake"}
 \r
 \r
 ## Build rule configuration file\r
-gDefaultBuildRuleFile = 'Conf/build_rule.txt'\r
+gDefaultBuildRuleFile = 'build_rule.txt'\r
+\r
+## Tools definition configuration file\r
+gDefaultToolsDefFile = 'tools_def.txt'\r
 \r
 ## Build rule default version\r
 AutoGenReqBuildRuleVerNum = "0.1"\r
@@ -412,7 +416,7 @@ class WorkspaceAutoGen(AutoGen):
                             if HasTokenSpace:\r
                                 if (PcdItem.TokenCName, PcdItem.TokenSpaceGuidCName) == (TokenCName, TokenSpaceGuidCName):\r
                                     PcdDatumType = PcdItem.DatumType\r
-                                    NewValue = self._BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, pcdvalue)\r
+                                    NewValue = BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, pcdvalue)\r
                                     FoundFlag = True\r
                             else:\r
                                 if PcdItem.TokenCName == TokenCName:\r
@@ -421,7 +425,7 @@ class WorkspaceAutoGen(AutoGen):
                                             TokenSpaceGuidCNameList.append(PcdItem.TokenSpaceGuidCName)\r
                                             PcdDatumType = PcdItem.DatumType\r
                                             TokenSpaceGuidCName = PcdItem.TokenSpaceGuidCName\r
-                                            NewValue = self._BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, pcdvalue)\r
+                                            NewValue = BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, pcdvalue)\r
                                             FoundFlag = True\r
                                         else:\r
                                             EdkLogger.error(\r
@@ -500,6 +504,22 @@ class WorkspaceAutoGen(AutoGen):
                                 SourcePcdDict['FixedAtBuild'].append((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))\r
                 else:\r
                     pass\r
+            #\r
+            # A PCD can only use one type for all source modules\r
+            #\r
+            for i in SourcePcdDict_Keys:\r
+                for j in SourcePcdDict_Keys:\r
+                    if i != j:\r
+                        IntersectionList = list(set(SourcePcdDict[i]).intersection(set(SourcePcdDict[j])))\r
+                        if len(IntersectionList) > 0:\r
+                            EdkLogger.error(\r
+                            'build',\r
+                            FORMAT_INVALID,\r
+                            "Building modules from source INFs, following PCD use %s and %s access method. It must be corrected to use only one access method." % (i, j),\r
+                            ExtraData="%s" % '\n\t'.join([str(P[1]+'.'+P[0]) for P in IntersectionList])\r
+                            )\r
+                    else:\r
+                        pass\r
 \r
             #\r
             # intersection the BinaryPCD for Mixed PCD\r
@@ -640,33 +660,87 @@ class WorkspaceAutoGen(AutoGen):
         self._MakeFileDir = None\r
         self._BuildCommand = None\r
 \r
+        #\r
+        # Create BuildOptions Macro & PCD metafile.\r
+        #\r
+        content = 'gCommandLineDefines: '\r
+        content += str(GlobalData.gCommandLineDefines)\r
+        content += os.linesep\r
+        content += 'BuildOptionPcd: '\r
+        content += str(GlobalData.BuildOptionPcd)\r
+        SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False)\r
+\r
+        #\r
+        # Get set of workspace metafiles\r
+        #\r
+        AllWorkSpaceMetaFiles = self._GetMetaFiles(Target, Toolchain, Arch)\r
+\r
+        #\r
+        # Retrieve latest modified time of all metafiles\r
+        #\r
+        SrcTimeStamp = 0\r
+        for f in AllWorkSpaceMetaFiles:\r
+            if os.stat(f)[8] > SrcTimeStamp:\r
+                SrcTimeStamp = os.stat(f)[8]\r
+        self._SrcTimeStamp = SrcTimeStamp\r
+\r
+        #\r
+        # Write metafile list to build directory\r
+        #\r
+        AutoGenFilePath = os.path.join(self.BuildDir, 'AutoGen')\r
+        if os.path.exists (AutoGenFilePath):\r
+            os.remove(AutoGenFilePath)\r
+        if not os.path.exists(self.BuildDir):\r
+            os.makedirs(self.BuildDir)\r
+        with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file:\r
+            for f in AllWorkSpaceMetaFiles:\r
+                print >> file, f\r
         return True\r
 \r
-    def _BuildOptionPcdValueFormat(self, TokenSpaceGuidCName, TokenCName, PcdDatumType, Value):\r
-        if PcdDatumType == 'VOID*':\r
-            if Value.startswith('L'):\r
-                if not Value[1]:\r
-                    EdkLogger.error('build', OPTION_VALUE_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", B"{...}"')\r
-                Value = Value[0] + '"' + Value[1:] + '"'\r
-            elif Value.startswith('B'):\r
-                if not Value[1]:\r
-                    EdkLogger.error('build', OPTION_VALUE_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", B"{...}"')\r
-                Value = Value[1:]\r
-            else:\r
-                if not Value[0]:\r
-                    EdkLogger.error('build', OPTION_VALUE_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", B"{...}"')\r
-                Value = '"' + Value + '"'\r
-\r
-        IsValid, Cause = CheckPcdDatum(PcdDatumType, Value)\r
-        if not IsValid:\r
-            EdkLogger.error('build', FORMAT_INVALID, Cause, ExtraData="%s.%s" % (TokenSpaceGuidCName, TokenCName))\r
-        if PcdDatumType == 'BOOLEAN':\r
-            Value = Value.upper()\r
-            if Value == 'TRUE' or Value == '1':\r
-                Value = '1'\r
-            elif Value == 'FALSE' or Value == '0':\r
-                Value = '0'\r
-        return  Value\r
+\r
+    def _GetMetaFiles(self, Target, Toolchain, Arch):\r
+        AllWorkSpaceMetaFiles = set()\r
+        #\r
+        # add fdf\r
+        #\r
+        if self.FdfFile:\r
+            AllWorkSpaceMetaFiles.add (self.FdfFile.Path)\r
+            if self.FdfFile:\r
+                FdfFiles = GlobalData.gFdfParser.GetAllIncludedFile()\r
+                for f in FdfFiles:\r
+                    AllWorkSpaceMetaFiles.add (f.FileName)\r
+        #\r
+        # add dsc\r
+        #\r
+        AllWorkSpaceMetaFiles.add(self.MetaFile.Path)\r
+\r
+        #\r
+        # add build_rule.txt & tools_def.txt\r
+        #\r
+        AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultBuildRuleFile))\r
+        AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultToolsDefFile))\r
+\r
+        # add BuildOption metafile\r
+        #\r
+        AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions'))\r
+\r
+        for Arch in self.ArchList:\r
+            Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]\r
+            PGen = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)\r
+\r
+            #\r
+            # add dec\r
+            #\r
+            for Package in PGen.PackageList:\r
+                AllWorkSpaceMetaFiles.add(Package.MetaFile.Path)\r
+\r
+            #\r
+            # add included dsc\r
+            #\r
+            for filePath in Platform._RawData.IncludedFiles:\r
+                AllWorkSpaceMetaFiles.add(filePath.Path)\r
+\r
+        return AllWorkSpaceMetaFiles\r
 \r
     ## _CheckDuplicateInFV() method\r
     #\r
@@ -1718,7 +1792,10 @@ class PlatformAutoGen(AutoGen):
                         if self.BuildOption[Tool][Attr].startswith('='):\r
                             Value = self.BuildOption[Tool][Attr][1:]\r
                         else:\r
-                            Value += " " + self.BuildOption[Tool][Attr]\r
+                            if Attr != 'PATH':\r
+                                Value += " " + self.BuildOption[Tool][Attr]\r
+                            else:\r
+                                Value = self.BuildOption[Tool][Attr]\r
 \r
                     if Attr == "PATH":\r
                         # Don't put MAKE definition in the file\r
@@ -2381,8 +2458,11 @@ class PlatformAutoGen(AutoGen):
                         if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):\r
                             BuildOptions[Tool][Attr] = Options[Key]\r
                         else:\r
-                            # append options for the same tool\r
-                            BuildOptions[Tool][Attr] += " " + Options[Key]\r
+                            # append options for the same tool except PATH\r
+                            if Attr != 'PATH':\r
+                                BuildOptions[Tool][Attr] += " " + Options[Key]\r
+                            else:\r
+                                BuildOptions[Tool][Attr] = Options[Key]\r
         # Build Option Family has been checked, which need't to be checked again for family.\r
         if FamilyMatch or FamilyIsNull:\r
             return BuildOptions\r
@@ -2413,8 +2493,11 @@ class PlatformAutoGen(AutoGen):
                         if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):\r
                             BuildOptions[Tool][Attr] = Options[Key]\r
                         else:\r
-                            # append options for the same tool\r
-                            BuildOptions[Tool][Attr] += " " + Options[Key]\r
+                            # append options for the same tool except PATH\r
+                            if Attr != 'PATH':\r
+                                BuildOptions[Tool][Attr] += " " + Options[Key]\r
+                            else:\r
+                                BuildOptions[Tool][Attr] = Options[Key]\r
         return BuildOptions\r
 \r
     ## Append build options in platform to a module\r
@@ -2473,7 +2556,10 @@ class PlatformAutoGen(AutoGen):
                         BuildOptions[Tool][Attr] = ToolPath\r
                     else:\r
                         Value = mws.handleWsMacro(Value)\r
-                        BuildOptions[Tool][Attr] += " " + Value\r
+                        if Attr != 'PATH':\r
+                            BuildOptions[Tool][Attr] += " " + Value\r
+                        else:\r
+                            BuildOptions[Tool][Attr] = Value\r
         if Module.AutoGenVersion < 0x00010005 and self.Workspace.UniFlag != None:\r
             #\r
             # Override UNI flag only for EDK module.\r
@@ -2520,6 +2606,10 @@ class PlatformAutoGen(AutoGen):
 # to the [depex] section in module's inf file.\r
 #\r
 class ModuleAutoGen(AutoGen):\r
+    ## Cache the timestamps of metafiles of every module in a class variable\r
+    #\r
+    TimeDict = {}\r
+\r
     ## The real constructor of ModuleAutoGen\r
     #\r
     #  This method is not supposed to be called by users of ModuleAutoGen. It's\r
@@ -2620,6 +2710,11 @@ class ModuleAutoGen(AutoGen):
         self._FinalBuildTargetList    = None\r
         self._FileTypes               = None\r
         self._BuildRules              = None\r
+\r
+        self._TimeStampPath           = None\r
+\r
+        self.AutoGenDepSet = set()\r
+\r
         \r
         ## The Modules referenced to this Library\r
         #  Only Library has this attribute\r
@@ -2639,10 +2734,7 @@ class ModuleAutoGen(AutoGen):
         if self._FixedAtBuildPcds:\r
             return self._FixedAtBuildPcds\r
         for Pcd in self.ModulePcdList:\r
-            if self.IsLibrary:\r
-                if not (Pcd.Pending == False and Pcd.Type == "FixedAtBuild"):\r
-                    continue\r
-            elif Pcd.Type != "FixedAtBuild":\r
+            if Pcd.Type != "FixedAtBuild":\r
                 continue\r
             if Pcd not in self._FixedAtBuildPcds:\r
                 self._FixedAtBuildPcds.append(Pcd)\r
@@ -3821,6 +3913,13 @@ class ModuleAutoGen(AutoGen):
                 else:\r
                     continue\r
                 PcdValue = ''\r
+                if Pcd.DatumType == 'BOOLEAN':\r
+                    BoolValue = Pcd.DefaultValue.upper()\r
+                    if BoolValue == 'TRUE':\r
+                        Pcd.DefaultValue = '1'\r
+                    elif BoolValue == 'FALSE':\r
+                        Pcd.DefaultValue = '0'\r
+\r
                 if Pcd.DatumType != 'VOID*':\r
                     HexFormat = '0x%02x'\r
                     if Pcd.DatumType == 'UINT16':\r
@@ -3956,6 +4055,8 @@ class ModuleAutoGen(AutoGen):
 \r
         if self.IsMakeFileCreated:\r
             return\r
+        if self.CanSkip():\r
+            return\r
 \r
         if not self.IsLibrary and CreateLibraryMakeFile:\r
             for LibraryAutoGen in self.LibraryAutoGenList:\r
@@ -3972,6 +4073,7 @@ class ModuleAutoGen(AutoGen):
             EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %\r
                             (self.Name, self.Arch))\r
 \r
+        self.CreateTimeStamp(Makefile)\r
         self.IsMakeFileCreated = True\r
 \r
     def CopyBinaryFiles(self):\r
@@ -3987,6 +4089,8 @@ class ModuleAutoGen(AutoGen):
     def CreateCodeFile(self, CreateLibraryCodeFile=True):\r
         if self.IsCodeFileCreated:\r
             return\r
+        if self.CanSkip():\r
+            return\r
 \r
         # Need to generate PcdDatabase even PcdDriver is binarymodule\r
         if self.IsBinaryModule and self.PcdIsDriver != '':\r
@@ -4066,6 +4170,53 @@ class ModuleAutoGen(AutoGen):
                         self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)\r
         return self._LibraryAutoGenList\r
 \r
+    ## Decide whether we can skip the ModuleAutoGen process\r
+    #  If any source file is newer than the modeule than we cannot skip\r
+    #\r
+    def CanSkip(self):\r
+        if not os.path.exists(self.GetTimeStampPath()):\r
+            return False\r
+        #last creation time of the module\r
+        DstTimeStamp = os.stat(self.GetTimeStampPath())[8]\r
+\r
+        SrcTimeStamp = self.Workspace._SrcTimeStamp\r
+        if SrcTimeStamp > DstTimeStamp:\r
+            return False\r
+\r
+        with open(self.GetTimeStampPath(),'r') as f:\r
+            for source in f:\r
+                source = source.rstrip('\n')\r
+                if source not in ModuleAutoGen.TimeDict :\r
+                    ModuleAutoGen.TimeDict[source] = os.stat(source)[8]\r
+                if ModuleAutoGen.TimeDict[source] > DstTimeStamp:\r
+                    return False\r
+        return True\r
+\r
+    def GetTimeStampPath(self):\r
+        if self._TimeStampPath == None:\r
+            self._TimeStampPath = os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')\r
+        return self._TimeStampPath\r
+    def CreateTimeStamp(self, Makefile):\r
+\r
+        FileSet = set()\r
+\r
+        FileSet.add (self.MetaFile.Path)\r
+\r
+        for SourceFile in self.Module.Sources:\r
+            FileSet.add (SourceFile.Path)\r
+\r
+        for Lib in self.DependentLibraryList:\r
+            FileSet.add (Lib.MetaFile.Path)\r
+\r
+        for f in self.AutoGenDepSet:\r
+            FileSet.add (f.Path)\r
+\r
+        if os.path.exists (self.GetTimeStampPath()):\r
+            os.remove (self.GetTimeStampPath())\r
+        with open(self.GetTimeStampPath(), 'w+') as file:\r
+            for f in FileSet:\r
+                print >> file, f\r
+\r
     Module          = property(_GetModule)\r
     Name            = property(_GetBaseName)\r
     Guid            = property(_GetGuid)\r