#!/usr/bin/env python3 # Copyright 2022 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Generates GN build files for protobuf. See update_file_lists.sh from protobuf.""" import os.path PROTO_DIR = os.path.dirname(__file__) MAKEFILE = os.path.join(PROTO_DIR, 'Makefile.am') SRC_MAKEFILE = os.path.join(PROTO_DIR, 'src', 'Makefile.am') PROTO_SOURCES_GNI = os.path.join(PROTO_DIR, 'proto_sources.gni') def read_makefile_lines(f): # Roughly implement https://www.gnu.org/software/make/manual/html_node/Splitting-Lines.html # but skip condensing whitespace. That can be handled by the reader. Also # make no distinction between recipe and non-recipe lines. cont = [] while True: line = f.readline() if line == '': if len(cont) != 0: raise ValueError('Continuation at end of file') break line = line.rstrip('\n') if line.endswith('\\'): cont.append(line[:-1]) else: cont.append(line) yield ' '.join(cont) cont = [] def read_makefile_variables(f): ret = {} for line in read_makefile_lines(f): if not line or line[0].isspace(): continue # Sometimes there aren't spaces surrounding equals. line = line.replace('=', ' = ') # Do a very rough parse. tokens = line.split() if len(tokens) >= 2 and tokens[1] == '=': value = [] for token in tokens[2:]: if token.startswith('$(') and token.endswith(')'): value.extend(ret.get(token[2:-1], [])) else: value.append(token) ret[tokens[0]] = value return ret def is_protoc_header(path): if '/compiler/' not in path: return False # compiler/importer.h and compiler/parser.h should be part of libprotobuf # itself. return not path.endswith("/importer.h") and not path.endswith("/parser.h") def prefix_paths(prefix, paths): return [f'src/{p}' for p in paths] def write_gn_variable(f, name, value): f.write(f'\n{name} = [\n') # Sort and deduplicate the file lists. Protobuf has some duplicate entries. for path in sorted(set(value)): f.write(f' "{path}",\n') f.write(']\n') def main(): with open(SRC_MAKEFILE) as f: vars = read_makefile_variables(f) protobuf_headers = [ p for p in vars['nobase_include_HEADERS'] if not is_protoc_header(p) ] protobuf_lite_sources = vars['libprotobuf_lite_la_SOURCES'] protobuf_sources = [ p for p in vars['libprotobuf_la_SOURCES'] if p not in protobuf_lite_sources ] protoc_sources = vars['libprotoc_la_SOURCES'] protoc_headers = [ p for p in vars['nobase_include_HEADERS'] if is_protoc_header(p) ] protobuf_headers = prefix_paths('src', protobuf_headers) protobuf_lite_sources = prefix_paths('src', protobuf_lite_sources) protobuf_sources = prefix_paths('src', protobuf_sources) protoc_sources = prefix_paths('src', protoc_sources) protoc_headers = prefix_paths('src', protoc_headers) # Not upstream protobuf, added via Chromium patch. protobuf_lite_sources.append("src/google/protobuf/arenastring.cc") with open(MAKEFILE) as f: vars = read_makefile_variables(f) all_python_sources = [ p for p in vars['python_EXTRA_DIST'] if p.endswith('.py') and 'test' not in p ] # The copy rules in BUILD.gn can only handle files in the same directory, so # the list must be split into per-directory lists. pyproto_sources = [ p for p in all_python_sources if os.path.dirname(p) == 'python/google/protobuf' ] pyproto_internal_sources = [ p for p in all_python_sources if os.path.dirname(p) == 'python/google/protobuf/internal' ] with open(PROTO_SOURCES_GNI, 'w') as f: f.write('''# Copyright 2022 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Generated by gen_chromium_file_lists.py. Do not edit by hand. ''') write_gn_variable(f, 'protobuf_headers', protobuf_headers) write_gn_variable(f, 'protobuf_lite_sources', protobuf_lite_sources) write_gn_variable(f, 'protobuf_sources', protobuf_sources) write_gn_variable(f, 'protoc_sources', protoc_sources) write_gn_variable(f, 'protoc_headers', protoc_headers) write_gn_variable(f, 'pyproto_sources', pyproto_sources) write_gn_variable(f, 'pyproto_internal_sources', pyproto_internal_sources) if __name__ == '__main__': main()