| // 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 | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:hooks/hooks.dart'; | |
| import 'architecture.dart'; | |
| import 'c_compiler_config.dart'; | |
| import 'code_asset.dart'; | |
| import 'config.dart'; | |
| import 'link_mode.dart'; | |
| import 'link_mode_preference.dart'; | |
| import 'os.dart'; | |
| import 'sanitizer.dart'; | |
| import 'validation.dart'; | |
| /// The protocol extension for the `hook/build.dart` and `hook/link.dart` | |
| /// with [CodeAsset]s and [CodeConfig]. | |
| final class CodeAssetExtension extends ProtocolExtension { | |
| /// The architecture to build for. | |
| final Architecture targetArchitecture; | |
| /// The operating system to build for. | |
| final OS targetOS; | |
| /// The preferred link mode. | |
| final LinkModePreference linkModePreference; | |
| /// Optional C compiler configuration. | |
| final CCompilerConfig? cCompiler; | |
| /// Optional Android specific configuration. | |
| /// | |
| /// Required if [targetOS] is [OS.android]. | |
| final AndroidCodeConfig? android; | |
| /// Optional iOS specific configuration. | |
| /// | |
| /// Required if [targetOS] is [OS.iOS]. | |
| final IOSCodeConfig? iOS; | |
| /// Optional macOS specific configuration. | |
| /// | |
| /// Required if [targetOS] is [OS.macOS]. | |
| final MacOSCodeConfig? macOS; | |
| /// Optional compiler sanitizer to use when compiling code assets. | |
| /// | |
| /// Sanitizers (like AddressSanitizer, MemorySanitizer, or ThreadSanitizer) | |
| /// instrument binaries for runtime diagnostics. | |
| /// | |
| /// The Dart SDK JIT or AOT runtime itself can be compiled with a sanitizer. | |
| /// To run native code alongside a sanitized Dart SDK, the code assets must be | |
| /// compiled with the exact same sanitizer, ensuring they share compatible | |
| /// runtime libraries and memory allocators across the FFI boundary. | |
| final Sanitizer? sanitizer; | |
| /// Constructs a [CodeAssetExtension]. | |
| CodeAssetExtension({ | |
| required this.targetArchitecture, | |
| required this.targetOS, | |
| required this.linkModePreference, | |
| this.cCompiler, | |
| this.android, | |
| this.iOS, | |
| this.macOS, | |
| this.sanitizer, | |
| }); | |
| @override | |
| void setupBuildInput(BuildInputBuilder input) { | |
| _setupConfig(input); | |
| } | |
| @override | |
| void setupLinkInput(LinkInputBuilder input) { | |
| _setupConfig(input); | |
| } | |
| void _setupConfig(HookInputBuilder input) { | |
| input.config.addBuildAssetTypes([CodeAssetType.type]); | |
| input.config.setupCode( | |
| targetArchitecture: targetArchitecture, | |
| targetOS: targetOS, | |
| linkModePreference: linkModePreference, | |
| cCompiler: cCompiler, | |
| android: android, | |
| iOS: iOS, | |
| macOS: macOS, | |
| sanitizer: sanitizer, | |
| ); | |
| } | |
| @override | |
| Future<ValidationErrors> validateBuildInput(BuildInput input) => | |
| validateCodeAssetBuildInput(input); | |
| @override | |
| Future<ValidationErrors> validateLinkInput(LinkInput input) => | |
| validateCodeAssetLinkInput(input); | |
| @override | |
| Future<ValidationErrors> validateBuildOutput( | |
| BuildInput input, | |
| BuildOutput output, | |
| ) => validateCodeAssetBuildOutput(input, output, logger: logger); | |
| @override | |
| Future<ValidationErrors> validateLinkOutput( | |
| LinkInput input, | |
| LinkOutput output, | |
| ) => validateCodeAssetLinkOutput(input, output, logger: logger); | |
| @override | |
| Future<ValidationErrors> validateApplicationAssets( | |
| List<EncodedAsset> assets, | |
| ) => validateCodeAssetInApplication(assets); | |
| @override | |
| Iterable<Uri> outputFiles(List<EncodedAsset> assets) sync* { | |
| for (final encodedAsset in assets) { | |
| if (encodedAsset.isCodeAsset) { | |
| final asset = encodedAsset.asCodeAsset; | |
| if (asset.linkMode is DynamicLoadingBundled || | |
| asset.linkMode is StaticLinking) { | |
| final file = asset.file; | |
| if (file != null) { | |
| yield file; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } |