Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: tools/protoc_wrapper/protoc_wrapper.py

Issue 2239383002: GN proto_libary refactoring. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nit Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """ 6 """
7 A simple wrapper for protoc. 7 A simple wrapper for protoc.
8 8 Script for //third_party/protobuf/proto_library.gni .
9 - Adds includes in generated headers. 9 Features:
10 - Handles building with system protobuf as an option. 10 - Inserts #include for extra header automatically.
11 - Prevents bad proto names.
11 """ 12 """
12 13
13 import fnmatch 14 from __future__ import print_function
14 import optparse 15 import argparse
15 import os.path 16 import os.path
16 import shutil
17 import subprocess 17 import subprocess
18 import sys 18 import sys
19 import tempfile 19 import tempfile
20 20
21 PROTOC_INCLUDE_POINT = '// @@protoc_insertion_point(includes)\n' 21 PROTOC_INCLUDE_POINT = "// @@protoc_insertion_point(includes)"
22
23 def ModifyHeader(header_file, extra_header):
24 """Adds |extra_header| to |header_file|. Returns 0 on success.
25
26 |extra_header| is the name of the header file to include.
27 |header_file| is a generated protobuf cpp header.
28 """
29 include_point_found = False
30 header_contents = []
31 with open(header_file) as f:
32 for line in f:
33 header_contents.append(line)
34 if line == PROTOC_INCLUDE_POINT:
35 extra_header_msg = '#include "%s"\n' % extra_header
36 header_contents.append(extra_header_msg)
37 include_point_found = True;
38 if not include_point_found:
39 return 1
40
41 with open(header_file, 'wb') as f:
42 f.write(''.join(header_contents))
43 return 0
44
45 def ScanForBadFiles(scan_root):
46 """Scan for bad file names, see http://crbug.com/386125 for details.
47 Returns True if any filenames are bad. Outputs errors to stderr.
48
49 |scan_root| is the path to the directory to be recursively scanned.
50 """
51 badname = False
52 real_scan_root = os.path.realpath(scan_root)
53 for dirpath, dirnames, filenames in os.walk(real_scan_root):
54 matches = fnmatch.filter(filenames, '*-*.proto')
55 if len(matches) > 0:
56 if not badname:
57 badname = True
58 sys.stderr.write('proto files must not have hyphens in their names ('
59 'see http://crbug.com/386125 for more information):\n')
60 for filename in matches:
61 sys.stderr.write(' ' + os.path.join(real_scan_root,
62 dirpath, filename) + '\n')
63 return badname
64 22
65 23
66 def RewriteProtoFilesForSystemProtobuf(path): 24 def FormatGeneratorOptions(options):
67 wrapper_dir = tempfile.mkdtemp() 25 if not options:
68 try: 26 return ""
69 for filename in os.listdir(path): 27 if options.endswith(":"):
70 if not filename.endswith('.proto'): 28 return options
71 continue 29 return options + ":"
72 with open(os.path.join(path, filename), 'r') as src_file:
73 with open(os.path.join(wrapper_dir, filename), 'w') as dst_file:
74 for line in src_file:
75 # Remove lines that break build with system protobuf.
76 # We cannot optimize for lite runtime, because system lite runtime
77 # does not have a Chromium-specific hack to retain unknown fields.
78 # Similarly, it does not understand corresponding option to control
79 # the usage of that hack.
80 if 'LITE_RUNTIME' in line or 'retain_unknown_fields' in line:
81 continue
82 dst_file.write(line)
83 30
84 return wrapper_dir 31
85 except: 32 def VerifyProtoNames(protos):
86 shutil.rmtree(wrapper_dir) 33 for filename in protos:
87 raise 34 if "-" in filename:
35 raise RuntimeError("Proto file names must not contents hyphens "
xyzzyz 2016/08/16 21:04:37 contain?
kraynov 2016/08/17 00:40:34 Done.
36 "(see http://crbug.com/386125 for more information).")
37
38
39 def StripProtoExtension(filename):
40 if not filename.endswith(".proto"):
41 raise RuntimeError("Invalid proto filename extension: "
42 "{0} .".format(filename))
43 return filename.rsplit(".", 1)[0]
44
45
46 def WriteIncludes(headers, include):
47 for filename in headers:
48 include_point_found = False
49 contents = []
50 with open(filename) as f:
51 for line in f:
52 stripped_line = line.strip()
53 contents.append(stripped_line)
54 if stripped_line == PROTOC_INCLUDE_POINT:
55 if include_point_found:
56 raise RuntimeException("Multiple include points found.")
57 include_point_found = True
58 extra_statement = "#include \"{0}\"".format(include)
59 contents.append(extra_statement)
60
61 if not include_point_found:
62 raise RuntimeError("Include point not found in header: "
63 "{0} .".format(filename))
64
65 with open(filename, "w") as f:
66 for line in contents:
67 print(line, file=f)
88 68
89 69
90 def main(argv): 70 def main(argv):
91 parser = optparse.OptionParser() 71 parser = argparse.ArgumentParser()
92 parser.add_option('--include', dest='extra_header', 72 parser.add_argument("--protoc",
93 help='The extra header to include. This must be specified ' 73 help="Relative path to compiler.")
94 'along with --protobuf.')
95 parser.add_option('--protobuf', dest='generated_header',
96 help='The c++ protobuf header to add the extra header to. '
97 'This must be specified along with --include.')
98 parser.add_option('--proto-in-dir',
99 help='The directory containing .proto files.')
100 parser.add_option('--proto-in-file', help='Input file to compile.')
101 parser.add_option('--use-system-protobuf', type=int, default=0,
102 help='Option to use system-installed protobuf '
103 'instead of bundled one.')
104 (options, args) = parser.parse_args(sys.argv)
105 if len(args) < 2:
106 return 1
107 74
108 if ScanForBadFiles(options.proto_in_dir): 75 parser.add_argument("--proto-in-dir",
109 return 1 76 help="Base directory with source protos.")
77 parser.add_argument("--cc-out-dir",
78 help="Output directory for standard C++ generator.")
79 parser.add_argument("--py-out-dir",
80 help="Output directory for standard Python generator.")
81 parser.add_argument("--plugin-out-dir",
82 help="Output directory for custom generator plugin.")
110 83
111 proto_path = options.proto_in_dir 84 parser.add_argument("--plugin",
112 if options.use_system_protobuf == 1: 85 help="Relative path to custom generator plugin.")
113 proto_path = RewriteProtoFilesForSystemProtobuf(proto_path) 86 parser.add_argument("--plugin-options",
114 try: 87 help="Custom generator plugin options.")
115 # Run what is hopefully protoc. 88 parser.add_argument("--cc-options",
116 protoc_args = args[1:] 89 help="Standard C++ generator options.")
117 protoc_args += ['--proto_path=%s' % proto_path, 90 parser.add_argument("--include",
118 os.path.join(proto_path, options.proto_in_file)] 91 help="Name of include to insert into generated headers.")
119 ret = subprocess.call(protoc_args)
120 if ret != 0:
121 return ret
122 finally:
123 if options.use_system_protobuf == 1:
124 # Remove temporary directory holding re-written files.
125 shutil.rmtree(proto_path)
126 92
127 # protoc succeeded, check to see if the generated cpp header needs editing. 93 parser.add_argument("protos", nargs="+",
128 if not options.extra_header or not options.generated_header: 94 help="Input protobuf definition file(s).")
129 return 0 95
130 return ModifyHeader(options.generated_header, options.extra_header) 96 options = parser.parse_args()
97
98 proto_dir = os.path.relpath(options.proto_in_dir)
99 protoc_cmd = [
100 os.path.realpath(options.protoc),
101 "--proto_path",
102 proto_dir
103 ]
104
105 protos = options.protos
106 headers = []
107 VerifyProtoNames(protos)
108
109 if options.cc_out_dir:
110 cc_out_dir = options.cc_out_dir
111 cc_options = FormatGeneratorOptions(options.cc_options)
112 protoc_cmd += [
113 "--cpp_out",
xyzzyz 2016/08/16 21:04:37 Can this protoc_cmd be a single line? Here and bel
kraynov 2016/08/17 00:40:34 Done.
114 cc_options + cc_out_dir
115 ]
116 for filename in protos:
117 stripped_name = StripProtoExtension(filename)
118 headers.append(os.path.join(cc_out_dir, stripped_name + ".pb.h"))
119
120 if options.py_out_dir:
121 protoc_cmd += [
122 "--python_out",
123 options.py_out_dir
124 ]
125
126 if options.plugin_out_dir:
127 plugin_options = FormatGeneratorOptions(options.plugin_options)
128 protoc_cmd += [
129 "--plugin",
130 "protoc-gen-plugin=" + os.path.relpath(options.plugin),
131 "--plugin_out",
132 plugin_options + options.plugin_out_dir,
133 ]
134
135 protoc_cmd += [os.path.join(proto_dir, name) for name in protos]
136 ret = subprocess.call(protoc_cmd)
137 if ret != 0:
138 raise RuntimeError("Protoc has returned non-zero status: "
139 "{0} .".format(ret))
140
141 if options.include:
142 WriteIncludes(headers, options.include)
131 143
132 144
133 if __name__ == '__main__': 145 if __name__ == "__main__":
134 sys.exit(main(sys.argv)) 146 try:
147 main(sys.argv)
148 except RuntimeError as e:
149 print(e, file=sys.stderr)
150 sys.exit(1)
OLDNEW
« third_party/protobuf/proto_library.gni ('K') | « third_party/protobuf/proto_library.gni ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698