Roll Perfetto to 49c59636465f2a32f4d83cff835538ba7bf8d732

Drop libprotobuf dependency and update compile_perfetto_protos
to rely on externally provided protoc and protozero_plugin. 
This is done because protoc does not build with our current
toolchain and fixing this build requires rolling new protobuf,
protobuf_gn and perfetto. Which also pulls more external dependencies
like abseil.

Regenerate Perfetto *.pbzero{.cc,.h}, *.dart files

TEST=ci

Change-Id: I11a32aa07e810b48ac12502e526bbaee6a6a6964
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/482781
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Slava Egorov
2026-02-24 03:24:32 -08:00
committed by Commit Queue
parent 590b656877
commit 1418cb1b9c
48 changed files with 450 additions and 250 deletions
+2 -12
View File
@@ -113,11 +113,9 @@ vars = {
"libcxx_rev": "bd557f6f764d1e40b62528a13b124ce740624f8f",
"libcxxabi_rev": "a4dda1589d37a7e4b4f7a81ebad01b1083f2e726",
"libc_rev": "5af39a19a1ad51ce93972cdab206dcd3ff9b6afa",
"libprotobuf_rev": "24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"perfetto_rev": "13ce0c9e13b0940d2476cd0cff2301708a9a2e2b",
"perfetto_rev": "49c59636465f2a32f4d83cff835538ba7bf8d732",
"ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
"protobuf_gn_rev": "ca669f79945418f6229e4fef89b666b2a88cbb10",
"WebCore_rev": "bcb10901266c884e7b3740abc597ab95373ab55c",
"zlib_rev": "470d3a2ee4ef721688ce6961bc865a99fcb64070",
@@ -322,21 +320,13 @@ deps = {
"@" + Var("jinja2_rev"),
Var("dart_root") + "/third_party/perfetto/src":
Var("android_git") + "/platform/external/perfetto" +
Var("chromium_git") + "/external/github.com/google/perfetto" +
"@" + Var("perfetto_rev"),
Var("dart_root") + "/third_party/ply":
Var("chromium_git") + "/chromium/src/third_party/ply.git" +
"@" + Var("ply_rev"),
Var("dart_root") + "/build/secondary/third_party/protobuf":
Var("fuchsia_git") + "/protobuf-gn" +
"@" + Var("protobuf_gn_rev"),
Var("dart_root") + "/third_party/protobuf":
Var("fuchsia_git") + "/third_party/protobuf" +
"@" + Var("libprotobuf_rev"),
Var("dart_root") + "/third_party/icu":
Var("chromium_git") + "/chromium/deps/icu.git" +
"@" + Var("icu_rev"),
@@ -7,3 +7,8 @@
# builds in the Android tree.
perfetto_build_with_embedder = true
perfetto_root_path = "//third_party/perfetto/src/"
# We do not actually bring a real protobuf library as a dependency for Dart
# because it requires pulling lots of other things (e.g. abseil).
perfetto_protobuf_target_prefix = "//third_party/perfetto/mock_protobuf"
perfetto_protobuf_gni = perfetto_protobuf_target_prefix + "/proto_library.gni"
-2
View File
@@ -1,2 +0,0 @@
# Ignore protobuf directory because it is retrieved by gclient sync.
protobuf/
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -103,10 +103,16 @@ class InternedString extends $pb.GeneratedMessage {
class Mapping extends $pb.GeneratedMessage {
factory Mapping({
$fixnum.Int64? iid,
$fixnum.Int64? startOffset,
$fixnum.Int64? start,
$fixnum.Int64? end,
$core.Iterable<$fixnum.Int64>? pathStringIds,
}) {
final result = create();
if (iid != null) result.iid = iid;
if (startOffset != null) result.startOffset = startOffset;
if (start != null) result.start = start;
if (end != null) result.end = end;
if (pathStringIds != null) result.pathStringIds.addAll(pathStringIds);
return result;
}
@@ -127,6 +133,13 @@ class Mapping extends $pb.GeneratedMessage {
createEmptyInstance: create)
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'iid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$fixnum.Int64>(
3, _omitFieldNames ? '' : 'startOffset', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'start', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'end', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..p<$fixnum.Int64>(
7, _omitFieldNames ? '' : 'pathStringIds', $pb.PbFieldType.PU6)
..hasRequiredFields = false;
@@ -159,10 +172,37 @@ class Mapping extends $pb.GeneratedMessage {
@$pb.TagNumber(1)
void clearIid() => $_clearField(1);
@$pb.TagNumber(3)
$fixnum.Int64 get startOffset => $_getI64(1);
@$pb.TagNumber(3)
set startOffset($fixnum.Int64 value) => $_setInt64(1, value);
@$pb.TagNumber(3)
$core.bool hasStartOffset() => $_has(1);
@$pb.TagNumber(3)
void clearStartOffset() => $_clearField(3);
@$pb.TagNumber(4)
$fixnum.Int64 get start => $_getI64(2);
@$pb.TagNumber(4)
set start($fixnum.Int64 value) => $_setInt64(2, value);
@$pb.TagNumber(4)
$core.bool hasStart() => $_has(2);
@$pb.TagNumber(4)
void clearStart() => $_clearField(4);
@$pb.TagNumber(5)
$fixnum.Int64 get end => $_getI64(3);
@$pb.TagNumber(5)
set end($fixnum.Int64 value) => $_setInt64(3, value);
@$pb.TagNumber(5)
$core.bool hasEnd() => $_has(3);
@$pb.TagNumber(5)
void clearEnd() => $_clearField(5);
/// E.g. ["system", "lib64", "libc.so"]
/// id of string.
@$pb.TagNumber(7)
$pb.PbList<$fixnum.Int64> get pathStringIds => $_getList(1);
$pb.PbList<$fixnum.Int64> get pathStringIds => $_getList(4);
}
class Frame extends $pb.GeneratedMessage {
@@ -245,6 +285,14 @@ class Frame extends $pb.GeneratedMessage {
@$pb.TagNumber(2)
void clearFunctionNameId() => $_clearField(2);
/// The mapping in which this frame's instruction pointer resides.
/// iid of Mapping.iid.
///
/// If set (non-zero), rel_pc MUST also be set. If mapping_id is 0 (not set),
/// this frame has no associated memory mapping (e.g., symbolized frames
/// without address information).
///
/// Starts from 1, 0 is the same as "not set".
@$pb.TagNumber(3)
$fixnum.Int64 get mappingId => $_getI64(2);
@$pb.TagNumber(3)
@@ -254,6 +302,8 @@ class Frame extends $pb.GeneratedMessage {
@$pb.TagNumber(3)
void clearMappingId() => $_clearField(3);
/// Instruction pointer relative to the start of the mapping.
/// MUST be set if mapping_id is set (non-zero). Ignored if mapping_id is 0.
@$pb.TagNumber(4)
$fixnum.Int64 get relPc => $_getI64(3);
@$pb.TagNumber(4)
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -40,14 +41,18 @@ const Mapping$json = {
'1': 'Mapping',
'2': [
{'1': 'iid', '3': 1, '4': 1, '5': 4, '10': 'iid'},
{'1': 'start_offset', '3': 3, '4': 1, '5': 4, '10': 'startOffset'},
{'1': 'start', '3': 4, '4': 1, '5': 4, '10': 'start'},
{'1': 'end', '3': 5, '4': 1, '5': 4, '10': 'end'},
{'1': 'path_string_ids', '3': 7, '4': 3, '5': 4, '10': 'pathStringIds'},
],
};
/// Descriptor for `Mapping`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List mappingDescriptor = $convert.base64Decode(
'CgdNYXBwaW5nEhAKA2lpZBgBIAEoBFIDaWlkEiYKD3BhdGhfc3RyaW5nX2lkcxgHIAMoBFINcG'
'F0aFN0cmluZ0lkcw==');
'CgdNYXBwaW5nEhAKA2lpZBgBIAEoBFIDaWlkEiEKDHN0YXJ0X29mZnNldBgDIAEoBFILc3Rhcn'
'RPZmZzZXQSFAoFc3RhcnQYBCABKARSBXN0YXJ0EhAKA2VuZBgFIAEoBFIDZW5kEiYKD3BhdGhf'
'c3RyaW5nX2lkcxgHIAMoBFINcGF0aFN0cmluZ0lkcw==');
@$core.Deprecated('Use frameDescriptor instead')
const Frame$json = {
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,7 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
import 'dart:core' as $core;
@@ -16,7 +16,8 @@
// ignore_for_file: constant_identifier_names
// ignore_for_file: curly_braces_in_flow_control_structures
// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
// ignore_for_file: non_constant_identifier_names, unused_import
// ignore_for_file: non_constant_identifier_names, prefer_relative_imports
// ignore_for_file: unused_import
import 'dart:convert' as $convert;
import 'dart:core' as $core;
+6 -2
View File
@@ -219,7 +219,7 @@ main(List<String> files) async {
await Future.wait(
files.map((String filepath) async {
// The `runtime/.clang-tidy` file has the enabled checks in it.
final args = <String>['-quiet', filepath, '--']
final args = <String>['--allow-no-checks', '-quiet', filepath, '--']
..addAll(compilerFlagsForFile(filepath))
..addAll(defines);
final processResult = await pool.withResource(
@@ -227,9 +227,13 @@ main(List<String> files) async {
);
final int exitCode = processResult.exitCode;
final String stdout = processResult.stdout.trim();
String stdout = processResult.stdout.trim();
final String stderr = processResult.stderr.trim();
if (stdout == 'No checks enabled.') {
stdout = '';
}
if (exitCode != 0 || stdout.isNotEmpty) {
if (!isFirstFailure) {
print('');
+4 -74
View File
@@ -1,78 +1,8 @@
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
import("//build_overrides/build.gni")
import("//third_party/protobuf/proto_library.gni")
# This is a modified copy of Perfetto's template of the same name defined in
# //third_party/perfetto/gn/proto_library.gni.
# This is equivalent to the proto_library template (generation of .h/.cc from
# .proto files) but enables generation using the protozero plugin.
# The generated files will have the .pbzero.{cc,h} suffix, as opposed to the
# .pb.{cc,h} of the official proto library.
template("protozero_library") {
proto_library(target_name) {
generate_cc = false
generate_python = false
generator_plugin_label =
perfetto_root_path + "src/protozero/protoc_plugin:protozero_plugin"
generator_plugin_suffix = ".pbzero"
if (defined(invoker.deps)) {
deps = invoker.deps
} else {
deps = []
}
forward_variables_from(invoker,
[
"defines",
"generator_plugin_options",
"include_dirs",
"proto_in_dir",
"proto_out_dir",
"sources",
"testonly",
"visibility",
"generate_descriptor",
"propagate_imports_configs",
"import_dirs",
])
}
}
_perfetto_proto_definition_sources = [
"protos/perfetto/common/builtin_clock.proto",
"protos/perfetto/trace/clock_snapshot.proto",
"protos/perfetto/trace/interned_data/interned_data.proto",
"protos/perfetto/trace/profiling/profile_common.proto",
"protos/perfetto/trace/profiling/profile_packet.proto",
"protos/perfetto/trace/trace.proto",
"protos/perfetto/trace/trace_packet.proto",
"protos/perfetto/trace/track_event/debug_annotation.proto",
"protos/perfetto/trace/track_event/process_descriptor.proto",
"protos/perfetto/trace/track_event/thread_descriptor.proto",
"protos/perfetto/trace/track_event/track_descriptor.proto",
"protos/perfetto/trace/track_event/track_event.proto",
]
# This target is not a dependency of any other GN target. It is required to make
# tools/compile_perfetto_protos.dart work though.
protozero_library("perfetto_protos_protozero") {
proto_in_dir = "."
proto_out_dir = "//third_party/perfetto"
generator_plugin_options = "wrapper_namespace=pbzero"
sources = _perfetto_proto_definition_sources
}
proto_library("perfetto_protos_dart") {
generate_cc = false
generate_python = false
generator_plugin_script = "tools/protoc_gen_dart_wrapper"
generator_plugin_suffixes = [ ".pb.dart" ]
proto_in_dir = "."
proto_out_dir = "//pkg/vm_service_protos/lib/src"
sources = _perfetto_proto_definition_sources
}
# This config needs to be propagated to all targets that depend on
# ":libprotozero".
+20 -3
View File
@@ -17,10 +17,27 @@ aware tree-shaker to reduce the size of the code).
Thus for now we choose to use manually tree-shaken protos.
# Updating Perfetto
# Regenerating protos
After updating Perfetto regenerated `*.pbzero.h` files by running:
Perfetto's `protozero_plugin` (protoc plugin) is not distributed a binary
(because it is not intended for use outside of Perfetto), so to
regenerate `*.pbzero.{cc,h}` files we need to build it from source.
This however requires a bunch of dependencies which Dart SDK build does
not currently depend on (specifically Protobuf and Abseil). So instead `protozero_plugin` needs to be built out-of-tree.
This can be done using the following commands:
```
$ dart third_party/perfetto/compile_perfetto_protos.dart
$ git clone https://github.com/google/perfetto
$ cd perfetto
$ git checkout $perfetto_rev_from_DEPS
$ tools/install-build-deps
$ gn args out/linux
$ ninja -C out/linux protoc protozero_plugin
```
Then you can run
```
$ PATH=$PERFETTO_DIR/out/linux:$PATH dart third_party/perfetto/tools/compile_perfetto_protos.dart
```
+16
View File
@@ -0,0 +1,16 @@
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Mock targets, just enough to make perfetto GN files to load.
foreach(target_name,
[
"protoc",
"protoc_lib",
"protobuf_full",
"protobuf_lite",
]) {
source_set(target_name) {
}
}
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Mock definition of proto_library, just enough to make perfetto GN files to
# load.
template("proto_library") {
not_needed(invoker, "*")
source_set(target_name) {
}
}
@@ -23,13 +23,18 @@
namespace perfetto {
namespace protos {
namespace pbzero {
class ClockSnapshot_Clock;
enum BuiltinClock : int32_t;
} // Namespace pbzero.
} // Namespace protos.
} // Namespace perfetto.
class ClockSnapshot_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
namespace perfetto {
namespace protos {
namespace pbzero {
class ClockSnapshot_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
ClockSnapshot_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -77,11 +82,11 @@ class ClockSnapshot : public ::protozero::Message {
2,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kEnum,
::perfetto::protos::pbzero::BuiltinClock,
BuiltinClock,
ClockSnapshot>;
static constexpr FieldMetadata_PrimaryTraceClock kPrimaryTraceClock{};
void set_primary_trace_clock(::perfetto::protos::pbzero::BuiltinClock value) {
void set_primary_trace_clock(BuiltinClock value) {
static constexpr uint32_t field_id =
FieldMetadata_PrimaryTraceClock::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
@@ -94,9 +99,7 @@ class ClockSnapshot : public ::protozero::Message {
};
class ClockSnapshot_Clock_Decoder
: public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
ClockSnapshot_Clock_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -23,7 +23,6 @@
namespace perfetto {
namespace protos {
namespace pbzero {
class Callstack;
class DebugAnnotationName;
class EventCategory;
@@ -31,10 +30,16 @@ class EventName;
class Frame;
class InternedString;
class Mapping;
} // Namespace pbzero.
} // Namespace protos.
} // Namespace perfetto.
class InternedData_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/29,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
namespace perfetto {
namespace protos {
namespace pbzero {
class InternedData_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/29> {
public:
InternedData_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -24,9 +24,8 @@ namespace perfetto {
namespace protos {
namespace pbzero {
class Callstack_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
class Callstack_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
Callstack_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -91,9 +90,8 @@ class Callstack : public ::protozero::Message {
}
};
class Frame_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/4,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class Frame_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/4> {
public:
Frame_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -196,9 +194,8 @@ class Frame : public ::protozero::Message {
}
};
class Mapping_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/7,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
class Mapping_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/7> {
public:
Mapping_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -209,6 +206,12 @@ class Mapping_Decoder : public ::protozero::TypedProtoDecoder<
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_iid() const { return at<1>().valid(); }
uint64_t iid() const { return at<1>().as_uint64(); }
bool has_start_offset() const { return at<3>().valid(); }
uint64_t start_offset() const { return at<3>().as_uint64(); }
bool has_start() const { return at<4>().valid(); }
uint64_t start() const { return at<4>().as_uint64(); }
bool has_end() const { return at<5>().valid(); }
uint64_t end() const { return at<5>().as_uint64(); }
bool has_path_string_ids() const { return at<7>().valid(); }
::protozero::RepeatedFieldIterator<uint64_t> path_string_ids() const {
return GetRepeated<uint64_t>(7);
@@ -220,6 +223,9 @@ class Mapping : public ::protozero::Message {
using Decoder = Mapping_Decoder;
enum : int32_t {
kIidFieldNumber = 1,
kStartOffsetFieldNumber = 3,
kStartFieldNumber = 4,
kEndFieldNumber = 5,
kPathStringIdsFieldNumber = 7,
};
static constexpr const char* GetName() { return ".perfetto.protos.Mapping"; }
@@ -242,6 +248,60 @@ class Mapping : public ::protozero::Message {
value);
}
using FieldMetadata_StartOffset = ::protozero::proto_utils::FieldMetadata<
3,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
Mapping>;
static constexpr FieldMetadata_StartOffset kStartOffset{};
void set_start_offset(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_StartOffset::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Start = ::protozero::proto_utils::FieldMetadata<
4,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
Mapping>;
static constexpr FieldMetadata_Start kStart{};
void set_start(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_Start::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_End = ::protozero::proto_utils::FieldMetadata<
5,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
Mapping>;
static constexpr FieldMetadata_End kEnd{};
void set_end(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_End::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_PathStringIds = ::protozero::proto_utils::FieldMetadata<
7,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
@@ -261,9 +321,8 @@ class Mapping : public ::protozero::Message {
}
};
class InternedString_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class InternedString_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
InternedString_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -66,6 +66,10 @@ message Mapping {
// start_offset is the offset into the library file of the first mapping
// for that library. For native libraries (.so files) this should be 0.
optional uint64 start_offset = 3;
optional uint64 start = 4;
optional uint64 end = 5;
// E.g. ["system", "lib64", "libc.so"]
// id of string.
repeated uint64 path_string_ids = 7;
@@ -79,7 +83,18 @@ message Frame {
// id of string.
optional uint64 function_name_id = 2;
// The mapping in which this frame's instruction pointer resides.
// iid of Mapping.iid.
//
// If set (non-zero), rel_pc MUST also be set. If mapping_id is 0 (not set),
// this frame has no associated memory mapping (e.g., symbolized frames
// without address information).
//
// Starts from 1, 0 is the same as "not set".
optional uint64 mapping_id = 3;
// Instruction pointer relative to the start of the mapping.
// MUST be set if mapping_id is set (non-zero). Ignored if mapping_id is 0.
optional uint64 rel_pc = 4;
}
@@ -24,9 +24,8 @@ namespace perfetto {
namespace protos {
namespace pbzero {
class PerfSample_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/4,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class PerfSample_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/4> {
public:
PerfSample_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
+9 -4
View File
@@ -23,12 +23,17 @@
namespace perfetto {
namespace protos {
namespace pbzero {
class TracePacket;
} // Namespace pbzero.
} // Namespace protos.
} // Namespace perfetto.
class Trace_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/1,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
namespace perfetto {
namespace protos {
namespace pbzero {
class Trace_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/1> {
public:
Trace_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -23,12 +23,18 @@
namespace perfetto {
namespace protos {
namespace pbzero {
class ClockSnapshot;
class InternedData;
class PerfSample;
class TrackDescriptor;
class TrackEvent;
} // Namespace pbzero.
} // Namespace protos.
} // Namespace perfetto.
namespace perfetto {
namespace protos {
namespace pbzero {
namespace perfetto_pbzero_enum_TracePacket {
enum SequenceFlags : int32_t {
@@ -63,9 +69,8 @@ const char* TracePacket_SequenceFlags_Name(
return "PBZERO_UNKNOWN_ENUM_VALUE";
}
class TracePacket_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/66,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class TracePacket_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/66> {
public:
TracePacket_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -25,9 +25,7 @@ namespace protos {
namespace pbzero {
class DebugAnnotationName_Decoder
: public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
DebugAnnotationName_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -96,9 +94,8 @@ class DebugAnnotationName : public ::protozero::Message {
}
};
class DebugAnnotation_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/17,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class DebugAnnotation_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/17> {
public:
DebugAnnotation_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -24,9 +24,8 @@ namespace perfetto {
namespace protos {
namespace pbzero {
class ProcessDescriptor_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/6,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class ProcessDescriptor_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/6> {
public:
ProcessDescriptor_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -24,9 +24,8 @@ namespace perfetto {
namespace protos {
namespace pbzero {
class ThreadDescriptor_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/5,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class ThreadDescriptor_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/5> {
public:
ThreadDescriptor_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -23,13 +23,18 @@
namespace perfetto {
namespace protos {
namespace pbzero {
class ProcessDescriptor;
class ThreadDescriptor;
} // Namespace pbzero.
} // Namespace protos.
} // Namespace perfetto.
class TrackDescriptor_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/5,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
namespace perfetto {
namespace protos {
namespace pbzero {
class TrackDescriptor_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/5> {
public:
TrackDescriptor_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -23,12 +23,18 @@
namespace perfetto {
namespace protos {
namespace pbzero {
class DebugAnnotation;
namespace perfetto_pbzero_enum_TrackEvent {
enum Type : int32_t;
} // namespace perfetto_pbzero_enum_TrackEvent
using TrackEvent_Type = perfetto_pbzero_enum_TrackEvent::Type;
} // Namespace pbzero.
} // Namespace protos.
} // Namespace perfetto.
namespace perfetto {
namespace protos {
namespace pbzero {
namespace perfetto_pbzero_enum_TrackEvent {
enum Type : int32_t {
@@ -63,9 +69,8 @@ const char* TrackEvent_Type_Name(
return "PBZERO_UNKNOWN_ENUM_VALUE";
}
class EventName_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class EventName_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
EventName_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -134,9 +139,8 @@ class EventName : public ::protozero::Message {
}
};
class EventCategory_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
class EventCategory_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/2> {
public:
EventCategory_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -205,9 +209,8 @@ class EventCategory : public ::protozero::Message {
}
};
class TrackEvent_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/48,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
class TrackEvent_Decoder
: public ::protozero::TypedProtoDecoder</*MAX_FIELD_ID=*/48> {
public:
TrackEvent_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
@@ -363,11 +366,11 @@ class TrackEvent : public ::protozero::Message {
9,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kEnum,
::perfetto::protos::pbzero::TrackEvent_Type,
TrackEvent_Type,
TrackEvent>;
static constexpr FieldMetadata_Type kType{};
void set_type(::perfetto::protos::pbzero::TrackEvent_Type value) {
void set_type(TrackEvent_Type value) {
static constexpr uint32_t field_id = FieldMetadata_Type::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
+132 -63
View File
@@ -6,6 +6,8 @@ import 'dart:async';
import 'dart:io';
import 'dart:ffi';
import 'package:path/path.dart' as p;
final hostArch = switch (Abi.current()) {
Abi.linuxArm => 'arm',
Abi.macosArm64 || Abi.linuxArm64 => 'arm64',
@@ -13,26 +15,63 @@ final hostArch = switch (Abi.current()) {
_ => throw 'Unsupported platform',
};
Future<void> compilePerfettoProtos() async {
final processResult = await Process.run('./tools/build.py', [
'-mdebug',
'-a$hostArch',
'third_party/perfetto:perfetto_protos_protozero',
'third_party/perfetto:perfetto_protos_dart',
]);
final int exitCode = processResult.exitCode;
final String stdout = processResult.stdout.trim();
final String stderr = processResult.stderr.trim();
if (exitCode != 0) {
print('exit-code: $exitCode');
Future<void> protoc({
required String protocPath,
required String protoPath,
required String plugin,
required String outDir,
List<String>? pluginOptions,
required List<String> protos,
}) async {
final pluginOut = [...?pluginOptions, outDir].join(':');
final args = [
'--proto_path=$protoPath',
'--plugin=protoc-gen-plugin=$plugin',
'--plugin_out=$pluginOut',
...protos,
];
print('Running: $protocPath ${args.join(' ')}');
final result = await Process.run(protocPath, args);
if (result.exitCode != 0) {
print('protoc invocation failed with ${result.exitCode}');
print('stdout:');
print('${stdout}');
print('${result.stdout}');
print('stderr:');
print('${stderr}');
print('${result.stderr}');
throw StateError(
'failed to generate protobuf files using protoc with $plugin',
);
}
}
Future<void> compilePerfettoProtos({
required String protocPath,
required String protozeroPath,
required String outDir,
}) async {
final protos = Directory('third_party/perfetto/protos')
.listSync(recursive: true)
.whereType<File>()
.where((f) => f.path.endsWith('.proto'))
.map((f) => f.path)
.toList();
await protoc(
protocPath: protocPath,
protoPath: 'third_party/perfetto',
plugin: protozeroPath,
pluginOptions: ['wrapper_namespace=pbzero'],
outDir: outDir,
protos: protos,
);
await protoc(
protocPath: protocPath,
protoPath: 'third_party/perfetto',
plugin: 'third_party/perfetto/tools/protoc_gen_dart_wrapper',
outDir: outDir,
protos: protos,
);
}
const noticesToPrepend = r'''
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -45,46 +84,28 @@ const noticesToPrepend = r'''
''';
Future<void> copyGeneratedFiles({
required Set<String> extensions,
required Directory source,
required Directory destination,
}) async {
final executable = 'cp';
final args = ['-R', source.path, destination.path];
final processResult = await Process.run(executable, args);
for (final file in Directory(source.path).listSync(recursive: true)) {
if (file is File && extensions.contains(p.extension(file.path))) {
if (file.path.endsWith('.pbenum.dart') &&
file.readAsStringSync().indexOf('class') == -1) {
// Drop empty .pbenum.dart files.
continue;
}
final int exitCode = processResult.exitCode;
final String stdout = processResult.stdout.trim();
final String stderr = processResult.stderr.trim();
if (exitCode != 0) {
print('exit-code: $exitCode');
print('stdout:');
print('${stdout}');
print('stderr:');
print('${stderr}');
}
final relativePath = p.relative(file.path, from: source.path);
final destinationPath = p.join(destination.path, relativePath);
Directory(p.dirname(destinationPath)).createSync(recursive: true);
for (final file in Directory(
'${destination.path}/protos',
).listSync(recursive: true)) {
if (!(file is File &&
(file.path.endsWith('.pbzero.h') ||
file.path.endsWith('.pb.dart') ||
file.path.endsWith('.pbenum.dart') ||
file.path.endsWith('.pbjson.dart') ||
file.path.endsWith('.pbserver.dart')))) {
continue;
final contentsIncludingPrependedNotices =
noticesToPrepend + file.readAsStringSync();
File(
destinationPath,
).writeAsStringSync(contentsIncludingPrependedNotices);
}
if (file.path.endsWith('.pbenum.dart') &&
file.readAsStringSync().indexOf('class') == -1) {
// Sometimes .pbenum.dart files that are effictively empty get generated,
// so we delete them.
file.deleteSync();
continue;
}
final contentsIncludingPrependedNotices =
noticesToPrepend + file.readAsStringSync();
file.writeAsStringSync(contentsIncludingPrependedNotices, flush: true);
}
}
@@ -93,7 +114,10 @@ void createFileThatExportsAllGeneratedDartCode() {
if (!file.existsSync()) {
file.createSync();
}
file.writeAsStringSync(noticesToPrepend + '\n');
final content = StringBuffer();
content.writeln(noticesToPrepend);
final generatedDartFilePaths =
Directory('./pkg/vm_service_protos/lib/src/protos/perfetto')
@@ -104,27 +128,72 @@ void createFileThatExportsAllGeneratedDartCode() {
generatedDartFilePaths.sort();
for (final path in generatedDartFilePaths) {
final pathToExport = path.replaceAll('./pkg/vm_service_protos/lib/', '');
file.writeAsStringSync("export '$pathToExport';\n", mode: FileMode.append);
content.writeln('export \'$pathToExport\';');
}
file.writeAsStringSync(content.toString());
}
main(List<String> files) async {
final pathDirs = (Platform.environment['PATH'] ?? '').split(':');
String? locateBinaryInPath(String binary) {
for (var dir in pathDirs) {
var path = p.join(dir, binary);
if (File(path).existsSync()) {
return path;
}
}
return null;
}
void main(List<String> args) async {
if (!Directory('./third_party/perfetto').existsSync()) {
print('Error: this tool must be run from the root directory of the SDK.');
exit(1);
return;
}
final outDir = Platform.isMacOS ? 'xcodebuild' : 'out';
final buildDir = '$outDir/Debug${hostArch.toUpperCase()}';
if (!(Platform.isLinux || Platform.isMacOS)) {
print('Error: this tool can only run on Linux or Mac OS X');
exit(1);
return;
}
await compilePerfettoProtos();
await copyGeneratedFiles(
destination: Directory('third_party/perfetto'),
source: Directory('$buildDir/gen/third_party/perfetto/protos'),
final protocPath = locateBinaryInPath('protoc');
final protozeroPath = locateBinaryInPath('protozero_plugin');
if (protocPath == null) {
print('Error: protoc binary must be available in PATH');
exit(1);
}
if (protozeroPath == null) {
print('Error: protozero_plugin binary must be available in PATH');
exit(1);
}
final tempDir = Directory.systemTemp.createTempSync(
'compile_perfetto_protos',
);
await copyGeneratedFiles(
destination: Directory('./pkg/vm_service_protos/lib/src'),
source: Directory('$buildDir/gen/pkg/vm_service_protos/lib/src/protos'),
);
createFileThatExportsAllGeneratedDartCode();
try {
await compilePerfettoProtos(
protocPath: protocPath,
protozeroPath: protozeroPath,
outDir: tempDir.path,
);
await copyGeneratedFiles(
extensions: {'.cc', '.h'},
destination: Directory('third_party/perfetto'),
source: tempDir,
);
await copyGeneratedFiles(
extensions: {'.dart'},
destination: Directory('./pkg/vm_service_protos/lib/src'),
source: tempDir,
);
createFileThatExportsAllGeneratedDartCode();
} finally {
tempDir.deleteSync(recursive: true);
}
}