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


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:39