Skip to content

Commit c5cb556

Browse files
Add option for native exe (#182)
Co-authored-by: Natalie Weizenbaum <[email protected]>
1 parent 154ed86 commit c5cb556

File tree

5 files changed

+97
-16
lines changed

5 files changed

+97
-16
lines changed

CHANGELOG.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1+
## 2.14.0
2+
3+
* Add a `pkg.useExe` config variable to allow users to customize exactly when
4+
single-file standalone executables are generated.
5+
16
## 2.13.0
27

38
* Generate an [AOT module] instead of a [portable module] in
4-
`pkg-standalone-dev`. Because dev artifacts are only intended to be used on
5-
the current machine, there's no need to trade speed for portability.
9+
`pkg-standalone-dev`. Because dev artifacts are only intended to be used on
10+
the current machine, there's no need to trade speed for portability.
611

712
* Add a `pkg-compile-native-dev` task to generate an AOT module with asserts
813
enabled.
914

1015
* The `pkg-compile-snapshot-dev` task is now an alias of `pkg-compile-snapshot`
11-
for backward compatibility. For portable modules asserts need be enabled at
12-
runtime with `dart --enable-asserts`.
16+
for backward compatibility. For portable modules asserts need be enabled at
17+
runtime with `dart --enable-asserts`.
1318

14-
[AOT module]: https://dart.dev/tools/dart-compile#aot-snapshot
15-
[portable module]: https://dart.dev/tools/dart-compile#kernel
19+
[AOT module]: https://dart.dev/tools/dart-compile#aot-snapshot
20+
[portable module]: https://dart.dev/tools/dart-compile#kernel
1621

1722
* Add support for new `dartvm` executable on Dart SDK >=3.10.0.
1823

doc/standalone.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,18 @@ Depends on: [`pkg-compile-snapshot`][]
3939

4040
## `pkg-compile-native`
4141

42-
Uses configuration: [`pkg.executables`][], [`pkg.version`][]
42+
Uses configuration: [`pkg.executables`][], [`pkg.version`][], [`pkg.useExe`][],
43+
44+
[`pkg.useExe`]: https://pub.dev/documentation/cli_pkg/latest/cli_pkg/useExe.html
4345

4446
Output: `build/$executable.native`
4547

4648
Compiles each executable in the package to an
47-
[AOT module (aot-snapshot)][aot-snapshot] with asserts disabled.
49+
[AOT module (aot-snapshot)][aot-snapshot] or a
50+
[self-contained executable][exe] (depending on the current platform and
51+
[`pkg.useExe`][]) with asserts disabled.
52+
53+
[exe]: https://dart.dev/tools/dart-compile#exe
4854

4955
[`String.fromEnvironment()`]: https://api.dartlang.org/stable/dart-core/String/String.fromEnvironment.html
5056

@@ -104,8 +110,9 @@ that can be used to invoke them.
104110

105111
Any OS's packages can be built regardless of the OS running the task, but if the
106112
host OS matches the target OS *and* the architecture is 64-bit, executables will
107-
be built as [AOT modules (aot-snapshot)][aot-snapshot], which are substantially
108-
faster and smaller than the kernel snapshots that are generated otherwise.
113+
be built as [AOT modules (aot-snapshot)][aot-snapshot] or ["exe"][exe], which
114+
are substantially faster and smaller than the kernel snapshots that are
115+
generated otherwise.
109116

110117
The target for the current OS and architecture is always available. However, for
111118
any OS or architecture under experimental Dart SDK support, such task is only

lib/src/standalone.dart

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ import 'utils.dart';
3333
/// This defaults to [name].
3434
final standaloneName = InternalConfigVariable.fn<String>(() => name.value);
3535

36+
/// Whether to build a native executable for the current platform instead of an
37+
/// AOT snapshot.
38+
///
39+
/// This is a function that's passed the [CliPlatform] that's being built to
40+
/// allow for different behavior on different platforms.
41+
///
42+
/// This defaults to returning [CliPlatform.useExe] unmodified.
43+
final useExe = InternalConfigVariable.value<bool Function(CliPlatform)>(
44+
(CliPlatform platform) => platform.useExe,
45+
);
46+
3647
/// For each executable entrypoint in [executables], builds a portable module
3748
/// (kernel) to `build/${executable}.snapshot`.
3849
void _compileSnapshot() {
@@ -66,7 +77,8 @@ void _compileSnapshot() {
6677
}
6778

6879
/// For each executable entrypoint in [executables], builds an AOT module
69-
/// (aot-snapshot) to `build/${executable}.native`.
80+
/// (aot-snapshot) or standalone executable (exe) to
81+
/// `build/${executable}.native`.
7082
///
7183
/// If [enableAsserts] is `true`, this compiles with `--enable-asserts`.
7284
void _compileNative({bool enableAsserts = false}) {
@@ -85,7 +97,7 @@ void _compileNative({bool enableAsserts = false}) {
8597
'dart',
8698
arguments: [
8799
'compile',
88-
CliPlatform.current.useExe ? 'exe' : 'aot-snapshot',
100+
useExe.value(CliPlatform.current) ? 'exe' : 'aot-snapshot',
89101
if (enableAsserts) '--enable-asserts',
90102
for (var entry in environmentConstants.value.entries)
91103
'-D${entry.key}=${entry.value}',
@@ -109,6 +121,7 @@ void addStandaloneTasks() {
109121

110122
freezeSharedVariables();
111123
standaloneName.freeze();
124+
useExe.freeze();
112125

113126
addTask(
114127
GrinderTask(
@@ -211,7 +224,9 @@ Future<void> _buildPackage(CliPlatform platform) async {
211224
var archive = Archive()
212225
..addFile(fileFromString("$standaloneName/src/LICENSE", await license));
213226

214-
if (!platform.useExe) {
227+
var nativeExe = useExe.value(platform);
228+
229+
if (!(platform.useNative && nativeExe)) {
215230
archive.addFile(
216231
fileFromBytes(
217232
"$standaloneName/src/dart${platform.binaryExtension}",
@@ -222,7 +237,7 @@ Future<void> _buildPackage(CliPlatform platform) async {
222237
}
223238

224239
for (var name in executables.value.keys) {
225-
if (platform.useExe) {
240+
if (platform.useNative && nativeExe) {
226241
archive.addFile(
227242
file(
228243
"$standaloneName/$name${platform.binaryExtension}",
@@ -240,7 +255,7 @@ Future<void> _buildPackage(CliPlatform platform) async {
240255
}
241256
}
242257

243-
if (!platform.useExe) {
258+
if (!(platform.useNative && nativeExe)) {
244259
// Do this separately from adding entrypoints because multiple executables
245260
// may have the same entrypoint.
246261
for (var name in executables.value.keys) {

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: cli_pkg
2-
version: 2.13.0
2+
version: 2.14.0
33
description: Grinder tasks for releasing Dart CLI packages.
44
homepage: https://github.com/google/dart_cli_pkg
55

test/standalone_test.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,60 @@ void main() {
124124
]).validate();
125125
});
126126

127+
test("can be standalone executables on current platform", () async {
128+
await d.package(pubspec, """
129+
void main(List<String> args) {
130+
pkg.useExe.value = (_) => true;
131+
pkg.addStandaloneTasks();
132+
grind(args);
133+
}
134+
""").create();
135+
136+
await (await grind([
137+
"pkg-standalone-${CliPlatform.current}",
138+
])).shouldExit(0);
139+
140+
await d.archive("my_app/build/my_app-1.2.3-$_archiveSuffix", [
141+
d.dir("my_app", [
142+
d.file("foo$dotExe", anything),
143+
d.file("bar$dotExe", anything),
144+
d.file("qux$dotExe", anything),
145+
d.dir("src", [
146+
d.nothing("foo.snapshot"),
147+
d.nothing("bar.snapshot"),
148+
d.nothing("qux.snapshot"),
149+
]),
150+
]),
151+
]).validate();
152+
});
153+
154+
test("can be aot snapshots on current platform", () async {
155+
await d.package(pubspec, """
156+
void main(List<String> args) {
157+
pkg.useExe.value = (_) => false;
158+
pkg.addStandaloneTasks();
159+
grind(args);
160+
}
161+
""").create();
162+
163+
await (await grind([
164+
"pkg-standalone-${CliPlatform.current}",
165+
])).shouldExit(0);
166+
167+
await d.archive("my_app/build/my_app-1.2.3-$_archiveSuffix", [
168+
d.dir("my_app", [
169+
d.file("foo$dotBat", anything),
170+
d.file("bar$dotBat", anything),
171+
d.file("qux$dotBat", anything),
172+
d.dir("src", [
173+
d.file("foo.snapshot", anything),
174+
d.file("bar.snapshot", anything),
175+
d.file("qux.snapshot", anything),
176+
]),
177+
]),
178+
]).validate();
179+
});
180+
127181
test("can be removed by the user", () async {
128182
await d.package(pubspec, """
129183
void main(List<String> args) {

0 commit comments

Comments
 (0)