buildHookDart function

String buildHookDart({
  1. required List<NativeAssetsModule> modules,
  2. String vendoredDir = 'src/nitro_native',
})

Contents of hook/build.dart — one CBuilder.library per modules entry (multi-module plugins build one code asset each; each module's generated Dart resolves against its own asset). The vendored Dart DL API in vendoredDir is compiled into every asset.

Implementation

String buildHookDart({
  required List<NativeAssetsModule> modules,
  String vendoredDir = 'src/nitro_native',
}) {
  String builder(NativeAssetsModule m) {
    final sources = [
      ...m.cppSources,
      for (final c in nativeAssetsVendoredCSources) '$vendoredDir/$c',
    ].map((s) => "        '$s',").join('\n');
    return '''    await CBuilder.library(
      name: '${m.libStem}',
      assetName: '${m.libStem}',
      language: Language.cpp,
      sources: [
$sources
      ],
      // vendored nitro C runtime + the generated-cpp dir (the impl #includes
      // <lib>.native.g.h, which lives beside the generated bridge).
      includes: ['$vendoredDir', 'lib/src/generated/cpp'],
      std: 'c++17',
      cppLinkStdLib: android ? 'c++_static' : null,
    ).run(input: input, output: output, logger: logger);''';
  }

  final builders = modules.map(builder).join('\n');
  return '''
// GENERATED BY nitrogen — native-assets build hook (do not edit).
import 'dart:io';

import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:logging/logging.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';

// Compiles each Nitro C++ bridge + impl (+ vendored Dart DL API) into its own
// code asset. CBuilder cross-compiles for whichever target the SDK/Flutter
// requests (xcrun / NDK / clang / cl); the generated `@Native` bindings resolve
// against these assets.
void main(List<String> args) async {
  await build(args, (input, output) async {
    // Android's NDK defaults to the SHARED libc++ (libc++_shared.so), which a
    // bare code asset doesn't bundle → dlopen fails. Link it statically so the
    // .so is self-contained. Apple/Linux keep their system default.
    final android = input.config.code.targetOS == OS.android;
    // Root logger ('') — setting .level on a NAMED logger throws unless
    // hierarchicalLoggingEnabled is set, so use the root here.
    final logger = Logger('')
      ..level = Level.SEVERE
      ..onRecord.listen((r) => stderr.writeln('\${r.level.name}: \${r.message}'));
$builders
  });
}
''';
}