diff --git a/CHANGELOG.md b/CHANGELOG.md index de2f09f..af368c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,23 @@ +## 2.14.0 + +* Add a `pkg.useExe` config variable to allow users to customize exactly when + single-file standalone executables are generated. + ## 2.13.0 * Generate an [AOT module] instead of a [portable module] in - `pkg-standalone-dev`. Because dev artifacts are only intended to be used on - the current machine, there's no need to trade speed for portability. + `pkg-standalone-dev`. Because dev artifacts are only intended to be used on + the current machine, there's no need to trade speed for portability. * Add a `pkg-compile-native-dev` task to generate an AOT module with asserts enabled. * The `pkg-compile-snapshot-dev` task is now an alias of `pkg-compile-snapshot` - for backward compatibility. For portable modules asserts need be enabled at - runtime with `dart --enable-asserts`. + for backward compatibility. For portable modules asserts need be enabled at + runtime with `dart --enable-asserts`. -[AOT module]: https://dart.dev/tools/dart-compile#aot-snapshot -[portable module]: https://dart.dev/tools/dart-compile#kernel + [AOT module]: https://dart.dev/tools/dart-compile#aot-snapshot + [portable module]: https://dart.dev/tools/dart-compile#kernel * Add support for new `dartvm` executable on Dart SDK >=3.10.0. diff --git a/doc/standalone.md b/doc/standalone.md index 63f423b..1237f37 100644 --- a/doc/standalone.md +++ b/doc/standalone.md @@ -39,12 +39,18 @@ Depends on: [`pkg-compile-snapshot`][] ## `pkg-compile-native` -Uses configuration: [`pkg.executables`][], [`pkg.version`][] +Uses configuration: [`pkg.executables`][], [`pkg.version`][], [`pkg.useExe`][], + +[`pkg.useExe`]: https://pub.dev/documentation/cli_pkg/latest/cli_pkg/useExe.html Output: `build/$executable.native` Compiles each executable in the package to an -[AOT module (aot-snapshot)][aot-snapshot] with asserts disabled. +[AOT module (aot-snapshot)][aot-snapshot] or a +[self-contained executable][exe] (depending on the current platform and +[`pkg.useExe`][]) with asserts disabled. + +[exe]: https://dart.dev/tools/dart-compile#exe [`String.fromEnvironment()`]: https://api.dartlang.org/stable/dart-core/String/String.fromEnvironment.html @@ -104,8 +110,9 @@ that can be used to invoke them. Any OS's packages can be built regardless of the OS running the task, but if the host OS matches the target OS *and* the architecture is 64-bit, executables will -be built as [AOT modules (aot-snapshot)][aot-snapshot], which are substantially -faster and smaller than the kernel snapshots that are generated otherwise. +be built as [AOT modules (aot-snapshot)][aot-snapshot] or ["exe"][exe], which +are substantially faster and smaller than the kernel snapshots that are +generated otherwise. The target for the current OS and architecture is always available. However, for any OS or architecture under experimental Dart SDK support, such task is only diff --git a/lib/src/standalone.dart b/lib/src/standalone.dart index 343564a..d28ce95 100644 --- a/lib/src/standalone.dart +++ b/lib/src/standalone.dart @@ -33,6 +33,17 @@ import 'utils.dart'; /// This defaults to [name]. final standaloneName = InternalConfigVariable.fn(() => name.value); +/// Whether to build a native executable for the current platform instead of an +/// AOT snapshot. +/// +/// This is a function that's passed the [CliPlatform] that's being built to +/// allow for different behavior on different platforms. +/// +/// This defaults to returning [CliPlatform.useExe] unmodified. +final useExe = InternalConfigVariable.value( + (CliPlatform platform) => platform.useExe, +); + /// For each executable entrypoint in [executables], builds a portable module /// (kernel) to `build/${executable}.snapshot`. void _compileSnapshot() { @@ -66,7 +77,8 @@ void _compileSnapshot() { } /// For each executable entrypoint in [executables], builds an AOT module -/// (aot-snapshot) to `build/${executable}.native`. +/// (aot-snapshot) or standalone executable (exe) to +/// `build/${executable}.native`. /// /// If [enableAsserts] is `true`, this compiles with `--enable-asserts`. void _compileNative({bool enableAsserts = false}) { @@ -85,7 +97,7 @@ void _compileNative({bool enableAsserts = false}) { 'dart', arguments: [ 'compile', - CliPlatform.current.useExe ? 'exe' : 'aot-snapshot', + useExe.value(CliPlatform.current) ? 'exe' : 'aot-snapshot', if (enableAsserts) '--enable-asserts', for (var entry in environmentConstants.value.entries) '-D${entry.key}=${entry.value}', @@ -109,6 +121,7 @@ void addStandaloneTasks() { freezeSharedVariables(); standaloneName.freeze(); + useExe.freeze(); addTask( GrinderTask( @@ -211,7 +224,9 @@ Future _buildPackage(CliPlatform platform) async { var archive = Archive() ..addFile(fileFromString("$standaloneName/src/LICENSE", await license)); - if (!platform.useExe) { + var nativeExe = useExe.value(platform); + + if (!(platform.useNative && nativeExe)) { archive.addFile( fileFromBytes( "$standaloneName/src/dart${platform.binaryExtension}", @@ -222,7 +237,7 @@ Future _buildPackage(CliPlatform platform) async { } for (var name in executables.value.keys) { - if (platform.useExe) { + if (platform.useNative && nativeExe) { archive.addFile( file( "$standaloneName/$name${platform.binaryExtension}", @@ -240,7 +255,7 @@ Future _buildPackage(CliPlatform platform) async { } } - if (!platform.useExe) { + if (!(platform.useNative && nativeExe)) { // Do this separately from adding entrypoints because multiple executables // may have the same entrypoint. for (var name in executables.value.keys) { diff --git a/pubspec.yaml b/pubspec.yaml index d16c9cb..60a0b4f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: cli_pkg -version: 2.13.0 +version: 2.14.0 description: Grinder tasks for releasing Dart CLI packages. homepage: https://github.com/google/dart_cli_pkg diff --git a/test/standalone_test.dart b/test/standalone_test.dart index aaea621..c050b36 100644 --- a/test/standalone_test.dart +++ b/test/standalone_test.dart @@ -124,6 +124,60 @@ void main() { ]).validate(); }); + test("can be standalone executables on current platform", () async { + await d.package(pubspec, """ + void main(List args) { + pkg.useExe.value = (_) => true; + pkg.addStandaloneTasks(); + grind(args); + } + """).create(); + + await (await grind([ + "pkg-standalone-${CliPlatform.current}", + ])).shouldExit(0); + + await d.archive("my_app/build/my_app-1.2.3-$_archiveSuffix", [ + d.dir("my_app", [ + d.file("foo$dotExe", anything), + d.file("bar$dotExe", anything), + d.file("qux$dotExe", anything), + d.dir("src", [ + d.nothing("foo.snapshot"), + d.nothing("bar.snapshot"), + d.nothing("qux.snapshot"), + ]), + ]), + ]).validate(); + }); + + test("can be aot snapshots on current platform", () async { + await d.package(pubspec, """ + void main(List args) { + pkg.useExe.value = (_) => false; + pkg.addStandaloneTasks(); + grind(args); + } + """).create(); + + await (await grind([ + "pkg-standalone-${CliPlatform.current}", + ])).shouldExit(0); + + await d.archive("my_app/build/my_app-1.2.3-$_archiveSuffix", [ + d.dir("my_app", [ + d.file("foo$dotBat", anything), + d.file("bar$dotBat", anything), + d.file("qux$dotBat", anything), + d.dir("src", [ + d.file("foo.snapshot", anything), + d.file("bar.snapshot", anything), + d.file("qux.snapshot", anything), + ]), + ]), + ]).validate(); + }); + test("can be removed by the user", () async { await d.package(pubspec, """ void main(List args) {