[Scons-users] intermediate builder step -- wish for no-build when the original files are unch

Jay Damask jaydamask at gmail.com
Mon Jun 3 20:36:50 EDT 2013


Hello again.

My two posts with subjects:
sconsign db access -- different results from Dir() and File() apis
sconsign db access -- different results from python cmdline and scons

both related to my intent to better control intermediate builds with
different tools. The tool for this topic is protoc, but lex / yacc are good
alternative examples.

$ uname -a
Linux wdac-nyk-lx01 3.5.0-25-generic #39-Ubuntu SMP Mon Feb 25 18:26:58 UTC
2013 x86_64 x86_64 x86_64 GNU/Linux
$ scons --version
SCons by Steven Knight et al.:
script: v2.1.0.r5357[MODIFIED], 2011/09/09 21:31:03, by bdeegan on
ubuntu
engine: v2.1.0.r5357[MODIFIED], 2011/09/09 21:31:03, by bdeegan on
ubuntu

Highlights of my repo --

SConstruct
site_scons/protoc_builder.py
src/SConscript
src/p/
a.proto
b.proto
a.pb.h <-- after protoc invocation
a.pb.cc <-- after protoc invocation
b.pb.h <-- after protoc invocation
b.pb.cc <-- after protoc invocation


Highlights of my python code:

protoc_builder.py: (ref: https://github.com/petriborg/Scons-Protoc)

...
def _detect(env):

detect and return protoc

def _protoc_emitter(target, source, env):

manipulate target(s) and source(s)

return target, source

_protoc_builder = SCons.Script.Builder(
action = SCons.Script.Action('$PROTOC_COM', '$PROTOC_COMSTR'),
suffix = '$PROTO_CCSUFFIX',
src_suffix = '$PROTO_SUFFIX',
emitter = _protoc_emitter,
)

def generate(env):
"""Add Builders and construction variables."""

env['PROTOC'] = _detect(env)
env.SetDefault(
...
PROTOC_COM = "$PROTOC $PROTOC_FLAGS $SOURCES",
...
)

env['BUILDERS']['Protoc'] = _protoc_builder

def exists(env):
return _detect(env)


SConscript:

...
proto_targets_cc = env.Protoc(
[
'p/a.proto',
'p/b.proto'
],
PROTO_PATH = '#p',
PROTO_CCOUT = '#p'
)

commLib = env.SharedLibrary('comm',
[
# proto target cc files
proto_targets_cc,

# other sources...
])

Return('commLib')


Clean first run:
$ scons commLib
invokes:
protoc --proto_path=<foo> --cpp_out=<bar> #/p/a.proto #/p/b.proto
which makes #/p/
a.pb.h, a.pb.cc, b.pb.h, b.pb.cc
invokes:
g++ -o #/b/a.pb.os #/p/a.pb.cc
g++ -o #/b/b.pb.os #/p/b.pb.cc
g++ <make comm_lib>


Dirty second run:
$ scons commLib
invokes:
protoc --proto_path=<foo> --cpp_out=<bar> a.proto b.proto
which makes #/p/
a.pb.h, a.pb.cc, b.pb.h, b.pb.cc
build completes


The problem is that each dirty scons run after the first invokes protoc,
which builds *.pb.h and *.pb.cc files. This occurs even when the *.proto
files are unchanged. Since I have these files in my editor, my editor keeps
asking me to update the *.pb.* files -- its not only annoying but the scons
build is inefficient.

I have read about Decider objects, they appear to be global and set the
signature (md5, ts, etc).

I have read about the Depends fcxn, but its n/a b/c I want the
proto_targets_cc files compiled into the comm_lib, not just that comm_lib
depends on the proto_targets_cc.

I have read about the Requires fcxn, but imo its n/a, too.

Since we are in python its pretty easy to get the md5sum of the source file
and the persisted md5sum from the sconsign db. If there's a diff then invoke
protoc, otherwise skip the protoc step.

In fact, with the code layout in protoc_builder.py I don't see an 'obvious'
way to skip the protoc invocation. The way I intended to kludge it is to
replace the $PROTOC_COM string the env dict with ''. Its a hack, if there's
better form I'd like to know.

What I'm addressing is a broader pattern, and I appreciate its touched on in
the scons dox. For instance there's CFile and CXXFile builders... Lex and
Yacc are excellent similar examples where I don't want the .cc files
generated when the .l and .y files are unchanged.

Any help with how to layout this code, and in particular cease the protoc
invocation when all *.proto files are unch, is much appreciated.

Thank you and regards,
-Jay





More information about the Scons-users mailing list