Skip to content

Commit

Permalink
Add a Protoc C++ tool.
Browse files Browse the repository at this point in the history
Example:

    prog = cxx.Program('prog')
    protos = builder.tools.Protoc(sources = ['myproto.proto'])
    prog.custom += [protos]

To make this work, protoc is now always executed in the top level of the
build directory. This is kind of gross as we have to make sure all paths
are relative to the root, rather than cwd. The alternative is running
protoc once for each language, which would be fine, but the current
thing is working.
  • Loading branch information
dvander committed Nov 9, 2023
1 parent 7bf999b commit 9cae625
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 13 deletions.
1 change: 1 addition & 0 deletions ambuild2/frontend/v2_2/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

from ambuild2.frontend.v2_2.tools.fxc import FxcJob as FXC
from ambuild2.frontend.v2_2.tools.protoc import DetectProtoc as DetectProtoc
from ambuild2.frontend.v2_2.tools.protoc import ProtocJob as Protoc
55 changes: 42 additions & 13 deletions ambuild2/frontend/v2_2/tools/protoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import subprocess
from ambuild2 import util
from ambuild2.frontend.version import Version
from ambuild2.frontend import paths

class ProtocRunner(object):
def __init__(self, protoc, builder, includes):
Expand All @@ -46,8 +47,7 @@ def AddOutput(self, language, folder):
}
self.gen_map[language] = {}

out_build_path = os.path.relpath(folder.path, self.builder.buildFolder)
self.argv += ['--{}_out={}'.format(language, out_build_path)]
self.argv += ['--{}_out={}'.format(language, folder.path)]

def AddSource(self, source_path):
source_name = os.path.basename(source_path)
Expand All @@ -59,9 +59,11 @@ def AddSource(self, source_path):
gen_file_list = []
gen_file_map = {}
for language in self.languages:
folder = self.languages[language]['folder']

gen_info = gen_file_map.setdefault(language, {
'sources': [],
'headers': [],
'sources': 0,
'headers': 0,
})
gen_source_names = []
gen_header_names = []
Expand All @@ -79,13 +81,13 @@ def AddSource(self, source_path):
else:
raise Exception('Language not supported yet: {}'.format(language))

gen_file_list += gen_source_names
gen_file_list += gen_header_names
for file in gen_source_names + gen_header_names:
gen_file_list += [paths.Join(folder, file)]

gen_info['sources'] += gen_source_names
gen_info['headers'] += gen_header_names
gen_info['sources'] += len(gen_source_names)
gen_info['headers'] += len(gen_header_names)

dep_file = '{}.d'.format(source_name)
dep_file = paths.Join(folder, '{}.d'.format(source_name))
argv = self.argv + [
'--dependency_out={}'.format(dep_file),
source_path,
Expand All @@ -96,16 +98,17 @@ def AddSource(self, source_path):
outputs = gen_file_list,
dep_type = 'md',
dep_file = dep_file,
shared_outputs = [dep_file])
shared_outputs = [dep_file],
folder = None)

# Translate the list of generated output entries.
cursor = 0
for language in self.languages:
gen_info = gen_file_map[language]
gen_sources = gen_entries[cursor:cursor + len(gen_info['sources'])]
gen_sources = gen_entries[cursor:cursor + gen_info['sources']]
cursor += len(gen_sources)

gen_headers = gen_entries[cursor:cursor + len(gen_info['headers'])]
gen_headers = gen_entries[cursor:cursor + gen_info['headers']]
cursor += len(gen_headers)

self.gen_map[language].setdefault('sources', []).extend(gen_sources)
Expand Down Expand Up @@ -168,6 +171,8 @@ def StaticLibrary(self, name, builder, cxx, sources, includes = []):
out = builder.Add(binary)
return ProtocCppNode(out, gen_map['cpp']['headers'])

FoundProtocMap = set()

def DetectProtoc(**kwargs):
path = kwargs.pop('path', None)
if len(kwargs):
Expand All @@ -188,6 +193,30 @@ def DetectProtoc(**kwargs):
name = parts[0]
version = Version(parts[1])

util.con_out(util.ConsoleHeader, 'found protoc {}-{}'.format(name, version))
if path not in FoundProtocMap:
util.con_out(util.ConsoleHeader, 'found protoc {}-{}'.format(name, version))
FoundProtocMap.add(path)

return Protoc(path, name, version)

class ProtocTool(object):
def __init__(self):
pass

def evaluate(self, cmd):
gen_map = cmd.data.protoc.Generate(builder = cmd.context,
sources = cmd.data.sources,
outputs = [('cpp', cmd.localFolderNode)])
cmd.sourcedeps += gen_map['cpp']['sources']
cmd.sourcedeps += gen_map['cpp']['headers']
for source in gen_map['cpp']['sources']:
cmd.sources += [os.path.join(cmd.context.buildPath, source.path)]

class ProtocJob(object):
def __init__(self, protoc = None, sources = []):
if protoc is None:
self.protoc = DetectProtoc()
else:
self.protoc = protoc.clone()
self.sources = sources[:]
self.tool = ProtocTool()

0 comments on commit 9cae625

Please sign in to comment.