Skip to content

Commit

Permalink
[native_assets_builder] Separate KernelAssets from Assets (#964)
Browse files Browse the repository at this point in the history
There are multiple differences between the `native_assets.yaml` that is embedded in the kernel file and the `build_output.yaml -> assets`. 

* Based on the discussions on #955 and #946, it is clear that the `path` for assets should be in `Asset`, not in `AssetPath` for the file-path the asset has after the `build.dart` run. When the embedders (Flutter/Dart) embed the native assets mapping then the `path`s start representing the path on the system where the Dart/Flutter app is running. This should be embedded in the path-type there.
* The kernel info does not contain link mode (currently), as static linking is not supported. It's not clear that if we support static linking whether any information should be embedded in the kernel info at all.
* The native_assets.yaml for the kernel file is laid out for easy lookup at runtime (keyed on Target).
* We want to change the `Asset`s to output OS and Architecture instead of Target.

Therefore we should not share the data structure between `Asset`s and `KernelAsset`s (new name for the entries that are embedded via native_assets.yaml in a kernel file.)

This means that `dartdev` and `flutter_tools` will have to start converting `Asset`s to `KernelAsset`s when making the `native_assets.yaml` file. Therefore this is a breaking change and will have to be rolled into Dart and flutter/flutter manually.
  • Loading branch information
dcharkes authored Feb 14, 2024
1 parent b1a0c2a commit 0901a33
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 111 deletions.
3 changes: 2 additions & 1 deletion pkgs/native_assets_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 0.3.3-wip
## 0.4.0-wip

- **Breaking change**: Split out the `KernelAsset`s from normal `Asset`s.
- Bump `package:native_assets_cli` to path dependency.

## 0.3.2
Expand Down
2 changes: 1 addition & 1 deletion pkgs/native_assets_builder/lib/native_assets_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
// BSD-style license that can be found in the LICENSE file.

export 'package:native_assets_builder/src/build_runner/build_runner.dart';
export 'package:native_assets_builder/src/model/asset.dart';
export 'package:native_assets_builder/src/model/kernel_assets.dart';
export 'package:native_assets_builder/src/package_layout/package_layout.dart';
73 changes: 0 additions & 73 deletions pkgs/native_assets_builder/lib/src/model/asset.dart

This file was deleted.

143 changes: 143 additions & 0 deletions pkgs/native_assets_builder/lib/src/model/kernel_assets.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/// Library defining the `native_assets.yaml` format for embedding in a Dart
/// kernel file.
///
/// The `native_assets.yaml` embedded in a kernel file has a different format
/// from the assets passed in the `build_output.yaml` from individual native
/// assets builds. This library defines the format of the former so that it
/// can be reused in `package:dartdev` and `package:flutter_tools`.
///
/// The format should be consistent with `pkg/vm/lib/native_assets/` in the
/// Dart SDK.
library kernel_native_assets;

import 'package:native_assets_cli/native_assets_cli_internal.dart';

import '../utils/yaml.dart';

class KernelAssets {
final List<KernelAsset> assets;

KernelAssets(this.assets);

String toNativeAssetsFile() {
final assetsPerTarget = <Target, List<KernelAsset>>{};
for (final asset in assets) {
final assets = assetsPerTarget[asset.target] ?? [];
assets.add(asset);
assetsPerTarget[asset.target] = assets;
}

final yamlContents = {
'format-version': [1, 0, 0],
'native-assets': {
for (final entry in assetsPerTarget.entries)
entry.key.toString(): {
for (final e in entry.value) e.id: e.path.toYaml(),
}
},
};

return yamlEncode(yamlContents);
}
}

class KernelAsset {
final String id;
final Target target;
final KernelAssetPath path;

KernelAsset({
required this.id,
required this.target,
required this.path,
});
}

abstract class KernelAssetPath {
List<String> toYaml();
}

/// Asset at absolute path [uri] on the target device where Dart is run.
class KernelAssetAbsolutePath implements KernelAssetPath {
final Uri uri;

KernelAssetAbsolutePath(this.uri);

static const _pathTypeValue = 'absolute';

@override
List<String> toYaml() => [_pathTypeValue, uri.toFilePath()];
}

/// Asset at relative path [uri], relative to the 'dart file' executed.
///
/// The 'dart file' executed can be one of the following:
///
/// 1. The `.dart` file when executing `dart path/to/script.dart`.
/// 2. The `.kernel` file when executing from a kernel file.
/// 3. The `.aotsnapshot` file when executing from an AOT snapshot with the Dart
/// AOT runtime.
/// 4. The executable when executing a Dart app compiled with `dart compile exe`
/// to a single file.
///
/// Note when writing your own embedder, make sure the `Dart_CreateIsolateGroup`
/// or similar calls set up the `script_uri` parameter correctly to ensure
/// relative path resolution works.
class KernelAssetRelativePath implements KernelAssetPath {
final Uri uri;

KernelAssetRelativePath(this.uri);

static const _pathTypeValue = 'relative';

@override
List<String> toYaml() => [_pathTypeValue, uri.toFilePath()];
}

/// Asset is avaliable on the system `PATH`.
///
/// [uri] only contains a file name.
class KernelAssetSystemPath implements KernelAssetPath {
final Uri uri;

KernelAssetSystemPath(this.uri);

static const _pathTypeValue = 'system';

@override
List<String> toYaml() => [_pathTypeValue, uri.toFilePath()];
}

/// Asset is loaded in the process and symbols are available through
/// `DynamicLibrary.process()`.
class KernelAssetInProcess implements KernelAssetPath {
KernelAssetInProcess._();

static final KernelAssetInProcess _singleton = KernelAssetInProcess._();

factory KernelAssetInProcess() => _singleton;

static const _pathTypeValue = 'process';

@override
List<String> toYaml() => [_pathTypeValue];
}

/// Asset is embedded in executable and symbols are available through
/// `DynamicLibrary.executable()`.
class KernelAssetInExecutable implements KernelAssetPath {
KernelAssetInExecutable._();

static final KernelAssetInExecutable _singleton = KernelAssetInExecutable._();

factory KernelAssetInExecutable() => _singleton;

static const _pathTypeValue = 'executable';

@override
List<String> toYaml() => [_pathTypeValue];
}
2 changes: 1 addition & 1 deletion pkgs/native_assets_builder/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: native_assets_builder
description: >-
This package is the backend that invokes top-level `build.dart` scripts.
version: 0.3.3-wip
version: 0.4.0-wip
repository: https://github.com/dart-lang/native/tree/main/pkgs/native_assets_builder

environment:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

// ignore_for_file: undefined_hidden_name

import 'package:native_assets_builder/src/model/asset.dart';
import 'package:native_assets_cli/native_assets_cli_internal.dart'
hide AssetIterable, AssetRelativePath;
import 'package:native_assets_builder/src/model/kernel_assets.dart';
import 'package:native_assets_cli/native_assets_cli_internal.dart';
import 'package:test/test.dart';

void main() {
Expand All @@ -15,50 +14,43 @@ void main() {
final foo3Uri = Uri(path: 'libfoo3.so');
final barUri = Uri(path: 'path/to/libbar.a');
final blaUri = Uri(path: 'path/with spaces/bla.dll');
final assets = [
Asset(
final assets = KernelAssets([
KernelAsset(
id: 'foo',
path: AssetAbsolutePath(fooUri),
path: KernelAssetAbsolutePath(fooUri),
target: Target.androidX64,
linkMode: LinkMode.dynamic,
),
Asset(
KernelAsset(
id: 'foo2',
path: AssetRelativePath(foo2Uri),
path: KernelAssetRelativePath(foo2Uri),
target: Target.androidX64,
linkMode: LinkMode.dynamic,
),
Asset(
KernelAsset(
id: 'foo3',
path: AssetSystemPath(foo3Uri),
path: KernelAssetSystemPath(foo3Uri),
target: Target.androidX64,
linkMode: LinkMode.dynamic,
),
Asset(
KernelAsset(
id: 'foo4',
path: AssetInExecutable(),
path: KernelAssetInExecutable(),
target: Target.androidX64,
linkMode: LinkMode.dynamic,
),
Asset(
KernelAsset(
id: 'foo5',
path: AssetInProcess(),
path: KernelAssetInProcess(),
target: Target.androidX64,
linkMode: LinkMode.dynamic,
),
Asset(
KernelAsset(
id: 'bar',
path: AssetAbsolutePath(barUri),
path: KernelAssetAbsolutePath(barUri),
target: Target.linuxArm64,
linkMode: LinkMode.static,
),
Asset(
KernelAsset(
id: 'bla',
path: AssetAbsolutePath(blaUri),
path: KernelAssetAbsolutePath(blaUri),
target: Target.windowsX64,
linkMode: LinkMode.dynamic,
),
];
]);

final assetsDartEncoding = '''format-version:
- 1
Expand Down Expand Up @@ -92,13 +84,4 @@ native-assets:
final fileContents = assets.toNativeAssetsFile();
expect(fileContents, assetsDartEncoding);
});

test('List<Asset> whereLinkMode', () async {
final assets2 = assets.whereLinkMode(LinkMode.dynamic);
expect(assets2.length, 6);
});

test('satisfy coverage', () async {
expect(() => assets[1].toYaml(), throwsUnimplementedError);
});
}

0 comments on commit 0901a33

Please sign in to comment.