44
55import 'dart:io' ;
66
7+ import 'package:code_assets/code_assets.dart' ;
78import 'package:crypto/crypto.dart' show sha256;
8- import 'package:intl4x/src/hook_helpers/build_options.dart' ;
9- import 'package:intl4x/src/hook_helpers/hashes.dart' ;
10- import 'package:intl4x/src/hook_helpers/shared.dart'
11- show assetId, package, runProcess;
12- import 'package:intl4x/src/hook_helpers/version.dart' ;
13- import 'package:native_assets_cli/code_assets.dart' ;
14- import 'package:path/path.dart' as path;
15-
16- const crateName = 'icu_capi' ;
9+ import 'package:hooks/hooks.dart' ;
10+ import 'package:intl4x/src/hook_helpers/build_libs.g.dart' show buildLib;
11+ import 'package:intl4x/src/hook_helpers/build_options.dart'
12+ show BuildModeEnum, BuildOptions;
13+ import 'package:intl4x/src/hook_helpers/hashes.dart' show fileHashes;
14+ import 'package:intl4x/src/hook_helpers/shared.dart' show assetId, package;
15+ import 'package:intl4x/src/hook_helpers/version.dart' show version;
1716
1817void main (List <String > args) async {
1918 await build (args, (input, output) async {
20- final buildOptions = await getBuildOptions (
21- input.outputDirectory.toFilePath (),
22- );
23- if (buildOptions == null ) {
19+ BuildOptions buildOptions;
20+ try {
21+ buildOptions = BuildOptions .fromDefines (input.userDefines);
22+ print ('Got build options: ${buildOptions .toJson ()}' );
23+ } catch (e) {
2424 throw ArgumentError ('''
25+ Error: $e
26+
27+
28+ Set the build mode with either `fetch`, `local`, or `checkout` by writing into your pubspec:
2529
26- Unknown build mode for icu4x. Set the build mode with either `fetch`, `local`, or `checkout` by writing into your pubspec:
2730* fetch: Fetch the precompiled binary from a CDN.
2831```
29- ...
30- hook:
31- intl4x:
32- buildMode: fetch
33- ...
32+ hooks:
33+ user_defines:
34+ intl4x:
35+ buildMode: fetch
3436```
37+
3538* local: Use a locally existing binary at the environment variable `LOCAL_ICU4X_BINARY`.
3639```
37- ...
38- hook:
39- intl4x:
40- buildMode: local
41- localDylibPath: path/to/dylib.so
42- ...
40+ hooks:
41+ user_defines:
42+ intl4x:
43+ buildMode: local
44+ localDylibPath: path/to/dylib.so
4345```
46+
4447* checkout: Build a fresh library from a local git checkout of the icu4x repository.
4548```
46- ...
47- hook:
48- intl4x:
49- buildMode: checkout
50- checkoutPath: path/to/checkout
51- ...
49+ hooks:
50+ user_defines:
51+ intl4x:
52+ buildMode: checkout
53+ checkoutPath: path/to/checkout
5254```
5355
5456''' );
@@ -70,25 +72,21 @@ hook:
7072 };
7173
7274 final builtLibrary = await buildMode.build ();
73- // For debugging purposes
74- // ignore: deprecated_member_use
75- output.addMetadatum ('ICU4X_BUILD_MODE' , buildOptions.buildMode.name);
7675
77- final targetOS = input.config.code.targetOS;
78- final targetArchitecture = input.config.code.targetArchitecture;
7976 output.assets.code.add (
8077 CodeAsset (
8178 package: package,
8279 name: assetId,
8380 linkMode: DynamicLoadingBundled (),
84- architecture: targetArchitecture,
85- os: targetOS,
8681 file: builtLibrary,
8782 ),
88- linkInPackage: input.config.linkingEnabled ? package : null ,
83+ routing:
84+ input.config.linkingEnabled
85+ ? const ToLinkHook (package)
86+ : const ToAppBundle (),
8987 );
90-
9188 output.addDependencies (buildMode.dependencies);
89+ output.addDependency (input.packageRoot.resolve ('pubspec.yaml' ));
9290 });
9391}
9492
@@ -155,12 +153,12 @@ final class FetchMode extends BuildMode {
155153}
156154
157155final class LocalMode extends BuildMode {
158- final String ? localPath;
156+ final Uri ? localPath;
159157 LocalMode (super .input, this .localPath, super .treeshake);
160158
161159 String get _localLibraryPath {
162160 if (localPath != null ) {
163- return localPath! ;
161+ return localPath! . toFilePath (windows : Platform .isWindows) ;
164162 }
165163 throw ArgumentError (
166164 '`LOCAL_ICU4X_BINARY` is empty. '
@@ -189,7 +187,7 @@ final class LocalMode extends BuildMode {
189187}
190188
191189final class CheckoutMode extends BuildMode {
192- final String ? checkoutPath;
190+ final Uri ? checkoutPath;
193191
194192 CheckoutMode (super .input, this .checkoutPath, super .treeshake);
195193
@@ -198,140 +196,35 @@ final class CheckoutMode extends BuildMode {
198196 print ('Running in `checkout` mode' );
199197 if (checkoutPath == null ) {
200198 throw ArgumentError (
201- 'Specify the ICU4X checkout folder'
202- 'with the LOCAL_ICU4X_CHECKOUT variable ' ,
199+ 'Specify the ICU4X checkout folder with the `checkoutPath` key in your '
200+ 'pubspec build options. ' ,
203201 );
204202 }
205- return await buildLib (input, checkoutPath! , treeshake);
206- }
207-
208- @override
209- List <Uri > get dependencies => [
210- Uri .directory (checkoutPath! ).resolve ('Cargo.lock' ),
211- ];
212- }
213-
214- //TODO: Reuse code from package:icu4x as soon as it is published.
215- Future <Uri > buildLib (
216- BuildInput input,
217- String workingDirectory,
218- bool treeshake,
219- ) async {
220- final crateNameFixed = crateName.replaceAll ('-' , '_' );
221- final libFileName = input.config.filename (treeshake)(crateNameFixed);
222- final libFileUri = input.outputDirectory.resolve (libFileName);
223-
224- final code = input.config.code;
225- final targetOS = code.targetOS;
226- final targetArchitecture = code.targetArchitecture;
227- final buildStatic = input.config.buildStatic (treeshake);
228-
229- final isNoStd = _isNoStdTarget ((targetOS, targetArchitecture));
230- final target = asRustTarget (input);
231-
232- if (! isNoStd) {
233- final rustArguments = ['target' , 'add' , target];
234- await runProcess (
235- 'rustup' ,
236- rustArguments,
237- workingDirectory: workingDirectory,
203+ final builtLib = await buildLib (
204+ input.config.code.targetOS,
205+ input.config.code.targetArchitecture,
206+ input.config.buildStatic (treeshake),
207+ input.config.code.targetOS == OS .iOS &&
208+ input.config.code.iOS.targetSdk == IOSSdk .iPhoneSimulator,
209+ Directory .fromUri (checkoutPath! ),
210+ [
211+ 'icu_collator' ,
212+ 'icu_datetime' ,
213+ 'icu_list' ,
214+ 'icu_decimal' ,
215+ 'icu_plurals' ,
216+ 'experimental_components' ,
217+ 'default_components' ,
218+ 'compiled_data' ,
219+ ],
238220 );
221+ return builtLib.uri;
239222 }
240- final stdFeatures = ['logging' , 'simple_logger' ];
241- final noStdFeatures = ['libc_alloc' , 'panic_handler' ];
242- final features = {
243- 'default_components' ,
244- 'icu_collator' ,
245- 'icu_datetime' ,
246- 'icu_list' ,
247- 'icu_decimal' ,
248- 'icu_plurals' ,
249- 'compiled_data' ,
250- 'buffer_provider' ,
251- 'experimental_components' ,
252- ...(isNoStd ? noStdFeatures : stdFeatures),
253- };
254- final arguments = [
255- if (buildStatic || isNoStd) '+nightly' ,
256- 'rustc' ,
257- '--manifest-path=$workingDirectory /ffi/capi/Cargo.toml' ,
258- '--crate-type=${buildStatic ? 'staticlib' : 'cdylib' }' ,
259- '--release' ,
260- '--config=profile.release.panic="abort"' ,
261- '--config=profile.release.codegen-units=1' ,
262- '--no-default-features' ,
263- '--features=${features .join (',' )}' ,
264- if (isNoStd) '-Zbuild-std=core,alloc' ,
265- if (buildStatic || isNoStd) ...[
266- '-Zbuild-std=std,panic_abort' ,
267- '-Zbuild-std-features=panic_immediate_abort' ,
268- ],
269- '--target=$target ' ,
270- ];
271- await runProcess ('cargo' , arguments, workingDirectory: workingDirectory);
272-
273- final builtPath = path.join (
274- workingDirectory,
275- 'target' ,
276- target,
277- 'release' ,
278- libFileName,
279- );
280- final file = File (builtPath);
281- if (! (await file.exists ())) {
282- throw FileSystemException ('Building the dylib failed' , builtPath);
283- }
284- await file.copy (libFileUri.toFilePath (windows: Platform .isWindows));
285- return libFileUri;
286- }
287223
288- String asRustTarget (BuildInput input) {
289- final rustTarget = _asRustTarget (
290- input.config.code.targetOS,
291- input.config.code.targetArchitecture,
292- input.config.code.targetOS == OS .iOS &&
293- input.config.code.iOS.targetSdk == IOSSdk .iPhoneSimulator,
294- );
295- return rustTarget;
296- }
297-
298- String _asRustTarget (OS os, Architecture ? architecture, bool isSimulator) {
299- if (os == OS .iOS && architecture == Architecture .arm64 && isSimulator) {
300- return 'aarch64-apple-ios-sim' ;
301- }
302- return switch ((os, architecture)) {
303- (OS .android, Architecture .arm) => 'armv7-linux-androideabi' ,
304- (OS .android, Architecture .arm64) => 'aarch64-linux-android' ,
305- (OS .android, Architecture .ia32) => 'i686-linux-android' ,
306- (OS .android, Architecture .riscv64) => 'riscv64-linux-android' ,
307- (OS .android, Architecture .x64) => 'x86_64-linux-android' ,
308- (OS .fuchsia, Architecture .arm64) => 'aarch64-unknown-fuchsia' ,
309- (OS .fuchsia, Architecture .x64) => 'x86_64-unknown-fuchsia' ,
310- (OS .iOS, Architecture .arm64) => 'aarch64-apple-ios' ,
311- (OS .iOS, Architecture .x64) => 'x86_64-apple-ios' ,
312- (OS .linux, Architecture .arm) => 'armv7-unknown-linux-gnueabihf' ,
313- (OS .linux, Architecture .arm64) => 'aarch64-unknown-linux-gnu' ,
314- (OS .linux, Architecture .ia32) => 'i686-unknown-linux-gnu' ,
315- (OS .linux, Architecture .riscv32) => 'riscv32gc-unknown-linux-gnu' ,
316- (OS .linux, Architecture .riscv64) => 'riscv64gc-unknown-linux-gnu' ,
317- (OS .linux, Architecture .x64) => 'x86_64-unknown-linux-gnu' ,
318- (OS .macOS, Architecture .arm64) => 'aarch64-apple-darwin' ,
319- (OS .macOS, Architecture .x64) => 'x86_64-apple-darwin' ,
320- (OS .windows, Architecture .arm64) => 'aarch64-pc-windows-msvc' ,
321- (OS .windows, Architecture .ia32) => 'i686-pc-windows-msvc' ,
322- (OS .windows, Architecture .x64) => 'x86_64-pc-windows-msvc' ,
323- (_, _) =>
324- throw UnimplementedError (
325- 'Target ${(os , architecture )} not available for rust' ,
326- ),
327- };
224+ @override
225+ List <Uri > get dependencies => [checkoutPath! .resolve ('Cargo.lock' )];
328226}
329227
330- bool _isNoStdTarget ((OS os, Architecture ? architecture) arg) => [
331- (OS .android, Architecture .riscv64),
332- (OS .linux, Architecture .riscv64),
333- ].contains (arg);
334-
335228extension on BuildConfig {
336229 bool buildStatic (bool treeshake) =>
337230 code.linkModePreference == LinkModePreference .static ||
0 commit comments