BaseTools: Detect structure pcd header file change.
authorBobCF <bob.c.feng@intel.com>
Fri, 16 Mar 2018 09:40:00 +0000 (17:40 +0800)
committerLiming Gao <liming.gao@intel.com>
Sat, 17 Mar 2018 14:30:30 +0000 (22:30 +0800)
Detect structure pcd header file change

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
BaseTools/Source/Python/Workspace/DscBuildData.py

index 9c43dac..517385a 100644 (file)
@@ -95,6 +95,67 @@ MAKEROOT ?= $(EDK_TOOLS_PATH)/Source/C
 LIBS = -lCommon\r
 '''\r
 \r
+## Regular expression for finding header file inclusions\r
+from AutoGen.GenMake import gIncludePattern\r
+\r
+## Find dependencies for one source file\r
+#\r
+#  By searching recursively "#include" directive in file, find out all the\r
+#  files needed by given source file. The dependecies will be only searched\r
+#  in given search path list.\r
+#\r
+#   @param      SearchPathList  The list of search path\r
+#\r
+#   @retval     list            The list of files the given source file depends on\r
+#\r
+def GetDependencyList(FileStack,SearchPathList):\r
+    DepDb = dict()\r
+    DependencySet = set(FileStack)\r
+    while len(FileStack) > 0:\r
+        F = FileStack.pop()\r
+        FullPathDependList = []\r
+        CurrentFileDependencyList = []\r
+        if F in DepDb:\r
+            CurrentFileDependencyList = DepDb[F]\r
+        else:\r
+            try:\r
+                Fd = open(F, 'r')\r
+                FileContent = Fd.read()\r
+            except BaseException, X:\r
+                EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=F + "\n\t" + str(X))\r
+            finally:\r
+                if "Fd" in dir(locals()):\r
+                    Fd.close()\r
+\r
+            if len(FileContent) == 0:\r
+                continue\r
+\r
+            if FileContent[0] == 0xff or FileContent[0] == 0xfe:\r
+                FileContent = unicode(FileContent, "utf-16")\r
+            IncludedFileList = gIncludePattern.findall(FileContent)\r
+\r
+            for Inc in IncludedFileList:\r
+                Inc = Inc.strip()\r
+                Inc = os.path.normpath(Inc)\r
+                CurrentFileDependencyList.append(Inc)\r
+            DepDb[F] = CurrentFileDependencyList\r
+\r
+        CurrentFilePath = os.path.dirname(F)\r
+        PathList = [CurrentFilePath] + SearchPathList\r
+        for Inc in CurrentFileDependencyList:\r
+            for SearchPath in PathList:\r
+                FilePath = os.path.join(SearchPath, Inc)\r
+                if not os.path.exists(FilePath):\r
+                    continue\r
+                if FilePath not in DependencySet:\r
+                    FileStack.append(FilePath)\r
+                    FullPathDependList.append(FilePath)\r
+                break\r
+        DependencySet.update(FullPathDependList)\r
+    DependencyList = list(DependencySet)  # remove duplicate ones\r
+\r
+    return DependencyList\r
+\r
 class DscBuildData(PlatformBuildClassObject):\r
     # dict used to convert PCD type in database to string used by build tool\r
     _PCD_TYPE_STRING_ = {\r
@@ -1918,11 +1979,13 @@ class DscBuildData(PlatformBuildClassObject):
         CApp = PcdMainCHeader\r
 \r
         Includes = {}\r
+        IncludeFiles = set()\r
         for PcdName in StructuredPcds:\r
             Pcd = StructuredPcds[PcdName]\r
             for IncludeFile in Pcd.StructuredPcdIncludeFile:\r
                 if IncludeFile not in Includes:\r
                     Includes[IncludeFile] = True\r
+                    IncludeFiles.add(IncludeFile)\r
                     CApp = CApp + '#include <%s>\n' % (IncludeFile)\r
         CApp = CApp + '\n'\r
         for PcdName in StructuredPcds:\r
@@ -1981,6 +2044,7 @@ class DscBuildData(PlatformBuildClassObject):
             MakeApp = MakeApp + 'APPNAME = %s\n' % (PcdValueInitName) + 'OBJECTS = %s/%s.o\n' % (self.OutputPath, PcdValueInitName) + \\r
                       'include $(MAKEROOT)/Makefiles/app.makefile\n' + 'INCLUDE +='\r
 \r
+        IncSearchList = []\r
         PlatformInc = {}\r
         for Cache in self._Bdb._CACHE_.values():\r
             if Cache.MetaFile.Ext.lower() != '.dec':\r
@@ -2003,6 +2067,7 @@ class DscBuildData(PlatformBuildClassObject):
                 if pkg in PlatformInc:\r
                     for inc in PlatformInc[pkg]:\r
                         MakeApp += '-I'  + str(inc) + ' '\r
+                        IncSearchList.append(inc)\r
         MakeApp = MakeApp + '\n'\r
 \r
         CC_FLAGS = LinuxCFLAGS\r
@@ -2050,7 +2115,23 @@ class DscBuildData(PlatformBuildClassObject):
 \r
         if sys.platform == "win32":\r
             MakeApp = MakeApp + PcdMakefileEnd\r
+        MakeApp = MakeApp + '\n'\r
+        IncludeFileFullPaths = []\r
+        for includefile in IncludeFiles:\r
+            for includepath in IncSearchList:\r
+                includefullpath = os.path.join(str(includepath),includefile)\r
+                if os.path.exists(includefullpath):\r
+                    IncludeFileFullPaths.append(os.path.normpath(includefullpath))\r
+                    break\r
+        SearchPathList = []\r
+        SearchPathList.append(os.path.normpath(mws.join(GlobalData.gWorkspace, "BaseTools/Source/C/Include")))\r
+        SearchPathList.append(os.path.normpath(mws.join(GlobalData.gWorkspace, "BaseTools/Source/C/Common")))\r
+        SearchPathList.extend([str(item) for item in IncSearchList])\r
+        IncFileList = GetDependencyList(IncludeFileFullPaths,SearchPathList)\r
+        for include_file in IncFileList:\r
+            MakeApp += "$(OBJECTS) : %s\n" % include_file\r
         MakeFileName = os.path.join(self.OutputPath, 'Makefile')\r
+        MakeApp += "$(OBJECTS) : %s\n" % MakeFileName\r
         SaveFileOnChange(MakeFileName, MakeApp, False)\r
 \r
         InputValueFile = os.path.join(self.OutputPath, 'Input.txt')\r
@@ -2062,59 +2143,61 @@ class DscBuildData(PlatformBuildClassObject):
             PcdValueInitExe = os.path.join(os.getenv("EDK_TOOLS_PATH"), 'Source', 'C', 'bin', PcdValueInitName)\r
         else:\r
             PcdValueInitExe = os.path.join(os.getenv("EDK_TOOLS_PATH"), 'Bin', 'Win32', PcdValueInitName) +".exe"\r
-        if not os.path.exists(PcdValueInitExe) or self.NeedUpdateOutput(OutputValueFile, CAppBaseFileName + '.c',MakeFileName,InputValueFile):\r
-            Messages = ''\r
-            if sys.platform == "win32":\r
-                MakeCommand = 'nmake clean & nmake -f %s' % (MakeFileName)\r
-                returncode, StdOut, StdErr = self.ExecuteCommand (MakeCommand)\r
-                Messages = StdOut\r
-            else:\r
-                MakeCommand = 'make clean & make -f %s' % (MakeFileName)\r
-                returncode, StdOut, StdErr = self.ExecuteCommand (MakeCommand)\r
-                Messages = StdErr\r
-            Messages = Messages.split('\n')\r
-            MessageGroup = []\r
-            if returncode <>0:\r
-                CAppBaseFileName = os.path.join(self.OutputPath, PcdValueInitName)\r
-                File = open (CAppBaseFileName + '.c', 'r')\r
-                FileData = File.readlines()\r
-                File.close()\r
-                for Message in Messages:\r
-                    if " error" in Message or "warning" in Message:\r
-                        FileInfo = Message.strip().split('(')\r
-                        if len (FileInfo) > 1:\r
-                            FileName = FileInfo [0]\r
-                            FileLine = FileInfo [1].split (')')[0]\r
+\r
+        Messages = ''\r
+        if sys.platform == "win32":\r
+            MakeCommand = 'nmake -f %s' % (MakeFileName)\r
+            returncode, StdOut, StdErr = self.ExecuteCommand (MakeCommand)\r
+            Messages = StdOut\r
+        else:\r
+            MakeCommand = 'make -f %s' % (MakeFileName)\r
+            returncode, StdOut, StdErr = self.ExecuteCommand (MakeCommand)\r
+            Messages = StdErr\r
+        Messages = Messages.split('\n')\r
+        MessageGroup = []\r
+        if returncode <>0:\r
+            CAppBaseFileName = os.path.join(self.OutputPath, PcdValueInitName)\r
+            File = open (CAppBaseFileName + '.c', 'r')\r
+            FileData = File.readlines()\r
+            File.close()\r
+            for Message in Messages:\r
+                if " error" in Message or "warning" in Message:\r
+                    FileInfo = Message.strip().split('(')\r
+                    if len (FileInfo) > 1:\r
+                        FileName = FileInfo [0]\r
+                        FileLine = FileInfo [1].split (')')[0]\r
+                    else:\r
+                        FileInfo = Message.strip().split(':')\r
+                        FileName = FileInfo [0]\r
+                        FileLine = FileInfo [1]\r
+                    if FileLine.isdigit():\r
+                        error_line = FileData[int (FileLine) - 1]\r
+                        if r"//" in error_line:\r
+                            c_line,dsc_line = error_line.split(r"//")\r
                         else:\r
-                            FileInfo = Message.strip().split(':')\r
-                            FileName = FileInfo [0]\r
-                            FileLine = FileInfo [1]\r
-                        if FileLine.isdigit():\r
-                            error_line = FileData[int (FileLine) - 1]\r
-                            if r"//" in error_line:\r
-                                c_line,dsc_line = error_line.split(r"//")\r
-                            else:\r
-                                dsc_line = error_line\r
-                            message_itmes = Message.split(":")\r
-                            Index = 0\r
-                            if "PcdValueInit.c" not in Message:\r
-                                if not MessageGroup:\r
-                                    MessageGroup.append(Message)\r
-                                break\r
-                            else:\r
-                                for item in message_itmes:\r
-                                    if "PcdValueInit.c" in item:\r
-                                        Index = message_itmes.index(item)\r
-                                        message_itmes[Index] = dsc_line.strip()\r
-                                        break\r
-                                MessageGroup.append(":".join(message_itmes[Index:]).strip())\r
-                                continue\r
+                            dsc_line = error_line\r
+                        message_itmes = Message.split(":")\r
+                        Index = 0\r
+                        if "PcdValueInit.c" not in Message:\r
+                            if not MessageGroup:\r
+                                MessageGroup.append(Message)\r
+                            break\r
                         else:\r
-                            MessageGroup.append(Message)\r
-                if MessageGroup:\r
-                    EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "\n".join(MessageGroup) )\r
-                else:\r
-                    EdkLogger.error('Build', COMMAND_FAILURE, 'Can not execute command: %s' % MakeCommand)\r
+                            for item in message_itmes:\r
+                                if "PcdValueInit.c" in item:\r
+                                    Index = message_itmes.index(item)\r
+                                    message_itmes[Index] = dsc_line.strip()\r
+                                    break\r
+                            MessageGroup.append(":".join(message_itmes[Index:]).strip())\r
+                            continue\r
+                    else:\r
+                        MessageGroup.append(Message)\r
+            if MessageGroup:\r
+                EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "\n".join(MessageGroup) )\r
+            else:\r
+                EdkLogger.error('Build', COMMAND_FAILURE, 'Can not execute command: %s' % MakeCommand)\r
+\r
+        if self.NeedUpdateOutput(OutputValueFile, PcdValueInitExe ,InputValueFile):\r
             Command = PcdValueInitExe + ' -i %s -o %s' % (InputValueFile, OutputValueFile)\r
             returncode, StdOut, StdErr = self.ExecuteCommand (Command)\r
             if returncode <> 0:\r
@@ -2131,13 +2214,11 @@ class DscBuildData(PlatformBuildClassObject):
             StructurePcdSet.append((PcdInfo[0],PcdInfo[1], PcdInfo[2], PcdInfo[3], PcdValue[2].strip()))\r
         return StructurePcdSet\r
 \r
-    def NeedUpdateOutput(self,OutputFile, ValueCFile, MakeFile, StructureInput):\r
+    def NeedUpdateOutput(self,OutputFile, ValueCFile, StructureInput):\r
         if not os.path.exists(OutputFile):\r
             return True\r
         if os.stat(OutputFile).st_mtime <= os.stat(ValueCFile).st_mtime:\r
             return True\r
-        if os.stat(OutputFile).st_mtime <= os.stat(MakeFile).st_mtime:\r
-            return True\r
         if os.stat(OutputFile).st_mtime <= os.stat(StructureInput).st_mtime:\r
             return True\r
         return False\r