17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen''' 27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenScons Builder for nanopb .proto definitions. 37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenThis tool will locate the nanopb generator and use it to generate .pb.c and 57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen.pb.h files from the .proto files. 67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenBasic example 87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen------------- 97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Build myproto.pb.c and myproto.pb.h from myproto.proto 107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenmyproto = env.NanopbProto("myproto") 117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen# Link nanopb core to the program 137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenenv.Append(CPPPATH = "$NANOB") 147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenmyprog = env.Program(["myprog.c", myproto, "$NANOPB/pb_encode.c", "$NANOPB/pb_decode.c"]) 157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenConfiguration options 177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen--------------------- 187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenNormally, this script is used in the test environment of nanopb and it locates 197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenthe nanopb generator by a relative path. If this script is used in another 207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenapplication, the path to nanopb root directory has to be defined: 217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenenv.SetDefault(NANOPB = "path/to/nanopb") 237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenAdditionally, the path to protoc and the options to give to protoc can be 257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendefined manually: 267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenenv.SetDefault(PROTOC = "path/to/protoc") 287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenenv.SetDefault(PROTOCFLAGS = "--plugin=protoc-gen-nanopb=path/to/protoc-gen-nanopb") 297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen''' 307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport SCons.Action 327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport SCons.Builder 337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport SCons.Util 347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenimport os.path 357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenclass NanopbWarning(SCons.Warnings.Warning): 377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pass 387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan CohenSCons.Warnings.enableWarningClass(NanopbWarning) 397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef _detect_nanopb(env): 417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Find the path to nanopb root directory.''' 427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if env.has_key('NANOPB'): 437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Use nanopb dir given by user 447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return env['NANOPB'] 457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen p = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) 477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if os.path.isdir(p) and os.path.isfile(os.path.join(p, 'pb.h')): 487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Assume we are running under tests/site_scons/site_tools 497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return p 507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise SCons.Errors.StopError(NanopbWarning, 527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen "Could not find the nanopb root directory") 537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef _detect_protoc(env): 557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Find the path to the protoc compiler.''' 567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if env.has_key('PROTOC'): 577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Use protoc defined by user 587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return env['PROTOC'] 597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen n = _detect_nanopb(env) 617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen p1 = os.path.join(n, 'generator-bin', 'protoc' + env['PROGSUFFIX']) 627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if os.path.exists(p1): 637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Use protoc bundled with binary package 647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return env['ESCAPE'](p1) 657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen p = env.WhereIs('protoc') 677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if p: 687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Use protoc from path 697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return env['ESCAPE'](p) 707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen raise SCons.Errors.StopError(NanopbWarning, 727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen "Could not find the protoc compiler") 737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef _detect_protocflags(env): 757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Find the options to use for protoc.''' 767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if env.has_key('PROTOCFLAGS'): 777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return env['PROTOCFLAGS'] 787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen p = _detect_protoc(env) 807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen n = _detect_nanopb(env) 817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen p1 = os.path.join(n, 'generator-bin', 'protoc' + env['PROGSUFFIX']) 827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if p == env['ESCAPE'](p1): 837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen # Using the bundled protoc, no options needed 847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '' 857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen e = env['ESCAPE'] 877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if env['PLATFORM'] == 'win32': 887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return e('--plugin=protoc-gen-nanopb=' + os.path.join(n, 'generator', 'protoc-gen-nanopb.bat')) 897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else: 907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return e('--plugin=protoc-gen-nanopb=' + os.path.join(n, 'generator', 'protoc-gen-nanopb')) 917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef _nanopb_proto_actions(source, target, env, for_signature): 937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen esc = env['ESCAPE'] 947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen dirs = ' '.join(['-I' + esc(env.GetBuildPath(d)) for d in env['PROTOCPATH']]) 957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return '$PROTOC $PROTOCFLAGS %s --nanopb_out=. %s' % (dirs, esc(str(source[0]))) 967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef _nanopb_proto_emitter(target, source, env): 987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen basename = os.path.splitext(str(source[0]))[0] 997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen target.append(basename + '.pb.h') 1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if os.path.exists(basename + '.options'): 1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen source.append(basename + '.options') 1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return target, source 1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen_nanopb_proto_builder = SCons.Builder.Builder( 1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen generator = _nanopb_proto_actions, 1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen suffix = '.pb.c', 1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen src_suffix = '.proto', 1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen emitter = _nanopb_proto_emitter) 1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef generate(env): 1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen '''Add Builder for nanopb protos.''' 1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen env['NANOPB'] = _detect_nanopb(env) 1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen env['PROTOC'] = _detect_protoc(env) 1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen env['PROTOCFLAGS'] = _detect_protocflags(env) 1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen env.SetDefault(PROTOCPATH = ['.', os.path.join(env['NANOPB'], 'generator', 'proto')]) 1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen env.SetDefault(NANOPB_PROTO_CMD = '$PROTOC $PROTOC_OPTS --nanopb_out=. $SOURCE') 1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen env['BUILDERS']['NanopbProto'] = _nanopb_proto_builder 1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohendef exists(env): 1257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return _detect_protoc(env) and _detect_protoc_opts(env) 1267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 127