blob: 599619d450ccb9ad7c23b7963ba3e6b0f4caa6d8 [file]
#!/usr/bin/env python3
# Copyright (C) 2026 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.
"""Prevents code outside Trace Processor from depending on its internals.
Targets under src/trace_processor/util are intentionally reusable. All other
src/trace_processor targets are implementation details and must not be direct
dependencies of targets outside that directory.
"""
import argparse
import os
import sys
# gn_utils remains infrastructure for interrogating GN build descriptions.
ROOT_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.insert(0, os.path.join(ROOT_DIR, 'tools'))
import gn_utils
TP_PREFIX = '//src/trace_processor'
ALLOWED_TP_PREFIX = '//src/trace_processor/util'
# These root executables aggregate Trace Processor's own tests and benchmarks.
TP_TEST_AGGREGATORS = {
'//:all',
'//:perfetto_benchmarks',
'//:perfetto_integrationtests',
'//:perfetto_trace_processor_unittests',
'//:perfetto_unittests',
'//:trace_processor_minimal_smoke_tests',
}
# Existing boundary violations. Do not add entries: move the shared code out of
# Trace Processor instead.
LEGACY_ALLOWED_EDGES = {
('//src/profiling/memory:end_to_end_tests', '//src/trace_processor:lib'),
('//src/protozero/text_to_proto:unittests',
'//src/trace_processor:gen_cc_test_messages_descriptor'),
('//src/tools/protoprofile:common', '//src/trace_processor:lib'),
('//src/tools/protoprofile:common',
'//src/trace_processor/importers/proto:gen_cc_android_extension_descriptor'
),
('//src/tools/protoprofile:common',
'//src/trace_processor/importers/proto:gen_cc_trace_descriptor'),
('//src/traceconv:lib', '//src/trace_processor:export_json'),
('//src/traceconv:lib', '//src/trace_processor:lib'),
('//src/traceconv:lib', '//src/trace_processor:storage_minimal'),
('//src/traceconv:pprofbuilder',
'//src/trace_processor/containers:containers'),
('//test:perfetto_end_to_end_integrationtests',
'//src/trace_processor:trace_processor_shell'),
('//ui:ui', '//src/trace_processor:trace_processor.wasm'),
('//ui:ui', '//src/trace_processor:trace_processor_memory64.wasm'),
}
def is_in(label, prefix):
return label == prefix or label.startswith((prefix + '/', prefix + ':'))
def check(desc):
errors = []
for label, target in desc.items():
source = gn_utils.label_without_toolchain(label)
if is_in(source, TP_PREFIX) or source in TP_TEST_AGGREGATORS:
continue
for dependency in target.get('deps', []):
dependency = gn_utils.label_without_toolchain(dependency)
edge = (source, dependency)
if (is_in(dependency, TP_PREFIX) and
not is_in(dependency, ALLOWED_TP_PREFIX) and
edge not in LEGACY_ALLOWED_EDGES):
errors.append(
f'target "{source}" depends on Trace Processor internal target '
f'"{dependency}"; only {ALLOWED_TP_PREFIX} targets are reusable.')
return sorted(set(errors))
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--out',
help='use an existing GN out directory instead of a temporary one')
args = parser.parse_args()
if args.out:
errors = check(gn_utils.load_build_description(args.out))
else:
with gn_utils.BuildDescription('') as build:
errors = check(build.desc)
for error in errors:
print(error, file=sys.stderr)
return 1 if errors else 0
if __name__ == '__main__':
sys.exit(main())