code_assets library
This package provides the API for code assets to be used with
package:hooks.
A CodeAsset is an asset containing executable code which respects the native application binary interface (ABI). These assets are bundled with a Dart or Flutter application. They can be produced by compiling C, C++, Objective-C, Rust, or Go code for example.
This package is used in a build hook (hook/build.dart) or link hook
(hook/link.dart) to inform the Dart and Flutter SDKs about the code assets
that need to be bundled with an application.
A CodeAsset can be added to the BuildOutputBuilder in a build hook as
follows:
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
void main(List<String> args) async {
await build(args, (input, output) async {
if (input.config.buildCodeAssets) {
final packageName = input.packageName;
final assetPathInPackage = input.packageRoot.resolve('...');
final assetPathDownload = input.outputDirectoryShared.resolve('...');
output.assets.code.add(
CodeAsset(
package: packageName,
name: '...',
linkMode: DynamicLoadingBundled(),
file: assetPathInPackage,
),
);
}
});
}
When compiling C, C++ or Objective-C code from source, consider using
package:native_toolchain_c
with a build hook and a link hook. First, define the C library
specification in a shared file:
import 'package:native_toolchain_c/native_toolchain_c.dart';
/// The C build specification for the sqlite library.
///
/// It is used by the build and link hooks in the `hook/` directory.
final cLibrary = CLibrary(
name: 'sqlite3',
assetName: 'src/third_party/sqlite3.g.dart',
sources: ['third_party/sqlite/sqlite3.c'],
);
Next, compile the library in the build hook:
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:sqlite/src/c_library.dart';
void main(List<String> args) async {
await build(args, (input, output) async {
if (input.config.buildCodeAssets) {
await cLibrary.build(
input: input,
output: output,
defines: {
if (input.config.code.targetOS == OS.windows)
// Ensure symbols are exported in dll.
'SQLITE_API': '__declspec(dllexport)',
},
);
}
});
}
Finally, tree-shake and link the library in the link hook:
import 'package:hooks/hooks.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';
import 'package:record_use/record_use.dart';
import 'package:sqlite/src/c_library.dart';
import 'package:sqlite/src/third_party/record_use_mapping.dart';
void main(List<String> arguments) async {
await link(arguments, (input, output) async {
await cLibrary.link(
input: input,
output: output,
linkerOptions: LinkerOptions.treeshake(
symbolsToKeep: input.recordedUses?.calls.keys.cast<Method>().map(
(e) => recordUseMapping[e.name]!,
),
),
);
});
}
See the full example in example/sqlite/.
When interfacing with system libraries, the API in this package is enough:
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
void main(List<String> args) async {
await build(args, (input, output) async {
if (input.config.buildCodeAssets) {
switch (input.config.code.targetOS) {
case OS.android || OS.iOS || OS.linux || OS.macOS:
output.assets.code.add(
CodeAsset(
package: 'host_name',
name: 'src/third_party/unix.dart',
linkMode: LookupInProcess(),
),
);
case OS.windows:
output.assets.code.add(
CodeAsset(
package: 'host_name',
name: 'src/third_party/windows.dart',
linkMode: DynamicLoadingSystem(Uri.file('ws2_32.dll')),
),
);
case final os:
throw UnsupportedError('Unsupported OS: ${os.name}.');
}
}
});
}
The CodeConfig nested in the HookInput gives access to configuration
specifically for compiling code assets. For example CodeConfig.targetOS
and CodeConfig.targetArchitecture give access to the target OS and
architecture that the code assets are compiled for:
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
void main(List<String> args) async {
await build(args, (input, output) async {
if (input.config.buildCodeAssets) {
final codeConfig = input.config.code;
final targetOS = codeConfig.targetOS;
final targetArchitecture = codeConfig.targetArchitecture;
// Add some code assets.
}
});
}
For more information about build and link hooks see dart.dev/tools/hooks.
Classes
- AndroidCodeConfig
- The configuration for CodeAssets for target OS OS.android in CodeConfig.android.
- Architecture
- A hardware architecture which the Dart VM can run on.
- BuildOutputCodeAssetBuilder
-
Extension on
BuildOutputBuilderto add CodeAssets. - CCompilerConfig
- The configuration for a C toolchain inside CodeConfig.cCompiler.
- CodeAsset
- An asset containing executable code which respects the native application binary interface (ABI).
- CodeAssetExtension
-
The protocol extension for the
hook/build.dartandhook/link.dartwith CodeAssets and CodeConfig. - CodeConfig
-
The configuration for CodeAssets in
HookConfig. - DeveloperCommandPrompt
- The configuration for the Windows Developer Command Prompt in WindowsCCompilerConfig.developerCommandPrompt.
- DynamicLoadingBundled
- CodeAssets with this LinkMode will be bundled as dynamic libraries by Dart/Flutter at build time.
- DynamicLoadingSystem
-
CodeAssets with this LinkMode are expected to be available as dynamic
library on the target system
PATH. - IOSCodeConfig
- The configuration for CodeAssets for target OS OS.iOS in CodeConfig.iOS.
- IOSSdk
- The iOS SDK (device or simulator) in IOSCodeConfig.targetSdk.
- LinkMode
- The link mode for a CodeAsset.
- LinkModePreference
- The preferred link mode for CodeAssets in CodeConfig.linkModePreference.
- LinkOutputCodeAssetBuilder
-
Extension on
LinkOutputBuilderto add CodeAssets. - LookupInExecutable
-
CodeAssets with this LinkMode are expected to have their symbols
available through
DynamicLibrary.executable(). - LookupInProcess
-
CodeAssets with this LinkMode are expected to have their symbols
available through
DynamicLibrary.process(). - MacOSCodeConfig
- The configuration for CodeAssets for target OS OS.macOS in CodeConfig.macOS.
- OS
- An operating system which the Dart VM can run on.
- Sanitizer
- A compiler sanitizer.
- StaticLinking
- CodeAssets with this LinkMode are linked statically.
- WindowsCCompilerConfig
- The configuration provided in CCompilerConfig.windows when CodeConfig.targetOS is OS.windows.
Extensions
- BuildOutputAssetsBuilderCode on BuildOutputAssetsBuilder
-
Extension on
BuildOutputBuilderto add CodeAssets. - BuildOutputCodeAssets on BuildOutputAssets
-
The CodeAssets in
BuildOutputAssets.encodedAssets. - EncodedCodeAsset on EncodedAsset
-
Methods on
EncodedAssetfor CodeAssets. - HookConfigCodeConfig on HookConfig
-
Extension to the
HookConfigproviding access to configuration specific to code assets (only available if code assets are supported). - LinkInputCodeAssets on LinkInputAssets
-
Extension to the
LinkInputproviding access to configuration specific to code assets as well as code asset inputs to the linker (only available if code assets are supported). - LinkOutputAssetsBuilderCode on LinkOutputAssetsBuilder
-
Extension on
LinkOutputBuilderto add CodeAssets. - LinkOutputCodeAssets on LinkOutputAssets
-
The CodeAssets in
LinkOutputAssets.encodedAssets. - OSLibraryNaming on OS
- Provides OS-specific library naming conventions.
Functions
-
testCodeBuildHook(
{required FutureOr< void> mainMethod(List<String> arguments), required FutureOr<void> check(BuildInput, BuildOutput), bool? linkingEnabled, Architecture? targetArchitecture, OS? targetOS, IOSSdk? targetIOSSdk = IOSSdk.iPhoneOS, int? targetIOSVersion = 17, int? targetMacOSVersion = 13, int? targetAndroidNdkApi = 30, CCompilerConfig? cCompiler, LinkModePreference? linkModePreference = LinkModePreference.dynamic, PackageUserDefines? userDefines, Map<String, List< ? assets}) → Future<EncodedAsset> >void> -
Tests the main function of a
hook/build.dartwith CodeAssets.