Brett Chabot | 8ac5118 | 2012-09-19 07:35:35 -0700 | [diff] [blame] | 1 | # |
| 2 | # Copyright 2012, The Android Open Source Project |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | """Data structure for processing makefiles.""" |
| 17 | |
| 18 | import os |
| 19 | |
| 20 | import android_build |
| 21 | import android_mk |
| 22 | import errors |
| 23 | |
| 24 | class MakeNode(object): |
| 25 | """Represents single node in make tree.""" |
| 26 | |
| 27 | def __init__(self, name, parent): |
| 28 | self._name = name |
| 29 | self._children_map = {} |
| 30 | self._is_leaf = False |
| 31 | self._parent = parent |
| 32 | self._includes_submake = None |
| 33 | if parent: |
| 34 | self._path = os.path.join(parent._GetPath(), name) |
| 35 | else: |
| 36 | self._path = "" |
| 37 | |
| 38 | def _AddPath(self, path_segs): |
| 39 | """Adds given path to this node. |
| 40 | |
| 41 | Args: |
| 42 | path_segs: list of path segments |
| 43 | """ |
| 44 | if not path_segs: |
| 45 | # done processing path |
| 46 | return self |
| 47 | current_seg = path_segs.pop(0) |
| 48 | child = self._children_map.get(current_seg) |
| 49 | if not child: |
| 50 | child = MakeNode(current_seg, self) |
| 51 | self._children_map[current_seg] = child |
| 52 | return child._AddPath(path_segs) |
| 53 | |
| 54 | def _SetLeaf(self, is_leaf): |
| 55 | self._is_leaf = is_leaf |
| 56 | |
| 57 | def _GetPath(self): |
| 58 | return self._path |
| 59 | |
| 60 | def _DoesIncludesSubMake(self): |
| 61 | if self._includes_submake is None: |
| 62 | if self._is_leaf: |
| 63 | path = os.path.join(android_build.GetTop(), self._path) |
| 64 | mk_parser = android_mk.CreateAndroidMK(path) |
| 65 | self._includes_submake = mk_parser.IncludesMakefilesUnder() |
| 66 | else: |
| 67 | self._includes_submake = False |
| 68 | return self._includes_submake |
| 69 | |
| 70 | def _DoesParentIncludeMe(self): |
| 71 | return self._parent and self._parent._DoesIncludesSubMake() |
| 72 | |
| 73 | def _BuildPrunedMakeList(self, make_list): |
| 74 | if self._is_leaf and not self._DoesParentIncludeMe(): |
| 75 | make_list.append(os.path.join(self._path, "Android.mk")) |
| 76 | for child in self._children_map.itervalues(): |
| 77 | child._BuildPrunedMakeList(make_list) |
| 78 | |
| 79 | |
| 80 | class MakeTree(MakeNode): |
| 81 | """Data structure for building a non-redundant set of Android.mk paths. |
| 82 | |
| 83 | Used to collapse set of Android.mk files to use to prevent issuing make |
| 84 | command that include same module multiple times due to include rules. |
| 85 | """ |
| 86 | |
| 87 | def __init__(self): |
| 88 | super(MakeTree, self).__init__("", None) |
| 89 | |
| 90 | def AddPath(self, path): |
| 91 | """Adds make directory path to tree. |
| 92 | |
| 93 | Will have no effect if path is already included in make set. |
| 94 | |
| 95 | Args: |
| 96 | path: filesystem path to directory to build, relative to build root. |
| 97 | """ |
| 98 | path = os.path.normpath(path) |
| 99 | mk_path = os.path.join(android_build.GetTop(), path, "Android.mk") |
| 100 | if not os.path.isfile(mk_path): |
| 101 | raise errors.AbortError("%s does not exist" % mk_path) |
| 102 | path_segs = path.split(os.sep) |
| 103 | child = self._AddPath(path_segs) |
| 104 | child._SetLeaf(True) |
| 105 | |
| 106 | def GetPrunedMakeList(self): |
| 107 | """Return as list of the minimum set of Android.mk files necessary to |
| 108 | build all leaf nodes in tree. |
| 109 | """ |
| 110 | make_list = [] |
| 111 | self._BuildPrunedMakeList(make_list) |
| 112 | return make_list |
| 113 | |
| 114 | def IsEmpty(self): |
| 115 | return not self._children_map |
| 116 | |