Ok, I solved the issue without requiring the user to install a specific old version or compile the proto files on another platform than my dev machine. It's inspired by this setup.py script from protobuf itself.
Firstly, protoc needs to be found, this can be done using
# Find the Protocol Compiler.
if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
protoc = os.environ['PROTOC']
else:
protoc = find_executable("protoc")
This function will compile a .proto file and put the _pb2.py in the same spot. However, the behavior can be changed arbitrarily.
def generate_proto(source):
"""Invokes the Protocol Compiler to generate a _pb2.py from the given
.proto file. Does nothing if the output already exists and is newer than
the input."""
output = source.replace(".proto", "_pb2.py")
if (not os.path.exists(output) or
(os.path.exists(source) and
os.path.getmtime(source) > os.path.getmtime(output))):
print "Generating %s..." % output
if not os.path.exists(source):
sys.stderr.write("Can't find required file: %s
" % source)
sys.exit(-1)
if protoc == None:
sys.stderr.write(
"Protocol buffers compiler 'protoc' not installed or not found.
"
)
sys.exit(-1)
protoc_command = [ protoc, "-I.", "--python_out=.", source ]
if subprocess.call(protoc_command) != 0:
sys.exit(-1)
Next, the classes _build_py and _clean are derived to add building and cleaning up the protocol buffers.
# List of all .proto files
proto_src = ['file1.proto', 'path/to/file2.proto']
class build_py(_build_py):
def run(self):
for f in proto_src:
generate_proto(f)
_build_py.run(self)
class clean(_clean):
def run(self):
# Delete generated files in the code tree.
for (dirpath, dirnames, filenames) in os.walk("."):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
if filepath.endswith("_pb2.py"):
os.remove(filepath)
# _clean is an old-style class, so super() doesn't work.
_clean.run(self)
And finally, the parameter
cmdclass = { 'clean': clean, 'build_py': build_py }
needs to be added to the call to setup and everything should work. Still have to check for possible quirks, but so far it works flawlessly on the Mac and on the Pi.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…