blob: d72ac038b47fb498a5c457dbcc1876e84390b1dd [file] [log] [blame]
#!/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)