-
Notifications
You must be signed in to change notification settings - Fork 2
/
protoc.py
178 lines (139 loc) · 4.95 KB
/
protoc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
"""
Google's Protoc builder
Example, will produce c++ output files in the src directory.
protoc_cc = env.Protoc(["src/Example.proto"],
PROTOC_PATH='#src',
PROTOC_CCOUT='#src',
)
"""
import os
import SCons.Util
from SCons.Script import Builder, Action, Dir, File, Entry
def _detect(env):
"""Try to find the Protoc compiler"""
try:
return env['PROTOC']
except KeyError:
pass
protoc = env.WhereIs('protoc')
if protoc:
return protoc
raise SCons.Errors.StopError(
"Could not detect protoc Compiler")
def _protoc_emitter(target, source, env):
"""Process target, sources, and flags"""
# always ignore target
target = []
# suffix
protoc_suffix = env.subst('$PROTOC_SUFFIX')
protoc_h_suffix = env.subst('$PROTOC_HSUFFIX')
protoc_cc_suffix = env.subst('$PROTOC_CCSUFFIX')
protoc_py_suffix = env.subst('$PROTOC_PYSUFFIX')
protoc_java_suffix = env.subst('$PROTOC_JAVASUFFIX')
# fetch all protoc flags
if env['PROTOC_FLAGS']:
protocflags = env.subst("$PROTOC_FLAGS",
target=target, source=source)
flags = SCons.Util.CLVar(protocflags)
else:
flags = SCons.Util.CLVar('')
# flag --proto_path, -I
proto_path = []
if env['PROTOC_PATH']:
inc = env['PROTOC_PATH']
if SCons.Util.is_List(inc):
for path in inc:
path = Dir(path)
#print "path:",path
proto_path.append(path)
flags.append('--proto_path='+str(path.abspath))
elif SCons.Util.is_Scalar(inc):
path=Dir(inc)
#print "path:",path
proto_path.append(path)
flags.append('--proto_path='+str(path.abspath))
# flag --cpp_out
if env['PROTOC_CCOUT']:
env['PROTOC_CCOUT'] = Dir(env['PROTOC_CCOUT'])
flags.append('--cpp_out=${PROTOC_CCOUT.abspath}')
# flag --python_out
if env['PROTOC_PYOUT']:
env['PROTOC_PYOUT'] = Dir(env['PROTOC_PYOUT'])
flags.append('--python_out=${PROTOC_PYOUT.abspath}')
# flag --java_out
if env['PROTOC_JAVAOUT']:
env['PROTOC_JAVAOUT'] = Dir(env['PROTOC_JAVAOUT'])
flags.append('--java_out=${PROTOC_JAVAOUT.abspath}')
# updated flags
env['PROTOC_FLAGS'] = str(flags)
#print "flags:",flags
# source scons dirs
src_struct = Dir('#')
src_script = Dir('.').srcnode()
# produce proper targets
for src in source:
src = File(src)
# find proto_path for this source
longest_common = '/'
for path in proto_path:
common = os.path.commonprefix([path.abspath, src.abspath])
if len(common) > len(longest_common):
longest_common = common
#print "longest_common:",longest_common
src_relpath = os.path.relpath(src.abspath, start=longest_common)
#print "src_relpath:",src_relpath
# create stem by remove the $PROTOC_SUFFIX or take a guess
if src_relpath.endswith(protoc_suffix):
stem = src_relpath[:-len(protoc_suffix)]
else:
stem = src_relpath
# C++ output, append
if env['PROTOC_CCOUT']:
out = Dir(env['PROTOC_CCOUT'])
base = os.path.join(out.abspath, stem)
target.append(File(base+protoc_cc_suffix))
target.append(File(base+protoc_h_suffix))
# python output, append
if env['PROTOC_PYOUT']:
out = Dir(env['PROTOC_PYOUT'])
base = os.path.join(out.abspath, stem)
target.append(File(base+protoc_py_suffix))
# java output, append
if env['PROTOC_JAVAOUT']:
out = Dir(env['PROTOC_JAVAOUT'])
base = os.path.join(out.abspath, stem)
target.append(File(base+protoc_java_suffix))
#print "targets:",env.subst("${TARGETS}", target=target, source=source)
#print "sources:",env.subst("${SOURCES}", target=target, source=source)
return target, source
_protoc_builder = Builder(
action = Action('$PROTOC_COM', '$PROTOC_COMSTR'),
suffix = '$PROTOC_CCSUFFIX',
src_suffix = '$PROTOC_SUFFIX',
emitter = _protoc_emitter,
)
def generate(env):
"""Add Builders and construction variables."""
env['PROTOC'] = _detect(env)
env.SetDefault(
# Additional command-line flags
PROTOC_FLAGS = SCons.Util.CLVar(''),
# Source path(s)
PROTOC_PATH = SCons.Util.CLVar(''),
# Output path
PROTOC_CCOUT = '',
PROTOC_PYOUT = '',
PROTOC_JAVAOUT = '',
# Suffixies / prefixes
PROTOC_SUFFIX = '.proto',
PROTOC_HSUFFIX = '.pb.h',
PROTOC_CCSUFFIX = '.pb.cc',
PROTOC_PYSUFFIX = '_pb2.py',
PROTOC_JAVASUFFIX = '.java',
# Protoc command
PROTOC_COM = "$PROTOC $PROTOC_FLAGS $SOURCES.abspath",
PROTOC_COMSTR = '',
)
env['BUILDERS']['Protoc'] = _protoc_builder
def exists(env):
return _detect(env)