blob: 617066ccfeee09c973c2617c101e32ba38a1e201 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This script generates a C header file with build flags.
#
# It takes a response file as input, which contains the build flags.
# The response file format is:
# --flags <list of one or more flag values>
#
# The generated header file defines macros for each build flag, which can be
# used in C code to conditionally compile code based on the build flags.
#
# See the gen_buildflags target in /gn/BUILD.gn for usage.
import argparse
import os
import shlex
import sys
import re
from dataclasses import dataclass
COPYRIGHT_HEADER = '''/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'''
@dataclass
class Flag:
name: str
raw_value: str
class HeaderGenerator:
"""Generates the build flag header file."""
def __init__(self, out_path: str, flags: list[Flag]):
self._out_path = out_path
self._flags = flags
self._guard = re.sub(r'[^A-Z0-9_]', '_', out_path.upper()) + '_'
def _get_define_value(self, value: str) -> str:
if value == 'true':
return '1'
if value == 'false':
return '0'
return value
def _escape_value(self, value: str) -> str:
return value.replace('\\', '\\\\').replace('"', '\\"')
def _generate_defines(self) -> str:
defines = []
for flag in self._flags:
define = (f'#define PERFETTO_BUILDFLAG_DEFINE_{flag.name}() '
f'({self._get_define_value(flag.raw_value)})')
defines.append(define)
return '\n'.join(defines)
def generate(self) -> None:
boolean_flags = [f for f in self._flags if f.raw_value in ('true', 'false')]
num_boolean_flags = len(boolean_flags)
items = []
for flag in boolean_flags:
items.append(
f' {{"{flag.name}", PERFETTO_BUILDFLAG_DEFINE_{flag.name}()}},')
all_build_flags_str = '\n'.join(items)
header_template = f"""// Generated by {os.path.basename(__file__)}
// fix_include_guards: off
#ifndef {self._guard}
#define {self._guard}
// clang-format off
{self._generate_defines()}
struct PerfettoBuildFlag {{
const char* name;
int value;
}};
static const struct PerfettoBuildFlag kPerfettoBuildFlags[] = {{
{all_build_flags_str}
}};
static const int kPerfettoBuildFlagsCount = sizeof(kPerfettoBuildFlags) / sizeof(struct PerfettoBuildFlag);
// clang-format on
#endif // {self._guard}
"""
with open(self._out_path, 'w', newline='\n') as out:
out.write(COPYRIGHT_HEADER)
out.write(header_template)
def parse_flags_from_rsp(rsp_file: str) -> list[Flag]:
"""Parses the response file and returns a list of flags."""
with open(rsp_file, 'r') as f:
content = f.read()
parts = shlex.split(content)
if not parts or parts[0] != '--flags':
raise ValueError("Invalid response file format: --flags not found.")
flags: list[Flag] = []
for flag_str in parts[1:]:
if '=' not in flag_str:
raise ValueError(f"Invalid flag format: {flag_str}")
key, raw_value = flag_str.split('=', 1)
flags.append(Flag(name=key, raw_value=raw_value))
return flags
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--rsp', help='Input response file containing the flags.')
parser.add_argument(
'--out', required=True, help='Output path of the generated header file.')
args = parser.parse_args()
flags = parse_flags_from_rsp(args.rsp)
HeaderGenerator(args.out, flags).generate()
if __name__ == '__main__':
sys.exit(main())