run method

Future<void> run({
  1. required BuildInput input,
  2. required BuildOutputBuilder output,
  3. required Logger? logger,
})

Run the native build pipeline.

This is the main entry point that replaces PrebuiltCodeAssetBuilder.run.

Implementation

Future<void> run({
  required BuildInput input,
  required BuildOutputBuilder output,
  required Logger? logger,
}) async {
  final code = input.config.code;
  if (!input.config.buildCodeAssets) {
    _logInfo(
      logger,
      'Skipping native_prebuilt: buildCodeAssets is disabled.',
    );
    return;
  }

  final target = targetFromCodeConfig(code);
  final configuredLinkMode = project.asset.linkMode;
  final requestedLinkMode = _requestedLinkMode(
    code.linkModePreference,
    configuredLinkMode,
  );
  final manifestPayload = project.prebuilts.artifacts[target.label]?.payload;
  final payload = _payloadForRequest(
    requestedLinkMode: requestedLinkMode,
    manifestPayload: manifestPayload,
  );
  final linkMode = _linkModeForPayload(payload, requestedLinkMode);

  _logInfo(
    logger,
    'Resolving ${project.asset.libraryStem} for ${target.label} '
    '(${payload is DynamicLibraryPayload ? 'dynamic' : 'static'}).',
  );

  // Try prebuilt resolution first
  if (project.prebuiltPolicy == PrebuiltPolicy.preferPrebuilt &&
      _manifestSupportsPayload(manifestPayload, payload)) {
    final context = PrebuiltResolutionContext(
      input: input,
      manifest: project.prebuilts,
      target: target,
      libraryStem: project.asset.libraryStem,
      payload: payload,
      localSearchRoot: Directory.fromUri(input.outputDirectory),
      logger: logger,
    );

    final chain =
        resolvers ??
        [
          UserDefinePrebuiltResolver(),
          LocalPrebuiltResolver(directoryName: localDirectoryName),
          SharedCacheResolver(),
        ];

    ResolvedPrebuilt? result;
    for (final resolver in chain) {
      _logInfo(logger, 'Trying ${resolver.runtimeType}...');
      result = await resolver.resolve(context);
      if (result != null) break;
    }

    if (result is ResolvedPrebuiltFound) {
      final libraryName = canonicalLibraryName(
        target: target,
        libraryStem: project.asset.libraryStem,
        payload: payload,
      );
      final bundledLibUri = input.outputDirectory.resolve(libraryName);

      await File(result.file.path).copy(File.fromUri(bundledLibUri).path);

      output.assets.code.add(
        CodeAsset(
          package: input.packageName,
          name: project.asset.assetName,
          linkMode: linkMode,
          file: bundledLibUri,
        ),
      );

      _logInfo(
        logger,
        'Using prebuilt ${project.asset.libraryStem} for ${target.label} '
        '(from ${result.source.label})',
      );
      return;
    }
  }

  // Fall back to source build
  _logInfo(
    logger,
    'No prebuilt available for ${target.label}; attempting source build.',
  );

  // Check if we have a recipe for this target
  final recipe = project.build.recipeFor(target);

  if (recipe != null) {
    // Use the new recipe-based build system via executor
    await _buildWithExecutor(
      target: target,
      linkMode: linkMode,
      payload: payload,
      input: input,
      output: output,
      logger: logger,
    );
    return;
  }

  // Fall back to source builder callback if available
  if (sourceFallback != null) {
    await _buildWithSourceFallback(
      target: target,
      linkMode: linkMode,
      payload: payload,
      input: input,
      output: output,
      logger: logger,
    );
    return;
  }

  final message =
      'No build recipe or source fallback for ${project.asset.libraryStem} '
      'on ${target.label}.';
  _logWarning(logger, message);
  throw StateError(message);
}