Skip to content

Commit

Permalink
[native_assets_builder] Only build native assets for dependencies of …
Browse files Browse the repository at this point in the history
…requested package
  • Loading branch information
dcharkes committed Nov 27, 2023
1 parent 0051e78 commit 2156f9a
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 8 deletions.
5 changes: 5 additions & 0 deletions pkgs/native_assets_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.3.1-wip

- Add support for `runPackageName` to avoid native assets for packages that
the root package depends on but the package being run doesn't.

## 0.3.0

- Bump `package:native_assets_cli` to 0.3.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,15 @@ class NativeAssetsBuildPlanner {
);
}

(List<Package> packages, bool success) plan() {
(List<Package> packages, bool success) plan({
String? runPackageName,
}) {
final PackageGraph packageGraph;
if (runPackageName != null) {
packageGraph = this.packageGraph.subGraph(runPackageName);
} else {
packageGraph = this.packageGraph;
}
final packageMap = {
for (final package in packagesWithNativeAssets) package.name: package
};
Expand Down Expand Up @@ -105,4 +113,19 @@ class PackageGraph {

List<List<String>> computeStrongComponents() =>
graphs.stronglyConnectedComponents(vertices, neighborsOf);

PackageGraph subGraph(String rootPackageName) {
final subgraphVertices = [
...graphs.transitiveClosure(vertices, neighborsOf)[rootPackageName]!,
rootPackageName,
];
return PackageGraph({
for (final vertex in map.keys)
if (subgraphVertices.contains(vertex))
vertex: [
for (final neighbor in map[vertex]!)
if (subgraphVertices.contains(neighbor)) neighbor,
]
});
}
}
20 changes: 14 additions & 6 deletions pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class NativeAssetsBuildRunner {
/// This method is invoked by launchers such as dartdev (for `dart run`) and
/// flutter_tools (for `flutter run` and `flutter build`).
///
/// Completes the future with an error if the build fails.
/// If provided, only native assets of all transitive dependencies of
/// [runPackageName] are built.
Future<BuildResult> build({
required LinkModePreference linkModePreference,
required Target target,
Expand All @@ -44,13 +45,14 @@ class NativeAssetsBuildRunner {
int? targetAndroidNdkApi,
required bool includeParentEnvironment,
PackageLayout? packageLayout,
String? runPackageName,
}) async {
packageLayout ??= await PackageLayout.fromRootPackageRoot(workingDirectory);
final packagesWithNativeAssets =
await packageLayout.packagesWithNativeAssets;
final List<Package> buildPlan;
final PackageGraph packageGraph;
if (packagesWithNativeAssets.length <= 1) {
if (packagesWithNativeAssets.length <= 1 && runPackageName == null) {
buildPlan = packagesWithNativeAssets;
packageGraph = PackageGraph({
for (final p in packagesWithNativeAssets) p.name: [],
Expand All @@ -62,7 +64,9 @@ class NativeAssetsBuildRunner {
dartExecutable: Uri.file(Platform.resolvedExecutable),
logger: logger,
);
final (plan, planSuccess) = planner.plan();
final (plan, planSuccess) = planner.plan(
runPackageName: runPackageName,
);
if (!planSuccess) {
return _BuildResultImpl(
assets: [],
Expand Down Expand Up @@ -125,19 +129,21 @@ class NativeAssetsBuildRunner {
/// This method is invoked by launchers such as dartdev (for `dart run`) and
/// flutter_tools (for `flutter run` and `flutter build`).
///
/// Completes the future with an error if the build fails.
/// If provided, only native assets of all transitive dependencies of
/// [runPackageName] are built.
Future<DryRunResult> dryRun({
required LinkModePreference linkModePreference,
required OS targetOs,
required Uri workingDirectory,
required bool includeParentEnvironment,
PackageLayout? packageLayout,
String? runPackageName,
}) async {
packageLayout ??= await PackageLayout.fromRootPackageRoot(workingDirectory);
final packagesWithNativeAssets =
await packageLayout.packagesWithNativeAssets;
final List<Package> buildPlan;
if (packagesWithNativeAssets.length <= 1) {
if (packagesWithNativeAssets.length <= 1 && runPackageName == null) {
buildPlan = packagesWithNativeAssets;
} else {
final planner = await NativeAssetsBuildPlanner.fromRootPackageRoot(
Expand All @@ -146,7 +152,9 @@ class NativeAssetsBuildRunner {
dartExecutable: Uri.file(Platform.resolvedExecutable),
logger: logger,
);
final (plan, planSuccess) = planner.plan();
final (plan, planSuccess) = planner.plan(
runPackageName: runPackageName,
);
if (!planSuccess) {
return _DryRunResultImpl(
assets: [],
Expand Down
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.0
version: 0.3.1-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 @@ -50,6 +50,7 @@ void main() async {
expect(buildPlan.single.name, 'native_add');
});
});

test('build dependency graph fromPackageRoot', () async {
await inTempDir((tempUri) async {
await copyTestProjects(targetUri: tempUri);
Expand All @@ -74,4 +75,30 @@ void main() async {
expect(buildPlan.single.name, 'native_add');
});
});

test('runPackageName', () async {
await inTempDir((tempUri) async {
await copyTestProjects(targetUri: tempUri);
final nativeAddUri = tempUri.resolve('native_add/');

// First, run `pub get`, we need pub to resolve our dependencies.
await runPubGet(workingDirectory: nativeAddUri, logger: logger);

final packageLayout =
await PackageLayout.fromRootPackageRoot(nativeAddUri);
final packagesWithNativeAssets =
await packageLayout.packagesWithNativeAssets;
final nativeAssetsBuildPlanner =
await NativeAssetsBuildPlanner.fromRootPackageRoot(
rootPackageRoot: nativeAddUri,
packagesWithNativeAssets: packagesWithNativeAssets,
dartExecutable: Uri.file(Platform.resolvedExecutable),
logger: logger,
);
final (buildPlan, _) = nativeAssetsBuildPlanner.plan(
runPackageName: 'ffigen',
);
expect(buildPlan.length, 0);
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2023, 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.

import 'dart:io';

import 'package:test/test.dart';

import '../helpers.dart';
import 'helpers.dart';

const Timeout longTimeout = Timeout(Duration(minutes: 5));

void main() async {
test('run ffigen first', timeout: longTimeout, () async {
await inTempDir((tempUri) async {
await copyTestProjects(targetUri: tempUri);
final packageUri = tempUri.resolve('native_add/');

await runPubGet(
workingDirectory: packageUri,
logger: logger,
);

{
final logMessages = <String>[];
final result = await build(
packageUri,
logger,
dartExecutable,
capturedLogs: logMessages,
runPackageName: 'ffigen',
);
expect(result.assets, isEmpty);
expect(result.dependencies, isEmpty);
}

{
final logMessages = <String>[];
final result = await build(
packageUri,
logger,
dartExecutable,
capturedLogs: logMessages,
runPackageName: 'native_add',
);
expect(result.assets, isNotEmpty);
expect(
result.dependencies,
[
packageUri.resolve('build.dart'),
packageUri.resolve('src/native_add.c'),
],
);
expect(
logMessages.join('\n'),
contains('native_add${Platform.pathSeparator}build.dart'),
);
}
});
});
}
2 changes: 2 additions & 0 deletions pkgs/native_assets_builder/test/build_runner/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Future<BuildResult> build(
bool includeParentEnvironment = true,
List<String>? capturedLogs,
PackageLayout? packageLayout,
String? runPackageName,
}) async {
StreamSubscription<LogRecord>? subscription;
if (capturedLogs != null) {
Expand All @@ -57,6 +58,7 @@ Future<BuildResult> build(
cCompilerConfig: cCompilerConfig,
includeParentEnvironment: includeParentEnvironment,
packageLayout: packageLayout,
runPackageName: runPackageName,
);
if (result.success) {
await expectAssetsExist(result.assets);
Expand Down

0 comments on commit 2156f9a

Please sign in to comment.