package:prebuilt_code_assetsShared build and link hook infrastructure for Dart packages that distribute prebuilt native code assets (via GitHub Releases or bundled prebuilt/ directories), support compiling from source through a toolchain-agnostic buildFromSource callback (e.g. CBuilder from package:native_toolchain_c, CMake, or Cargo), and tree-shake static libraries in hook/link.dart via @RecordUse.
Modeled after CLibrary in package:native_toolchain_c, a single PrebuiltLibrary specification is defined once and shared across hook/build.dart, hook/link.dart, tool/precompile_binaries.dart, and tool/regenerate_hashes.dart.
PrebuiltLibrary specification:library.build(input: input, output: output) for hook/build.dart.library.link(input: input, output: output) for hook/link.dart.library.buildStandalone(...) (via BuildInputBuilder) for standalone CI scripts.buildMode under hooks.user_defines.<package_name>):fetch (default): Uses a pub-bundled prebuilt/ binary if present, or downloads the prebuilt binary, verifies its SHA-256 digest, and caches it in outputDirectoryShared (in an ABI-specific subdirectory preserving the canonical OS library filename for iOS/macOS XCFrameworks). Downloads are streamed, retried on transient failures, and written atomically. Optionally falls back to buildFromSource if no binary is available.build (alias checkout): Compiles from source using buildFromSource (optionally from checkoutPath).local: Bundles a pre-existing dynamic library from localPath.treeshake under hooks.user_defines.<package_name>):usedSymbols, such as SymbolsResolvers.fromRecordUseMapping (ffigen) or SymbolsResolvers.fromMethodPrefix (e.g. Diplomat). Without usedSymbols, the library is never tree-shaken, and the build hook bundles the dynamic library directly.auto (default): Tree-shakes when possible. If no static library is released for a target, or if linking fails in fetch mode (e.g. no C toolchain for the target), prints a warning and bundles the prebuilt dynamic library instead.on: Always tree-shakes, and fails the build if that is not possible.off: Never tree-shakes; bundles the dynamic library directly without running the C linker.fetch mode bundles the prebuilt dynamic library. When building from source, the link hook links the static library keeping all functions, except on Windows, where a DLL only exports the functions it lists; that fails the build (use treeshake: off instead).package:native_toolchain_c only exports the used functions that the .lib defines.__declspec(dllexport) when compiling the static library: the linker then exports, and so keeps, every such function in each object file it links, even unused ones. The .def file already determines the exports.package:prebuilt_code_assets/tools.dart):runPrecompileBinariesCli for tool/precompile_binaries.dart.runRegenerateHashesCli for tool/regenerate_hashes.dart (supports both local artifact directories and remote release URLs, and refuses to write an incomplete manifest when downloads fail).PrebuiltLibrary (lib/src/hook_helpers/library.dart)import 'package:prebuilt_code_assets/prebuilt_code_assets.dart'; import 'package:record_use/record_use.dart' as record_use; import '../bindings/record_use_mapping.g.dart'; import 'hashes.dart'; final myLibrary = PrebuiltLibrary( name: 'my_lib', assetName: 'my_package.dart', releaseConfig: PrebuiltReleaseConfig.github( owner: 'my-org', repo: 'my_package', version: version, fileHashes: fileHashes, libraryName: 'my_lib', ), buildFromSource: (input, output, {required static, checkoutPath}) async { // Compile with your toolchain (e.g. `CBuilder`, CMake, or Cargo), add the // sources you read to `output.dependencies`, and return the Uri of the // built static (if `static`) or dynamic library. }, usedSymbols: SymbolsResolvers.fromRecordUseMapping( const record_use.Library('package:my_package/src/bindings/bindings.g.dart'), recordUseMapping, ), );
For release layouts other than <repo>-<target>-<libraryFileName>, pass a custom resolveAssetName to PrebuiltReleaseConfig.github, or use the PrebuiltReleaseConfig constructor directly.
hook/build.dart and hook/link.dart// hook/build.dart import 'package:hooks/hooks.dart'; import 'package:my_package/src/hook_helpers/library.dart'; Future<void> main(List<String> args) async { await build(args, (input, output) async { await myLibrary.build(input: input, output: output); }); }
// hook/link.dart import 'package:hooks/hooks.dart'; import 'package:my_package/src/hook_helpers/library.dart'; Future<void> main(List<String> args) async { await link(args, (input, output) async { await myLibrary.link(input: input, output: output); }); }
Both methods accept an optional Logger; by default messages are printed to the hook's stdout/stderr.
user_defines in pubspec.yamlConsumers of your package configure how the native library is obtained and whether it is tree-shaken under hooks.user_defines.<package_name> in their workspace or application pubspec.yaml:
hooks: user_defines: my_package: # 'fetch' (default), 'build' (alias 'checkout'), or 'local' buildMode: fetch # 'auto' (default), 'on', or 'off' treeshake: auto # Path to a local source checkout (used when buildMode is 'build') # checkoutPath: ../path/to/checkout # Path to a pre-existing dynamic library on disk (required when buildMode is 'local') # localPath: /absolute/or/relative/path/to/libmy_lib.so
| Key | Type | Description |
|---|---|---|
buildMode | String | 'fetch' (default: use bundled prebuilt/ or download from release URL), 'build' / 'checkout' (compile from source), or 'local' (use a binary at localPath). |
treeshake | String or bool | 'auto' (default), 'on' / true, or 'off' / false. See Features. |
local_build | bool | Shorthand used by dart-lang/native examples: local_build: true means buildMode: build. Ignored if buildMode is set. |
checkoutPath | String (path) | Optional path to a local source directory when buildMode is 'build'. |
localPath | String (path) | Path to a pre-built dynamic library file when buildMode is 'local'. |
Relative paths are resolved against the pubspec.yaml that defines them. Unknown values fail the build with an explanation (set strictBuildOptions: false on PrebuiltLibrary to fall back to the defaults instead).