Differences between revisions 7 and 8
Revision 7 as of 2013-07-27 09:59:35
Size: 4594
Editor: RusselWinder
Comment:
Revision 8 as of 2013-07-27 10:01:25
Size: 4594
Editor: RusselWinder
Comment:
Deletions are marked like this. Additions are marked like this.
Line 2: Line 2:
'''''Repositories under version control are the place for code rather than wiki pages, so a [[https://bitbucket.org/russel/scons_protobuf|Mercurial repository]] has been created on [[https://bitbucket.org/|BitBucket]] and copied the code from this page into it. The repository is where all evolution of this tool should happen. See also the [[http://scons.org/wiki/ToolsIndex|ToolsIndex]] page which has more on the tool strategy.''''' '''''Repositories under version control are the place for code rather than wiki pages, so a [[https://bitbucket.org/russel/scons_protobuf|Mercurial repository]] has been created on [[https://bitbucket.org/|BitBucket]] and the code from this page copied into it. The repository is where all evolution of this tool should happen. See also the [[http://scons.org/wiki/ToolsIndex|ToolsIndex]] page which has more on the tool strategy.'''''

Generating Protocol Buffers files with SCons

Repositories under version control are the place for code rather than wiki pages, so a Mercurial repository has been created on BitBucket and the code from this page copied into it. The repository is where all evolution of this tool should happen. See also the ToolsIndex page which has more on the tool strategy.

This builder will allow you to generate Google Protocol Buffers .pb.cc, .pb.h, and _pb2.py files using SCons from a .proto source file.

It doesn't currently support Java, but that should be easy to add.

Put this builder/tool file somewhere (next to the SConstruct file or in the Environment's 'toolpath', and call it 'protoc.py'.

   1 """
   2 protoc.py: Protoc Builder for SCons
   3 
   4 This Builder invokes protoc to generate C++ and Python
   5 from a .proto file.
   6 
   7 NOTE: Java is not currently supported."""
   8 
   9 __author__ = "Scott Stafford"
  10 
  11 import SCons.Action
  12 import SCons.Builder
  13 import SCons.Defaults
  14 import SCons.Node.FS
  15 import SCons.Util
  16 
  17 from SCons.Script import File, Dir
  18 
  19 import os.path
  20 
  21 protocs = 'protoc'
  22 
  23 ProtocAction = SCons.Action.Action('$PROTOCCOM', '$PROTOCCOMSTR')
  24 def ProtocEmitter(target, source, env):
  25     dirOfCallingSConscript = Dir('.').srcnode()
  26     env.Prepend(PROTOCPROTOPATH = dirOfCallingSConscript.path)
  27 
  28     source_with_corrected_path = []
  29     for src in source:
  30         commonprefix = os.path.commonprefix([dirOfCallingSConscript.path, src.srcnode().path])
  31         if len(commonprefix)>0:
  32             source_with_corrected_path.append( src.srcnode().path[len(commonprefix + os.sep):] )
  33         else:
  34             source_with_corrected_path.append( src.srcnode().path )
  35 
  36     source = source_with_corrected_path
  37 
  38     for src in source:
  39         modulename = os.path.splitext(src)[0]
  40 
  41         if env['PROTOCOUTDIR']:
  42             base = os.path.join(env['PROTOCOUTDIR'] , modulename)
  43             target.extend( [ base + '.pb.cc', base + '.pb.h' ] )
  44 
  45         if env['PROTOCPYTHONOUTDIR']:
  46             base = os.path.join(env['PROTOCPYTHONOUTDIR'] , modulename)
  47             target.append( base + '_pb2.py' )
  48 
  49     try:
  50         target.append(env['PROTOCFDSOUT'])
  51     except KeyError:
  52         pass
  53 
  54     #~ print "PROTOC SOURCE:", [str(s) for s in source]
  55     #~ print "PROTOC TARGET:", [str(s) for s in target]
  56 
  57     return target, source
  58 
  59 ProtocBuilder = SCons.Builder.Builder(action = ProtocAction,
  60                                    emitter = ProtocEmitter,
  61                                    srcsuffix = '$PROTOCSRCSUFFIX')
  62 
  63 def generate(env):
  64     """Add Builders and construction variables for protoc to an Environment."""
  65     try:
  66         bld = env['BUILDERS']['Protoc']
  67     except KeyError:
  68         bld = ProtocBuilder
  69         env['BUILDERS']['Protoc'] = bld
  70 
  71     env['PROTOC']        = env.Detect(protocs) or 'protoc'
  72     env['PROTOCFLAGS']   = SCons.Util.CLVar('')
  73     env['PROTOCPROTOPATH'] = SCons.Util.CLVar('')
  74     env['PROTOCCOM']     = '$PROTOC ${["-I%s"%x for x in PROTOCPROTOPATH]} $PROTOCFLAGS --cpp_out=$PROTOCCPPOUTFLAGS$PROTOCOUTDIR ${PROTOCPYTHONOUTDIR and ("--python_out="+PROTOCPYTHONOUTDIR) or ""} ${PROTOCFDSOUT and ("-o"+PROTOCFDSOUT) or ""} ${SOURCES}'
  75     env['PROTOCOUTDIR'] = '${SOURCE.dir}'
  76     env['PROTOCPYTHONOUTDIR'] = "python"
  77     env['PROTOCSRCSUFFIX']  = '.proto'
  78 
  79 def exists(env):
  80     return env.Detect(protocs)

Now you should have an env.Protoc() builder that takes .proto as source and emits generated protobuf source.

Here is a sample SConstruct I used (some MSVC/Windows-specific stuff, but the Protoc builder is OS-agnostic.) Note that you must make sure the protoc executable is available in your PATH or it won't be able to execute it.

   1 import os
   2 
   3 env = Environment(
   4     ENV = {'PATH' : os.environ['PATH']},
   5     CPPPATH = ['C:\wc\protobuf-trunk\src' ],
   6     CPPFLAGS = ['/EHsc', '/MDd'],
   7     tools=['default', 'protoc']
   8     )
   9 
  10 proto_files = env.Protoc(
  11     [],
  12     "config.proto",
  13     PROTOCPROTOPATH=['.',r'C:\wc\protobuf-trunk\src',],
  14     PROTOCPYTHONOUTDIR='python', # set to None to not generate python
  15     PROTOCOUTDIR = 'build', # defaults to same directory as .proto
  16     # PROTOCCPPOUTFLAGS = "dllexport_decl=PROTOCONFIG_EXPORT:", too
  17 )
  18 
  19 env.Program('test', ['test.cpp', proto_files[0]],
  20     LIBPATH=[r'C:\wc\protobuf-trunk\vsprojects\Debug'],
  21     LIBS=['libprotobuf.lib'],
  22     )

-- ScottStafford

ProtocBuilder (last edited 2013-07-27 10:01:25 by RusselWinder)