Skip to content

Commit cb9bd7e

Browse files
authored
Build hook spec (#955)
To be followed up by a v2.md
1 parent 876f9a1 commit cb9bd7e

File tree

1 file changed

+227
-0
lines changed
  • pkgs/native_assets_builder/doc/protocol

1 file changed

+227
-0
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
Build Hook Specification
2+
========================
3+
4+
Version 1: As of 2024-01-24 implemented behind `--enable-experiment=native-assets`
5+
6+
### Concepts
7+
8+
#### Asset
9+
10+
An asset is data which is accessible from a Dart or Flutter application. To retrieve an asset at runtime, we associate with it a string as a unique identifier, the `assetId`. There are several example types of assets:
11+
* Assets which designate symbols present in the target system, process, or executable. They are identified by their name.
12+
* Dynamic libraries bundled into the application.
13+
14+
An application is compiled to run on a certain target OS and architecture. If different targets require different assets, the package developer must specify which asset to bundle for which target.
15+
16+
An asset has different ways of being accessible in the final application. It is either brought in "manually" by having the package developer specify a path of the asset on the current system, it can be part of the Dart or Flutter SDK, or it can be already present in the target system. If the asset is bundled "manually", the Dart or Flutter SDK will take care of copying the asset from its specified location on the current system into the application bundle.
17+
18+
Assets are also called "native assets" to differentiate them from the Dart code also bundled with an application.
19+
20+
#### AssetId
21+
An asset must have a string identifier called `assetId`. Dart code that uses an asset, references the asset using this `assetId`.
22+
23+
A package must prefix all `assetId`s it defines with: `package:<package>/`, `<package>` being the current package's name. This ensures assets don't conflict between packages.
24+
25+
Additionally, the convention is that an asset referenced from `lib/src/foo.dart` in `package:foo` has the `assetId` `'package:foo/src/foo.dart'`.
26+
27+
#### Target
28+
29+
A target specifies the operating system and architecture of the targeted platform of the application.
30+
31+
#### `build.dart`
32+
Any package which needs to access assets at runtime must define a `build.dart` script to specify these assets. If there are assets in a package which are not shipped as part of Dart or Flutter and also not present on the target system by default, those assets will be bundled into the final application by the Dart or Flutter SDK automatically. The `build.dart` script takes as input information such as the target OS and architecture in a `build_config.yaml` file, and returns as output a list of assets which can be accessed at runtime in a `build_output.yaml` file.
33+
34+
### `build_config.yaml`
35+
36+
This is the structure of the input to a `build.dart` script.
37+
38+
```yaml
39+
# Build in dry-run mode.
40+
#
41+
# Running in dry-run mode `<out_dir>/build_output.yaml` must be written, but
42+
# the files it references need not exist.
43+
dry_run: true | false
44+
45+
# Build Mode.
46+
#
47+
# A hint `build.dart` can use to determined which optimizations to enable and
48+
# whether or not to include debug symbols in the format relevant for the asset.
49+
#
50+
# Not provided on dry runs.
51+
build_mode: release | debug
52+
53+
# Metadata as output from build.dart from direct dependencies.
54+
#
55+
# Not provided on dry runs.
56+
dependency_metadata:
57+
# package name of direct dependency.
58+
some_package_name:
59+
# key value pairs.
60+
some_key: some_value
61+
62+
# Preferred link mode
63+
link_mode_preference: dynamic | static | prefer-dynamic | prefer-static
64+
65+
# Path to output directory where assets should be placed.
66+
#
67+
# This is also where `build_output.yaml` should be written.
68+
#
69+
# Remark: Avoid using the name "build_output.yaml" for an asset file, this is
70+
# forbidden.
71+
out_dir: /absolute/path/to/out_dir/
72+
73+
# Name of the package that contains the `build.dart`
74+
#
75+
# Remark: This is entirely redundant since this is a config file specified to
76+
# `build.dart`, and the author of `build.dart` probably knows the name of the
77+
# package they are writing.
78+
package_name: my_package_with_native_assets
79+
80+
# Path to root folder for the package that contains `build.dart`.
81+
#
82+
# This is useful if `build.dart` wishes to find source code files embedded in
83+
# its own package and compile them to an asset.
84+
#
85+
# Note that this will be most likely a path in the pub cache when the package
86+
# with a `build.dart` is a dependency of another package.
87+
package_root: /absolute/path/to/my_package_with_native_assets
88+
89+
# Target architecture
90+
#
91+
# Combined with `target_os` this specifies the "target" for which assets
92+
# should be built.
93+
#
94+
# Not provided on dry runs.
95+
target_architecture: x64 | ia32 | arm | arm64 | riscv32 | riscv64
96+
97+
# Target operating system
98+
#
99+
# Combined with `target_architecture` this specifies the "target" for which
100+
# assets should be built.
101+
target_os: android | ios | linux | macos | windows
102+
103+
# Schema version of this file.
104+
version: 1.0.0
105+
```
106+
107+
### `build_output.yaml`
108+
109+
This file is the output from running a `build.dart` script, and contains the list of assets to be bundled into the application.
110+
111+
```yaml
112+
# The list of assets.
113+
#
114+
# In dry runs, must contain assets for each architecture for the requested os.
115+
assets:
116+
- id: 'package:my_package_with_native_assets/src/foo.dart'
117+
link_mode: dynamic | static | prefer-dynamic | prefer-static
118+
path:
119+
path_type: absolute | system | process | executable
120+
# Only provided for path_type absolute and system.
121+
#
122+
# If path_type absolute: The absolute path to the file name on the
123+
# current machine.
124+
#
125+
# If path_type system: The path of the dynamic library as available on
126+
# the target machine's PATH.
127+
uri: /absolute/path/to/outdir/arbitrary_filename.whatever
128+
target: linux_x64
129+
...
130+
131+
# The files used by this build.
132+
#
133+
# If any of the files in [dependencies] are modified after [timestamp], the
134+
# build will be re-run.
135+
#
136+
# Not output on dry runs.
137+
dependencies:
138+
- /absolute/path/to/my_package_with_native_assets/build.dart
139+
...
140+
141+
# The time the build this output is for started.
142+
#
143+
# Must be before any of the files in dependencies are read.
144+
timestamp: 2024-01-02 17:05:35.000
145+
146+
# Metadata usable for build.dart of packages directly depending on this package.
147+
#
148+
# Not output in dry runs.
149+
metadata:
150+
# Key value pairs.
151+
some_key: some_value
152+
153+
# Schema version of this file.
154+
version: 1.0.0
155+
```
156+
157+
### Running `build.dart`
158+
159+
The input is passed as a absolute path to a YAML file `build_config.yaml` encoding the input information as follows:
160+
161+
```console
162+
$ dart build.dart --config <build_config.yaml>
163+
```
164+
165+
The Dart and Flutter SDK invoke `build.dart` of all packages in the transitive dependencies and pass a `build_config.yaml` as the `--config` option.
166+
167+
If not in `dry_run` mode, the `build.dart` file MUST:
168+
* Read the `build_config.yaml` file,
169+
* Create assets using the configuration from `build_config.yaml`, if not already existing.
170+
* Write asset files into the directory with path `out_dir` that was provided by `build_config.yaml`.
171+
* MUST avoid file name `build_output.yaml`.
172+
* Write `build_output.yaml` into the directory at `out_dir`.
173+
* This maps the `assetId`s to assets previously written into `out_dir`.
174+
* There may be multiple assets for a given `assetId` depending on
175+
characteristics like `target`, `link_mode`, etc.
176+
* If the boolean parameter `dry_run` is set to true in the build configuration,
177+
the list of assets must be output, but the asset files must not be written.
178+
The asset file urls are expected to refer to non-existing files.
179+
180+
Notes:
181+
* The file name inside `out_dir` is irrelevant, because in Dart code the asset will only be referenced by its `assetId`.
182+
* If the boolean parameter `dry_run` is set to true in the build configuration, then the actual creation and writing of assets can be skipped, as long as the assets are still listed in the `build_output.yaml`.
183+
184+
### `.dart_tool/native_assets.yaml`
185+
186+
**This is not part of the build.dart protocol.**
187+
188+
This file is internal to the Dart SDK and Flutter SDK.
189+
It produced by `native_asset_builder` (as embedded in the SDKs).
190+
For each `target` it maps from `assetId` to a path type with an optional path.
191+
192+
These paths are used to resolve `@Native() external` functions in Dart code.
193+
194+
The path types in this file are as follows:
195+
196+
* `absolute` paths are absolute paths on the system where the Dart executable is running. This path type is used when running in JIT mode on a developers' host machine, or in an Android app where the root path is the Android bundle.
197+
* `relative` paths are relative to the kernel or aot snapshot. This path type is used for shipping native assets in a directory together with a kernelsnapshot, aotsnapshot, or standalone executable (dartaotruntime+aotsnapshot).
198+
* `system` paths are expected to resolve on the target machine PATH.
199+
* `process` "paths" have no path, symbols are resolved in the current process.
200+
* `executable` "paths" have no path, symbols are resolved in the current executable.
201+
202+
```yaml
203+
# Schema version of this file.
204+
format-version: [1, 0, 0]
205+
206+
# A mapping from target and assetId to an asset.
207+
native-assets:
208+
# A <target>.
209+
linux_x64:
210+
# An <assetId>.
211+
'package:my_package_with_native_assets/src/foo.dart':
212+
# A list of path_type and optionally a path.
213+
- absolute | relative | system | process | executable
214+
- <url> # Only provided for absolute, relative, and system path types.
215+
...
216+
```
217+
218+
This file is used by the embedded SDK to resolve `assetId`s when running in
219+
development mode or build a deployable application (or standalone executable).
220+
221+
## Wishes to improve for v2
222+
223+
* Multiple asset types. Rename `Asset` to `NativeCodeAsset` and introduce `DataAsset`s.
224+
* The path_types really only make sense for `link_mode: dynamic`.
225+
* Fix the mismatch between `target` for output but `os` and `architecture` for config.
226+
* Should the architecture field of native code assets be optional and be ommitted in dry runs?
227+
* Introduce a `link.dart` protocol with a link input and link output.

0 commit comments

Comments
 (0)