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