dart-sdk/build/gn_dart_compile_exe.py
Vyacheslav Egorov a4dd314c9e [tools] Allow precompiling gen_kernel and compile_platform
When iterating on core library changes or changes in the AOT compiler
many seconds are wasted waiting on gen_kernel/compile_platform to
parse Dart code. This happens because we are running these tools
from sources on prebuilt Dart SDK.

This CL allows SDK developer to opt-in into AOT compiling these
tools by adding `precompile_tools=true` to their DART_GN_ARGS.

AOT compilation is performed using prebuilt SDK - so these
executables do not need to be recompiled if core libraries or
VM changes reducing iteration cycles.

pkg/vm/tool/precompiler2 is tweaked to detect when DART_GN_ARGS
contains `precompile_tools=true` and use precompiled
gen_kernel.exe instead of running it from source.

Using precompiled compile_platform takes vm_platform_strong.dill
build from 20 seconds to 3 seconds.

Using precompiled gen_kernel takes small benchmark build from
~10 seconds to 2 seconds.

This relands 5cda2a871c with fixes
for Flutter build.

TEST=manually tested

Change-Id: I552861c80c152890655e41baaf6ea3fb3b03a57e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/367961
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2024-05-24 09:40:39 +00:00

152 lines
4.9 KiB
Python
Executable file

#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Helper script for GN to run `dart compile exe` and produce a depfile.
Run with:
python3 gn_dart_compile_exe.py \
--dart-binary <path to dart binary> \
--entry-point <path to dart entry point> \
--output <path to resulting executable> \
--sdk-hash <SDK hash> \
--packages <path to package config file> \
--depfile <path to depfile to write>
This is workaround for `dart compile exe` not supporting --depfile option
in the current version of prebuilt SDK. Once we roll in a new version
of checked in SDK we can remove this helper.
"""
import argparse
import os
import sys
import subprocess
from tempfile import TemporaryDirectory
def parse_args(argv):
parser = argparse.ArgumentParser()
parser.add_argument("--dart-sdk",
required=True,
help="Path to the prebuilt Dart SDK")
parser.add_argument("--sdk-hash", required=True, help="SDK hash")
parser.add_argument("--entry-point",
required=True,
help="Dart entry point to precompile")
parser.add_argument("--output",
required=True,
help="Path to resulting executable ")
parser.add_argument("--packages",
required=True,
help="Path to package config file")
parser.add_argument("--depfile",
required=True,
help="Path to depfile to write")
return parser.parse_args(argv)
# Run a command, swallowing the output unless there is an error.
def run_command(command):
try:
subprocess.check_output(command, stderr=subprocess.STDOUT)
return True
except subprocess.CalledProcessError as e:
print("Command failed: " + " ".join(command) + "\n" + "output: " +
_decode(e.output))
return False
except OSError as e:
print("Command failed: " + " ".join(command) + "\n" + "output: " +
_decode(e.strerror))
return False
def _decode(bytes):
return bytes.decode("utf-8")
def main(argv):
args = parse_args(argv[1:])
# Unless the path is absolute, this script is designed to run binaries
# produced by the current build, which is the current working directory when
# this script is run.
prebuilt_sdk = os.path.abspath(args.dart_sdk)
dart_binary = os.path.join(prebuilt_sdk, "bin", "dart")
if not os.path.isfile(dart_binary):
print("Binary not found: " + dart_binary)
return 1
dartaotruntime_binary = os.path.join(prebuilt_sdk, "bin", "dartaotruntime")
if not os.path.isfile(dartaotruntime_binary):
print("Binary not found: " + dartaotruntime_binary)
return 1
gen_kernel_snapshot = os.path.join(prebuilt_sdk, "bin", "snapshots",
"gen_kernel_aot.dart.snapshot")
if not os.path.isfile(gen_kernel_snapshot):
print("Binary not found: " + gen_kernel_snapshot)
return 1
platform_dill = os.path.join(prebuilt_sdk, "lib", "_internal",
"vm_platform_strong.dill")
if not os.path.isfile(platform_dill):
print("Binary not found: " + platform_dill)
return 1
# Compile the executable.
ok = run_command([
dart_binary,
"compile",
"exe",
"--packages",
args.packages,
f"-Dsdk_hash={args.sdk_hash}",
"-o",
args.output,
args.entry_point,
])
if not ok:
return 1
# Collect dependencies by using gen_kernel.
with TemporaryDirectory() as tmpdir:
output_dill = os.path.join(tmpdir, "output.dill")
ok = run_command([
dartaotruntime_binary,
gen_kernel_snapshot,
"--platform",
platform_dill,
"--packages",
args.packages,
"--depfile",
args.depfile,
"-o",
output_dill,
args.entry_point,
])
if not ok:
return 1
# Fix generated depfile to refer to the output file name instead
# of referring to the temporary dill file we have generated.
with open(args.depfile, "r") as f:
content = f.read()
(target_name, deps) = content.split(": ", 1)
if target_name != output_dill:
print(
"ERROR: Something is wrong with generated depfile: expected {output_dill} as target, but got {target_name}"
)
return 1
with open(args.depfile, "w") as f:
f.write(args.output)
f.write(": ")
f.write(deps)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))