xref: /aosp_15_r20/external/angle/third_party/abseil-cpp/absl/abseil.podspec.gen.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*8975f5c5SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
3*8975f5c5SAndroid Build Coastguard Worker"""This script generates abseil.podspec from all BUILD.bazel files.
4*8975f5c5SAndroid Build Coastguard Worker
5*8975f5c5SAndroid Build Coastguard WorkerThis is expected to run on abseil git repository with Bazel 1.0 on Linux.
6*8975f5c5SAndroid Build Coastguard WorkerIt recursively analyzes BUILD.bazel files using query command of Bazel to
7*8975f5c5SAndroid Build Coastguard Workerdump its build rules in XML format. From these rules, it constructs podspec
8*8975f5c5SAndroid Build Coastguard Workerstructure.
9*8975f5c5SAndroid Build Coastguard Worker"""
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Workerimport argparse
12*8975f5c5SAndroid Build Coastguard Workerimport collections
13*8975f5c5SAndroid Build Coastguard Workerimport os
14*8975f5c5SAndroid Build Coastguard Workerimport re
15*8975f5c5SAndroid Build Coastguard Workerimport subprocess
16*8975f5c5SAndroid Build Coastguard Workerimport xml.etree.ElementTree
17*8975f5c5SAndroid Build Coastguard Worker
18*8975f5c5SAndroid Build Coastguard Worker# Template of root podspec.
19*8975f5c5SAndroid Build Coastguard WorkerSPEC_TEMPLATE = """
20*8975f5c5SAndroid Build Coastguard Worker# This file has been automatically generated from a script.
21*8975f5c5SAndroid Build Coastguard Worker# Please make modifications to `abseil.podspec.gen.py` instead.
22*8975f5c5SAndroid Build Coastguard WorkerPod::Spec.new do |s|
23*8975f5c5SAndroid Build Coastguard Worker  s.name     = 'abseil'
24*8975f5c5SAndroid Build Coastguard Worker  s.version  = '${version}'
25*8975f5c5SAndroid Build Coastguard Worker  s.summary  = 'Abseil Common Libraries (C++) from Google'
26*8975f5c5SAndroid Build Coastguard Worker  s.homepage = 'https://abseil.io'
27*8975f5c5SAndroid Build Coastguard Worker  s.license  = 'Apache License, Version 2.0'
28*8975f5c5SAndroid Build Coastguard Worker  s.authors  = { 'Abseil Team' => '[email protected]' }
29*8975f5c5SAndroid Build Coastguard Worker  s.source = {
30*8975f5c5SAndroid Build Coastguard Worker    :git => 'https://github.com/abseil/abseil-cpp.git',
31*8975f5c5SAndroid Build Coastguard Worker    :tag => '${tag}',
32*8975f5c5SAndroid Build Coastguard Worker  }
33*8975f5c5SAndroid Build Coastguard Worker  s.resource_bundles = {
34*8975f5c5SAndroid Build Coastguard Worker    s.module_name => 'PrivacyInfo.xcprivacy',
35*8975f5c5SAndroid Build Coastguard Worker  }
36*8975f5c5SAndroid Build Coastguard Worker  s.module_name = 'absl'
37*8975f5c5SAndroid Build Coastguard Worker  s.header_mappings_dir = 'absl'
38*8975f5c5SAndroid Build Coastguard Worker  s.header_dir = 'absl'
39*8975f5c5SAndroid Build Coastguard Worker  s.libraries = 'c++'
40*8975f5c5SAndroid Build Coastguard Worker  s.compiler_flags = '-Wno-everything'
41*8975f5c5SAndroid Build Coastguard Worker  s.pod_target_xcconfig = {
42*8975f5c5SAndroid Build Coastguard Worker    'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"',
43*8975f5c5SAndroid Build Coastguard Worker    'USE_HEADERMAP' => 'NO',
44*8975f5c5SAndroid Build Coastguard Worker    'ALWAYS_SEARCH_USER_PATHS' => 'NO',
45*8975f5c5SAndroid Build Coastguard Worker  }
46*8975f5c5SAndroid Build Coastguard Worker  s.ios.deployment_target = '9.0'
47*8975f5c5SAndroid Build Coastguard Worker  s.osx.deployment_target = '10.11'
48*8975f5c5SAndroid Build Coastguard Worker  s.tvos.deployment_target = '9.0'
49*8975f5c5SAndroid Build Coastguard Worker  s.watchos.deployment_target = '2.0'
50*8975f5c5SAndroid Build Coastguard Worker  s.subspec 'xcprivacy' do |ss|
51*8975f5c5SAndroid Build Coastguard Worker    ss.resource_bundles = {
52*8975f5c5SAndroid Build Coastguard Worker      ss.module_name => 'PrivacyInfo.xcprivacy',
53*8975f5c5SAndroid Build Coastguard Worker    }
54*8975f5c5SAndroid Build Coastguard Worker  end
55*8975f5c5SAndroid Build Coastguard Worker"""
56*8975f5c5SAndroid Build Coastguard Worker
57*8975f5c5SAndroid Build Coastguard Worker# Rule object representing the rule of Bazel BUILD.
58*8975f5c5SAndroid Build Coastguard WorkerRule = collections.namedtuple(
59*8975f5c5SAndroid Build Coastguard Worker    "Rule", "type name package srcs hdrs textual_hdrs deps visibility testonly")
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Worker
62*8975f5c5SAndroid Build Coastguard Workerdef get_elem_value(elem, name):
63*8975f5c5SAndroid Build Coastguard Worker  """Returns the value of XML element with the given name."""
64*8975f5c5SAndroid Build Coastguard Worker  for child in elem:
65*8975f5c5SAndroid Build Coastguard Worker    if child.attrib.get("name") != name:
66*8975f5c5SAndroid Build Coastguard Worker      continue
67*8975f5c5SAndroid Build Coastguard Worker    if child.tag == "string":
68*8975f5c5SAndroid Build Coastguard Worker      return child.attrib.get("value")
69*8975f5c5SAndroid Build Coastguard Worker    if child.tag == "boolean":
70*8975f5c5SAndroid Build Coastguard Worker      return child.attrib.get("value") == "true"
71*8975f5c5SAndroid Build Coastguard Worker    if child.tag == "list":
72*8975f5c5SAndroid Build Coastguard Worker      return [nested_child.attrib.get("value") for nested_child in child]
73*8975f5c5SAndroid Build Coastguard Worker    raise "Cannot recognize tag: " + child.tag
74*8975f5c5SAndroid Build Coastguard Worker  return None
75*8975f5c5SAndroid Build Coastguard Worker
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Workerdef normalize_paths(paths):
78*8975f5c5SAndroid Build Coastguard Worker  """Returns the list of normalized path."""
79*8975f5c5SAndroid Build Coastguard Worker  # e.g. ["//absl/strings:dir/header.h"] -> ["absl/strings/dir/header.h"]
80*8975f5c5SAndroid Build Coastguard Worker  return [path.lstrip("/").replace(":", "/") for path in paths]
81*8975f5c5SAndroid Build Coastguard Worker
82*8975f5c5SAndroid Build Coastguard Worker
83*8975f5c5SAndroid Build Coastguard Workerdef parse_rule(elem, package):
84*8975f5c5SAndroid Build Coastguard Worker  """Returns a rule from bazel XML rule."""
85*8975f5c5SAndroid Build Coastguard Worker  return Rule(
86*8975f5c5SAndroid Build Coastguard Worker      type=elem.attrib["class"],
87*8975f5c5SAndroid Build Coastguard Worker      name=get_elem_value(elem, "name"),
88*8975f5c5SAndroid Build Coastguard Worker      package=package,
89*8975f5c5SAndroid Build Coastguard Worker      srcs=normalize_paths(get_elem_value(elem, "srcs") or []),
90*8975f5c5SAndroid Build Coastguard Worker      hdrs=normalize_paths(get_elem_value(elem, "hdrs") or []),
91*8975f5c5SAndroid Build Coastguard Worker      textual_hdrs=normalize_paths(get_elem_value(elem, "textual_hdrs") or []),
92*8975f5c5SAndroid Build Coastguard Worker      deps=get_elem_value(elem, "deps") or [],
93*8975f5c5SAndroid Build Coastguard Worker      visibility=get_elem_value(elem, "visibility") or [],
94*8975f5c5SAndroid Build Coastguard Worker      testonly=get_elem_value(elem, "testonly") or False)
95*8975f5c5SAndroid Build Coastguard Worker
96*8975f5c5SAndroid Build Coastguard Worker
97*8975f5c5SAndroid Build Coastguard Workerdef read_build(package):
98*8975f5c5SAndroid Build Coastguard Worker  """Runs bazel query on given package file and returns all cc rules."""
99*8975f5c5SAndroid Build Coastguard Worker  result = subprocess.check_output(
100*8975f5c5SAndroid Build Coastguard Worker      ["bazel", "query", package + ":all", "--output", "xml"])
101*8975f5c5SAndroid Build Coastguard Worker  root = xml.etree.ElementTree.fromstring(result)
102*8975f5c5SAndroid Build Coastguard Worker  return [
103*8975f5c5SAndroid Build Coastguard Worker      parse_rule(elem, package)
104*8975f5c5SAndroid Build Coastguard Worker      for elem in root
105*8975f5c5SAndroid Build Coastguard Worker      if elem.tag == "rule" and elem.attrib["class"].startswith("cc_")
106*8975f5c5SAndroid Build Coastguard Worker  ]
107*8975f5c5SAndroid Build Coastguard Worker
108*8975f5c5SAndroid Build Coastguard Worker
109*8975f5c5SAndroid Build Coastguard Workerdef collect_rules(root_path):
110*8975f5c5SAndroid Build Coastguard Worker  """Collects and returns all rules from root path recursively."""
111*8975f5c5SAndroid Build Coastguard Worker  rules = []
112*8975f5c5SAndroid Build Coastguard Worker  for cur, _, _ in os.walk(root_path):
113*8975f5c5SAndroid Build Coastguard Worker    build_path = os.path.join(cur, "BUILD.bazel")
114*8975f5c5SAndroid Build Coastguard Worker    if os.path.exists(build_path):
115*8975f5c5SAndroid Build Coastguard Worker      rules.extend(read_build("//" + cur))
116*8975f5c5SAndroid Build Coastguard Worker  return rules
117*8975f5c5SAndroid Build Coastguard Worker
118*8975f5c5SAndroid Build Coastguard Worker
119*8975f5c5SAndroid Build Coastguard Workerdef relevant_rule(rule):
120*8975f5c5SAndroid Build Coastguard Worker  """Returns true if a given rule is relevant when generating a podspec."""
121*8975f5c5SAndroid Build Coastguard Worker  return (
122*8975f5c5SAndroid Build Coastguard Worker      # cc_library only (ignore cc_test, cc_binary)
123*8975f5c5SAndroid Build Coastguard Worker      rule.type == "cc_library" and
124*8975f5c5SAndroid Build Coastguard Worker      # ignore empty rule
125*8975f5c5SAndroid Build Coastguard Worker      (rule.hdrs + rule.textual_hdrs + rule.srcs) and
126*8975f5c5SAndroid Build Coastguard Worker      # ignore test-only rule
127*8975f5c5SAndroid Build Coastguard Worker      not rule.testonly)
128*8975f5c5SAndroid Build Coastguard Worker
129*8975f5c5SAndroid Build Coastguard Worker
130*8975f5c5SAndroid Build Coastguard Workerdef get_spec_var(depth):
131*8975f5c5SAndroid Build Coastguard Worker  """Returns the name of variable for spec with given depth."""
132*8975f5c5SAndroid Build Coastguard Worker  return "s" if depth == 0 else "s{}".format(depth)
133*8975f5c5SAndroid Build Coastguard Worker
134*8975f5c5SAndroid Build Coastguard Worker
135*8975f5c5SAndroid Build Coastguard Workerdef get_spec_name(label):
136*8975f5c5SAndroid Build Coastguard Worker  """Converts the label of bazel rule to the name of podspec."""
137*8975f5c5SAndroid Build Coastguard Worker  assert label.startswith("//absl/"), "{} doesn't start with //absl/".format(
138*8975f5c5SAndroid Build Coastguard Worker      label)
139*8975f5c5SAndroid Build Coastguard Worker  # e.g. //absl/apple/banana -> abseil/apple/banana
140*8975f5c5SAndroid Build Coastguard Worker  return "abseil/" + label[7:]
141*8975f5c5SAndroid Build Coastguard Worker
142*8975f5c5SAndroid Build Coastguard Worker
143*8975f5c5SAndroid Build Coastguard Workerdef write_podspec(f, rules, args):
144*8975f5c5SAndroid Build Coastguard Worker  """Writes a podspec from given rules and args."""
145*8975f5c5SAndroid Build Coastguard Worker  rule_dir = build_rule_directory(rules)["abseil"]
146*8975f5c5SAndroid Build Coastguard Worker  # Write root part with given arguments
147*8975f5c5SAndroid Build Coastguard Worker  spec = re.sub(r"\$\{(\w+)\}", lambda x: args[x.group(1)],
148*8975f5c5SAndroid Build Coastguard Worker                SPEC_TEMPLATE).lstrip()
149*8975f5c5SAndroid Build Coastguard Worker  f.write(spec)
150*8975f5c5SAndroid Build Coastguard Worker  # Write all target rules
151*8975f5c5SAndroid Build Coastguard Worker  write_podspec_map(f, rule_dir, 0)
152*8975f5c5SAndroid Build Coastguard Worker  f.write("end\n")
153*8975f5c5SAndroid Build Coastguard Worker
154*8975f5c5SAndroid Build Coastguard Worker
155*8975f5c5SAndroid Build Coastguard Workerdef build_rule_directory(rules):
156*8975f5c5SAndroid Build Coastguard Worker  """Builds a tree-style rule directory from given rules."""
157*8975f5c5SAndroid Build Coastguard Worker  rule_dir = {}
158*8975f5c5SAndroid Build Coastguard Worker  for rule in rules:
159*8975f5c5SAndroid Build Coastguard Worker    cur = rule_dir
160*8975f5c5SAndroid Build Coastguard Worker    for frag in get_spec_name(rule.package).split("/"):
161*8975f5c5SAndroid Build Coastguard Worker      cur = cur.setdefault(frag, {})
162*8975f5c5SAndroid Build Coastguard Worker    cur[rule.name] = rule
163*8975f5c5SAndroid Build Coastguard Worker  return rule_dir
164*8975f5c5SAndroid Build Coastguard Worker
165*8975f5c5SAndroid Build Coastguard Worker
166*8975f5c5SAndroid Build Coastguard Workerdef write_podspec_map(f, cur_map, depth):
167*8975f5c5SAndroid Build Coastguard Worker  """Writes podspec from rule map recursively."""
168*8975f5c5SAndroid Build Coastguard Worker  for key, value in sorted(cur_map.items()):
169*8975f5c5SAndroid Build Coastguard Worker    indent = "  " * (depth + 1)
170*8975f5c5SAndroid Build Coastguard Worker    f.write("{indent}{var0}.subspec '{key}' do |{var1}|\n".format(
171*8975f5c5SAndroid Build Coastguard Worker        indent=indent,
172*8975f5c5SAndroid Build Coastguard Worker        key=key,
173*8975f5c5SAndroid Build Coastguard Worker        var0=get_spec_var(depth),
174*8975f5c5SAndroid Build Coastguard Worker        var1=get_spec_var(depth + 1)))
175*8975f5c5SAndroid Build Coastguard Worker    if isinstance(value, dict):
176*8975f5c5SAndroid Build Coastguard Worker      write_podspec_map(f, value, depth + 1)
177*8975f5c5SAndroid Build Coastguard Worker    else:
178*8975f5c5SAndroid Build Coastguard Worker      write_podspec_rule(f, value, depth + 1)
179*8975f5c5SAndroid Build Coastguard Worker    f.write("{indent}end\n".format(indent=indent))
180*8975f5c5SAndroid Build Coastguard Worker
181*8975f5c5SAndroid Build Coastguard Worker
182*8975f5c5SAndroid Build Coastguard Workerdef write_podspec_rule(f, rule, depth):
183*8975f5c5SAndroid Build Coastguard Worker  """Writes podspec from given rule."""
184*8975f5c5SAndroid Build Coastguard Worker  indent = "  " * (depth + 1)
185*8975f5c5SAndroid Build Coastguard Worker  spec_var = get_spec_var(depth)
186*8975f5c5SAndroid Build Coastguard Worker  # Puts all files in hdrs, textual_hdrs, and srcs into source_files.
187*8975f5c5SAndroid Build Coastguard Worker  # Since CocoaPods treats header_files a bit differently from bazel,
188*8975f5c5SAndroid Build Coastguard Worker  # this won't generate a header_files field so that all source_files
189*8975f5c5SAndroid Build Coastguard Worker  # are considered as header files.
190*8975f5c5SAndroid Build Coastguard Worker  srcs = sorted(set(rule.hdrs + rule.textual_hdrs + rule.srcs))
191*8975f5c5SAndroid Build Coastguard Worker  write_indented_list(
192*8975f5c5SAndroid Build Coastguard Worker      f, "{indent}{var}.source_files = ".format(indent=indent, var=spec_var),
193*8975f5c5SAndroid Build Coastguard Worker      srcs)
194*8975f5c5SAndroid Build Coastguard Worker  # Writes dependencies of this rule.
195*8975f5c5SAndroid Build Coastguard Worker  for dep in sorted(rule.deps):
196*8975f5c5SAndroid Build Coastguard Worker    name = get_spec_name(dep.replace(":", "/"))
197*8975f5c5SAndroid Build Coastguard Worker    f.write("{indent}{var}.dependency '{dep}'\n".format(
198*8975f5c5SAndroid Build Coastguard Worker        indent=indent, var=spec_var, dep=name))
199*8975f5c5SAndroid Build Coastguard Worker  # Writes dependency to xcprivacy
200*8975f5c5SAndroid Build Coastguard Worker  f.write(
201*8975f5c5SAndroid Build Coastguard Worker      "{indent}{var}.dependency '{dep}'\n".format(
202*8975f5c5SAndroid Build Coastguard Worker          indent=indent, var=spec_var, dep="abseil/xcprivacy"
203*8975f5c5SAndroid Build Coastguard Worker      )
204*8975f5c5SAndroid Build Coastguard Worker  )
205*8975f5c5SAndroid Build Coastguard Worker
206*8975f5c5SAndroid Build Coastguard Worker
207*8975f5c5SAndroid Build Coastguard Workerdef write_indented_list(f, leading, values):
208*8975f5c5SAndroid Build Coastguard Worker  """Writes leading values in an indented style."""
209*8975f5c5SAndroid Build Coastguard Worker  f.write(leading)
210*8975f5c5SAndroid Build Coastguard Worker  f.write((",\n" + " " * len(leading)).join("'{}'".format(v) for v in values))
211*8975f5c5SAndroid Build Coastguard Worker  f.write("\n")
212*8975f5c5SAndroid Build Coastguard Worker
213*8975f5c5SAndroid Build Coastguard Worker
214*8975f5c5SAndroid Build Coastguard Workerdef generate(args):
215*8975f5c5SAndroid Build Coastguard Worker  """Generates a podspec file from all BUILD files under absl directory."""
216*8975f5c5SAndroid Build Coastguard Worker  rules = filter(relevant_rule, collect_rules("absl"))
217*8975f5c5SAndroid Build Coastguard Worker  with open(args.output, "wt") as f:
218*8975f5c5SAndroid Build Coastguard Worker    write_podspec(f, rules, vars(args))
219*8975f5c5SAndroid Build Coastguard Worker
220*8975f5c5SAndroid Build Coastguard Worker
221*8975f5c5SAndroid Build Coastguard Workerdef main():
222*8975f5c5SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
223*8975f5c5SAndroid Build Coastguard Worker      description="Generates abseil.podspec from BUILD.bazel")
224*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument(
225*8975f5c5SAndroid Build Coastguard Worker      "-v", "--version", help="The version of podspec", required=True)
226*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument(
227*8975f5c5SAndroid Build Coastguard Worker      "-t",
228*8975f5c5SAndroid Build Coastguard Worker      "--tag",
229*8975f5c5SAndroid Build Coastguard Worker      default=None,
230*8975f5c5SAndroid Build Coastguard Worker      help="The name of git tag (default: version)")
231*8975f5c5SAndroid Build Coastguard Worker  parser.add_argument(
232*8975f5c5SAndroid Build Coastguard Worker      "-o",
233*8975f5c5SAndroid Build Coastguard Worker      "--output",
234*8975f5c5SAndroid Build Coastguard Worker      default="abseil.podspec",
235*8975f5c5SAndroid Build Coastguard Worker      help="The name of output file (default: abseil.podspec)")
236*8975f5c5SAndroid Build Coastguard Worker  args = parser.parse_args()
237*8975f5c5SAndroid Build Coastguard Worker  if args.tag is None:
238*8975f5c5SAndroid Build Coastguard Worker    args.tag = args.version
239*8975f5c5SAndroid Build Coastguard Worker  generate(args)
240*8975f5c5SAndroid Build Coastguard Worker
241*8975f5c5SAndroid Build Coastguard Worker
242*8975f5c5SAndroid Build Coastguard Workerif __name__ == "__main__":
243*8975f5c5SAndroid Build Coastguard Worker  main()
244