21 import xml.etree.ElementTree
as ET
24 ABSEIL_PATH =
"third_party/abseil-cpp"
25 OUTPUT_PATH =
"src/abseil-cpp/preprocessed_builds.yaml"
26 CAPITAL_WORD = re.compile(
"[A-Z]+")
27 ABSEIL_CMAKE_RULE_BEGIN = re.compile(
"^absl_cc_.*\(", re.MULTILINE)
28 ABSEIL_CMAKE_RULE_END = re.compile(
"^\)", re.MULTILINE)
31 Rule = collections.namedtuple(
32 "Rule",
"type name package srcs hdrs textual_hdrs deps visibility testonly")
36 """Returns the value of XML element with the given name."""
38 if child.attrib.get(
"name") == name:
39 if child.tag ==
"string":
40 return child.attrib.get(
"value")
41 elif child.tag ==
"boolean":
42 return child.attrib.get(
"value") ==
"true"
43 elif child.tag ==
"list":
44 return [nested_child.attrib.get(
"value")
for nested_child
in child]
46 raise "Cannot recognize tag: " + child.tag
51 """Returns the list of normalized path."""
53 return [path.lstrip(
"/").replace(
":",
"/")
for path
in paths]
57 """Returns a rule from bazel XML rule."""
59 type=elem.attrib[
"class"],
71 """Runs bazel query on given package file and returns all cc rules."""
74 BAZEL_BIN =
"../../tools/bazel"
75 result = subprocess.check_output(
76 [BAZEL_BIN,
"query", package +
":all",
"--output",
"xml"])
77 root = ET.fromstring(result)
81 if elem.tag ==
"rule" and elem.attrib[
"class"].startswith(
"cc_")
86 """Collects and returns all bazel rules from root path recursively."""
88 for cur, _, _
in os.walk(root_path):
89 build_path = os.path.join(cur,
"BUILD.bazel")
90 if os.path.exists(build_path):
96 """Returns a rule from absl cmake rule.
97 Reference: https://github.com/abseil/abseil-cpp/blob/master/CMake/AbseilHelpers.cmake
101 lines = rule.splitlines()
102 for line
in lines[1:-1]:
103 if CAPITAL_WORD.match(line.strip()):
104 bucket = kv.setdefault(line.strip(), [])
106 if bucket
is not None:
107 bucket.append(line.strip())
109 raise ValueError(
"Illegal syntax: {}".
format(rule))
111 type=lines[0].rstrip(
"("),
112 name=
"absl::" + kv[
"NAME"][0],
114 srcs=[package +
"/" + f.strip(
'"')
for f
in kv.get(
"SRCS", [])],
115 hdrs=[package +
"/" + f.strip(
'"')
for f
in kv.get(
"HDRS", [])],
117 deps=kv.get(
"DEPS", []),
118 visibility=
"PUBLIC" in kv,
119 testonly=
"TESTONLY" in kv,
124 """Parses given CMakeLists.txt file and returns all cc rules."""
126 with open(build_path,
"r")
as f:
128 for begin_mo
in ABSEIL_CMAKE_RULE_BEGIN.finditer(src):
129 end_mo = ABSEIL_CMAKE_RULE_END.search(src[begin_mo.start(0):])
130 expr = src[begin_mo.start(0):begin_mo.start(0) + end_mo.start(0) + 1]
136 """Collects and returns all cmake rules from root path recursively."""
138 for cur, _, _
in os.walk(root_path):
139 build_path = os.path.join(cur,
"CMakeLists.txt")
140 if os.path.exists(build_path):
146 """Returns a pair map between bazel rules and cmake rules based on
147 the similarity of the file list in the rule. This is because
148 cmake build and bazel build of abseil are not identical.
151 for rule
in bazel_rules:
152 best_crule, best_similarity =
None, 0
153 for crule
in cmake_rules:
155 set(rule.srcs + rule.hdrs + rule.textual_hdrs).intersection(
156 set(crule.srcs + crule.hdrs + crule.textual_hdrs)))
157 if similarity > best_similarity:
158 best_crule, best_similarity = crule, similarity
160 pair_map[(rule.package, rule.name)] = best_crule.name
165 return [ABSEIL_PATH +
"/" + f
for f
in files
if f.endswith((
".h",
".inc"))]
169 return [ABSEIL_PATH +
"/" + f
for f
in files
if f.endswith(
".cc")]
173 return [(t[2:]
if t.startswith(
"//")
else t)
for t
in targets]
177 """Generates builds from all BUILD files under absl directory."""
179 filter(
lambda r: r.type ==
"cc_library" and not r.testonly,
182 filter(
lambda r: r.type ==
"absl_cc_library" and not r.testonly,
186 for rule
in sorted(bazel_rules, key=
lambda r: r.package[2:] +
":" + r.name):
189 rule.package[2:] +
":" + rule.name,
191 pair_map.get((rule.package, rule.name))
or "",
193 sorted(
resolve_hdrs(rule.srcs + rule.hdrs + rule.textual_hdrs)),
195 sorted(
resolve_srcs(rule.srcs + rule.hdrs + rule.textual_hdrs)),
204 previous_dir = os.getcwd()
205 os.chdir(ABSEIL_PATH)
207 os.chdir(previous_dir)
208 with open(OUTPUT_PATH,
'w')
as outfile:
209 outfile.write(yaml.dump(builds, indent=2))
212 if __name__ ==
"__main__":