link function
- List<
String> arguments, - Future<
void> linker(- LinkInput input,
- LinkOutputBuilder output
Links assets in a hook/link.dart.
If a link hook is defined (hook/link.dart) then link must be called by
that hook, to write the BuildInput.outputFile, even if the linker
function has no work to do.
Can link native assets which are not already available, or expose existing files. Each individual asset is assigned a unique asset ID.
The linking script may receive assets from build scripts, which are accessed through LinkInputAssets.encodedAssets. They will only be bundled with the final application if included in the LinkOutput.
import 'package:data_assets/data_assets.dart';
import 'package:hooks/hooks.dart';
void main(List<String> args) async {
await link(args, (input, output) async {
final dataEncodedAssets = input.assets.encodedAssets.where(
(e) => e.isDataAsset,
);
output.assets.addEncodedAssets(dataEncodedAssets);
});
}
If the linker fails, it must throw a HookError. Link hooks are
guaranteed to be invoked with a process invocation and should return a
non-zero exit code on failure. Throwing will lead to an uncaught exception,
causing a non-zero exit code.
Environment
Link hooks are executed in a semi-hermetic environment. This means that
Platform.environment does not expose all environment variables from the
parent process. This ensures that hook invocations are reproducible and
cacheable, and do not depend on accidental environment variables.
However, some environment variables are necessary for locating tools (like compilers) or configuring network access. The following environment variables are passed through to the hook process:
- Path and system roots:
PATH: Invoke native tools.HOME,USERPROFILE: Find tools in default install locations.SYSTEMDRIVE,SYSTEMROOT,WINDIR: Process invocations and CMake on Windows.PROGRAMDATA: Forvswhere.exeon Windows.
- Temporary directories:
TEMP,TMP,TMPDIR: Temporary directories.
- HTTP proxies:
HTTP_PROXY,HTTPS_PROXY,NO_PROXY: Network access behind proxies.
- Clang/LLVM:
LIBCLANG_PATH: Rust'sbindgen+clang-sys.
- Android NDK:
ANDROID_HOME: Standard location for the Android SDK/NDK.ANDROID_NDK,ANDROID_NDK_HOME,ANDROID_NDK_LATEST_HOME,ANDROID_NDK_ROOT: Alternative locations for the NDK.
- Ccache:
- Any variable starting with
CCACHE_.
- Any variable starting with
- Nix:
- Any variable starting with
NIX_.
- Any variable starting with
Any changes to these environment variables will cause cache invalidation for hooks.
All other environment variables are stripped.
Debugging
When a link hook doesn't work as expected, you can investigate the intermediate files generated by the Dart and Flutter SDK build process.
The most important files for debugging are located in a subdirectory
specific to your hook's execution. The path is of the form
.dart_tool/hooks_runner/<package_name>/<some_hash>/, where
<package_name> is the name of the package containing the hook. Inside, you
will find:
input.json: The configuration and data passed into your link hook.output.json: The JSON data that your link hook produced.stdout.txt: Any standard output from your link hook.stderr.txt: Any error messages or exceptions.
When you run a build, hooks for all dependencies are executed, so you might see multiple package directories.
The <some_hash> is a checksum of the LinkConfig in the input.json. If
you are unsure which hash directory to inspect within your package's hook
directory, you can delete the .dart_tool/hooks_runner/<package_name>/
directory and re-run the command that failed. The newly created directory
will be for the latest invocation.
You can step through your code with a debugger by running the link hook from
its source file and providing the input.json via the --config flag:
dart run hook/link.dart --config .dart_tool/hooks_runner/<package_name>/<some_hash>/input.json
To debug in VS Code, you can create a launch.json file in a .vscode
directory in your project root. This allows you to run your hook with a
debugger attached.
Here is an example configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Link Hook",
"type": "dart",
"request": "launch",
"program": "hook/link.dart",
"args": [
"--config",
".dart_tool/hooks_runner/your_package_name/some_hash/input.json"
]
}
]
}
Again, make sure to replace your_package_name, and some_hash with the
actual paths from your project. After setting this up, you can run the
"Debug Link Hook" configuration from the "Run and Debug" view in VS Code.
Implementation
Future<void> link(
List<String> arguments,
Future<void> Function(LinkInput input, LinkOutputBuilder output) linker,
) async {
final inputPath = getInputArgument(arguments);
final bytes = File(inputPath).readAsBytesSync();
final jsonInput =
const Utf8Decoder().fuse(const JsonDecoder()).convert(bytes)
as Map<String, Object?>;
final input = LinkInput(jsonInput);
final outputFile = input.outputFile;
final output = LinkOutputBuilder();
try {
await linker(input, output);
// ignore: avoid_catching_errors
} on HookError catch (e, st) {
output.setFailure(e.failureType);
await _writeOutput(output, outputFile);
_exitViaHookException(e, st);
}
final errors = await ProtocolBase.validateLinkOutput(
input,
LinkOutput(output.json),
);
if (errors.isNotEmpty) {
final message = [
'The output contained unsupported output:',
for (final error in errors) '- $error',
].join('\n');
stderr.writeln(message);
output.setFailure(.build);
await _writeOutput(output, outputFile);
exit(BuildError(message: message).exitCode);
}
await _writeOutput(output, outputFile);
}