| #!/usr/bin/env python3 |
| # Copyright 2020 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import datetime |
| import os |
| import platform |
| import re |
| import subprocess |
| import sys |
| |
| from typing import List, Callable |
| |
| from generate.types import * |
| from generate.identifiers import IDENTIFIERS |
| from generate.styles import STYLES |
| from generate.uses import USES |
| |
| # Where is this script? |
| MODULE = os.path.dirname(os.path.realpath(__file__)) |
| |
| # Where is the directory containing the module? |
| DIR = os.path.dirname(MODULE) |
| |
| # What platform are we on? |
| HOST_PLARFORM = "{}-{}".format( |
| platform.system().lower().replace("darwin", "mac"), |
| { |
| "x86_64": "x64", |
| "aarch64": "arm64", |
| }[platform.machine()], |
| ) |
| |
| # Where is gn? |
| GN = os.path.realpath( |
| os.path.join( |
| DIR, '../../../../prebuilt/third_party/gn', HOST_PLARFORM, 'gn')) |
| FUCHSIA_DIR = os.environ.get('FUCHSIA_DIR') |
| FUCHSIA_BUILD_DIR = os.environ.get('FUCHSIA_BUILD_DIR') |
| if FUCHSIA_BUILD_DIR is None or FUCHSIA_DIR is None: |
| print(f'Run "fx exec {DIR}/generate.sh".') |
| sys.exit(1) |
| FIDL_FORMAT = os.path.join(FUCHSIA_BUILD_DIR, 'host_x64', 'fidl-format') |
| RUST_FORMAT = os.path.join( |
| FUCHSIA_DIR, 'prebuilt', 'third_party', 'rust_tools', 'linux-x64', 'bin', |
| 'rustfmt') |
| |
| # Validate IDENTIFIERS |
| # check that the style & use names in deny rules are valid |
| style_names = frozenset(style.name for style in STYLES) |
| use_names = frozenset(use.name for use in USES) |
| for ident in IDENTIFIERS: |
| for deny in ident.deny: |
| for style in deny.styles: |
| if style not in style_names: |
| print( |
| f'Unknown style name "{style}" in deny list for "{ident.name}"' |
| ) |
| sys.exit(1) |
| for use in deny.uses: |
| if use not in use_names: |
| print( |
| f'Unknown use name "{use}" in deny list for "{ident.name}"') |
| sys.exit(1) |
| |
| |
| def generated(prefix: str) -> str: |
| """Return a header line indicating that this is a generated file.""" |
| return """{prefix} Copyright 2019 The Fuchsia Authors. All rights reserved. |
| {prefix} Use of this source code is governed by a BSD-style license that can be |
| {prefix} found in the LICENSE file. |
| {prefix} Generated by {generator}. |
| """.format( |
| prefix=prefix, |
| generator='//src/tests/fidl/dangerous_identifiers/generate') |
| |
| |
| def library_target(library_name: str) -> str: |
| return '//src/tests/fidl/dangerous_identifiers/fidl:%s' % library_name |
| |
| |
| def generate_fidl(identifier_defs: List[Identifier]) -> List[str]: |
| """Generate FIDL libraries for the specified identifier definitions. |
| |
| Return the list of library names. |
| """ |
| directory = os.path.join(DIR, 'fidl') |
| os.makedirs(directory, exist_ok=True) |
| prefix = 'fidl.test.dangerous' |
| # generate FIDL libraries |
| library_names = [] |
| for style in STYLES: |
| for use in USES: |
| library_name = '%s.%s.%s' % (prefix, use.name, style.name) |
| fidl_file = os.path.join(directory, '%s.test.fidl' % library_name) |
| idents = [ident.scoped(style, use) for ident in identifier_defs] |
| with open(fidl_file, 'w') as f: |
| f.write(generated('//')) |
| f.write('library %s;\n' % library_name) |
| use(f, [ident for ident in idents if not ident.denied]) |
| subprocess.check_output([FIDL_FORMAT, '-i', fidl_file]) |
| library_names.append(library_name) |
| |
| # generate BUILD.gn for FIDL libraries |
| build_file = os.path.join(directory, 'BUILD.gn') |
| with open(build_file, 'w') as build_gn: |
| build_gn.write(generated('#')) |
| build_gn.write('import("//build/fidl/fidl.gni")\n\n') |
| build_gn.write('group("fidl") {\ndeps=[\n') |
| for library_name in library_names: |
| build_gn.write(' ":%s",\n' % library_name) |
| build_gn.write(']}\n') |
| for library_name in library_names: |
| build_gn.write( |
| 'fidl("%s") {\n sources = [ "%s.test.fidl" ] }\n\n' % |
| (library_name, library_name)) |
| subprocess.check_output([GN, 'format', build_file]) |
| |
| return library_names |
| |
| |
| def generate_cpp(libraries: List[str]) -> None: |
| directory = os.path.join(DIR, 'cpp') |
| os.makedirs(directory, exist_ok=True) |
| |
| # generate BUILD.gn for C++ test |
| build_file = os.path.join(directory, 'BUILD.gn') |
| with open(build_file, 'w') as build_gn: |
| build_gn.write(generated('#')) |
| for library_name in libraries: |
| build_gn.write( |
| """source_set("%s_cpp") { |
| output_name = "cpp_fidl_dangerous_identifiers_test_%s" |
| sources = [ "%s_test.cc" ] |
| deps = [ |
| """ % (library_name, library_name, library_name)) |
| build_gn.write(' "%s",\n' % library_target(library_name)) |
| build_gn.write(' ]\n}\n') |
| build_gn.write("""group("cpp") { |
| deps = [""") |
| for library_name in libraries: |
| build_gn.write(""" |
| ":%s_cpp", |
| """ % (library_name)) |
| build_gn.write(""" |
| ] |
| }""") |
| |
| subprocess.check_output([GN, 'format', build_file]) |
| |
| |
| def generate_rust(libraries: List[str]) -> None: |
| os.makedirs(os.path.join(DIR, 'rust', 'src'), exist_ok=True) |
| |
| # Allowlist of libraries we can compile in Rust |
| # TODO(fxbug.dev/60219): Make all libraries pass. |
| allowed_libraries = { |
| 'fidl.test.dangerous.constants.lower', |
| 'fidl.test.dangerous.constants.camel', |
| 'fidl.test.dangerous.constants.upper', |
| 'fidl.test.dangerous.using.lower', |
| 'fidl.test.dangerous.using.camel', |
| 'fidl.test.dangerous.using.upper', |
| 'fidl.test.dangerous.enums.lower', |
| 'fidl.test.dangerous.struct.types.lower', |
| 'fidl.test.dangerous.struct.types.upper', |
| 'fidl.test.dangerous.table.names.lower', |
| 'fidl.test.dangerous.table.names.camel', |
| 'fidl.test.dangerous.table.names.upper', |
| } |
| |
| # BUILD.gn |
| build_file = os.path.join(DIR, 'rust', 'BUILD.gn') |
| with open(build_file, 'w') as f: |
| f.write(generated('#')) |
| f.write('\n') |
| f.write('import("//build/rust/rustc_test.gni")\n') |
| f.write('import("//tools/fidl/measure-tape/measure_tape.gni")\n') |
| f.write('\n') |
| f.write('rustc_test("rust") {\n') |
| f.write(' sources = [ "src/lib.rs" ]\n') |
| f.write(' deps = [\n') |
| for library_name in libraries: |
| f.write(' ') |
| if library_name not in allowed_libraries: |
| f.write('# ') |
| f.write('"%s-rustc",\n' % library_target(library_name)) |
| f.write(' ]\n') |
| f.write('}\n') |
| subprocess.check_output([GN, 'format', build_file]) |
| |
| # lib.rs |
| lib_rs = os.path.join(DIR, 'rust', 'src', 'lib.rs') |
| with open(lib_rs, 'w') as f: |
| f.write(generated('//')) |
| f.write('#![cfg(test)]\n') |
| f.write('#![allow(unused_imports)]\n') |
| f.write('use {\n') |
| for library_name in libraries: |
| f.write(' ') |
| if library_name not in allowed_libraries: |
| f.write('// ') |
| f.write('fidl_%s,\n' % library_name.replace('.', '_')) |
| f.write('};\n') |
| subprocess.check_output([RUST_FORMAT, lib_rs]) |
| |
| |
| if __name__ == '__main__': |
| library_names = generate_fidl(IDENTIFIERS) |
| generate_cpp(library_names) |
| generate_rust(library_names) |