blob: 99d21c71653c32699e5894e685c302a7cac21a71 [file] [log] [blame] [edit]
// Copyright (c) 2024, 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 'package:logging/logging.dart';
import 'build_config.dart';
import 'build_output.dart';
import 'linker.dart';
/// A builder to be run during a build hook.
///
/// [Builder]s should be used to build native code, download assets, and
/// transform assets. A build hook is only rerun when its declared
/// [BuildOutput.dependencies] change. ([Linker]s have access to tree-shaking
/// information in some build modes, and could potentially build or download
/// less assets. However, due to the tree-shaking information being an input to
/// link hooks, link hooks are re-run much more often.)
///
/// A package to be used in build hooks should implement this interface. The
/// typical pattern of build hooks should be a declarative specification of one
/// or more builders (constructor calls), followed by [run]ning these builders.
///
/// For example with a single builder from `package:native_toolchain_c`:
///
/// ```dart
/// import 'package:logging/logging.dart';
/// import 'package:native_assets_cli/native_assets_cli.dart';
/// import 'package:native_toolchain_c/native_toolchain_c.dart';
///
/// void main(List<String> args) async {
/// await build(args, (config, output) async {
/// final packageName = config.packageName;
/// final cbuilder = CBuilder.library(
/// name: packageName,
/// assetName: '$packageName.dart',
/// sources: [
/// 'src/$packageName.c',
/// ],
/// );
/// await cbuilder.run(
/// buildConfig: config,
/// buildOutput: output,
/// logger: Logger('')
/// ..level = Level.ALL
/// ..onRecord.listen((record) => print(record.message)),
/// );
/// });
/// }
/// ```
///
/// The builder is designed to immediately operate on [BuildConfig]. If a
/// builder should deviate behavior from the build config, this should be
/// configurable through a constructor parameter. For example, if a native
/// compiler should output a static library to be sent to a linker, but the
/// [BuildConfig.linkModePreference] is set to dynamic linking, the builder
/// should have its own `linkModePreference` parameter in the constructor.
///
/// The builder is designed to immediately operate on [BuildOutput]. If a
/// builder should output something else than standard, it should be
/// configurable through a constructor parameter. For example to send an asset
/// for linking to the output ([BuildOutput.addEncodedAsset] with
/// `linkInPackage` set), the builder should have a constructor parameter.
/// (Instead of capturing the BuildOutput as a return value and manually
/// manipulating it in the build hook.) This ensures that builder is in control
/// of what combination of build outputs are valid.
abstract interface class Builder {
/// Runs this build.
///
/// Reads the config from [config], streams output to [output], and streams
/// logs to [logger].
Future<void> run({
required BuildConfig config,
required BuildOutput output,
required Logger? logger,
});
}