scons: Convert ProtoBuf to use a scons Builder and Scanner.

There are several benefits to using a Builder. First, the action we're
executing is shared between all uses of the Builder. The number of
times this particular builder is called is small, but it should still
be a little more efficient.

Second, we can use SCons's emitter mechanism to generate the .pb.cc and
.pb.h target files in a little more general way.

Also, this change adds a Scanner for .proto files which will scan them
for imports and let SCons manage those implicit dependencies properly.
The scanner is a bit simplistic as described in a comment in the
source, but should work pretty well in practice with reasonably
formatted files, and in particular some files I'm working with that
include imports.

Change-Id: Iaf2498e61133d6f713d6ccaf199422b882c5894f
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/37276
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Gabe Black <gabe.black@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2020-11-08 07:17:04 -08:00
committed by Gabe Black
parent 0957ab118c
commit 6bbdfa370c

View File

@@ -65,7 +65,7 @@ Export('env')
build_env = [(opt, env[opt]) for opt in export_vars]
from m5.util import code_formatter, compareVersions
from m5.util import code_formatter, compareVersions, readCommand
########################################################################
# Code for adding source files of various types
@@ -386,6 +386,34 @@ class SimObject(PySource):
bisect.insort_right(SimObject.modnames, self.modname)
# This regular expression is simplistic and assumes that the import takes up
# the entire line, doesn't have the keyword "public", uses double quotes, has
# no whitespace at the end before or after the ;, and is all on one line. This
# should still cover most cases, and a completely accurate scanner would be
# MUCH more complex.
protoc_import_re = re.compile(r'^import\s+\"(.*\.proto)\"\;$', re.M)
def protoc_scanner(node, env, path):
deps = []
for imp in protoc_import_re.findall(node.get_text_contents()):
deps.append(Dir(env['BUILDDIR']).File(imp))
return deps
env.Append(SCANNERS=Scanner(function=protoc_scanner, skeys=['.proto']))
def protoc_emitter(target, source, env):
root, ext = os.path.splitext(source[0].get_abspath())
return [root + '.pb.cc', root + '.pb.h'], source
env.Append(BUILDERS={'ProtoBufCC' : Builder(
action=MakeAction('${PROTOC} --cpp_out ${BUILDDIR} '
'--proto_path ${BUILDDIR} '
'${SOURCE.get_abspath()}',
Transform("PROTOC")),
emitter=protoc_emitter
)})
class ProtoBuf(SourceFile):
'''Add a Protocol Buffer to build'''
@@ -400,20 +428,7 @@ class ProtoBuf(SourceFile):
modname,ext = self.extname
assert ext == 'proto'
# Currently, we stick to generating the C++ headers, so we
# only need to track the source and header.
self.cc_file = self.tnode.dir.File(modname + '.pb.cc')
self.hh_file = self.tnode.dir.File(modname + '.pb.h')
# Use both the source and header as the target, and the .proto
# file as the source. When executing the protoc compiler, also
# specify the proto_path to avoid having the generated files
# include the path.
env.Command([self.cc_file, self.hh_file], self.tnode,
MakeAction('${PROTOC} --cpp_out ${BUILDDIR} '
'--proto_path ${BUILDDIR} '
'${SOURCE.get_abspath()}',
Transform("PROTOC")))
self.cc_file, self.hh_file = env.ProtoBufCC(source=source)
# Add the C++ source file
Source(self.cc_file, tags=self.tags,