diff --git a/pkgs/intl4x/CHANGELOG.md b/pkgs/intl4x/CHANGELOG.md index c64d5b08..b012786d 100644 --- a/pkgs/intl4x/CHANGELOG.md +++ b/pkgs/intl4x/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.11.4 + +- Remove `native_assets_*` dependencies for `hooks` and `code_assets`. + ## 0.11.3 - Use new artifacts from `intl4x-icu-v.0.11.2-artifacts` release. diff --git a/pkgs/intl4x/analysis_options.yaml b/pkgs/intl4x/analysis_options.yaml index f0ad1ab9..7eba2d71 100644 --- a/pkgs/intl4x/analysis_options.yaml +++ b/pkgs/intl4x/analysis_options.yaml @@ -12,6 +12,8 @@ analyzer: exclude: - "submodules/*" - "lib/src/bindings/*" + - lib/src/hook_helpers/build_libs.g.dart + - tool/build_libs.g.dart enable-experiment: - native-assets diff --git a/pkgs/intl4x/example_native/pubspec.yaml b/pkgs/intl4x/example_native/pubspec.yaml index 25605cc5..9f78c365 100644 --- a/pkgs/intl4x/example_native/pubspec.yaml +++ b/pkgs/intl4x/example_native/pubspec.yaml @@ -11,9 +11,10 @@ dependencies: path: ../ dev_dependencies: - lints: ^5.0.0 + lints: ^6.0.0 -hook: - intl4x: - buildMode: fetch - treeshake: true +hooks: + user_defines: + intl4x: + buildMode: checkout + checkoutPath: ../../../submodules/icu4x/ diff --git a/pkgs/intl4x/hook/build.dart b/pkgs/intl4x/hook/build.dart index 03d823a0..a925b6a3 100644 --- a/pkgs/intl4x/hook/build.dart +++ b/pkgs/intl4x/hook/build.dart @@ -4,51 +4,53 @@ import 'dart:io'; +import 'package:code_assets/code_assets.dart'; import 'package:crypto/crypto.dart' show sha256; -import 'package:intl4x/src/hook_helpers/build_options.dart'; -import 'package:intl4x/src/hook_helpers/hashes.dart'; -import 'package:intl4x/src/hook_helpers/shared.dart' - show assetId, package, runProcess; -import 'package:intl4x/src/hook_helpers/version.dart'; -import 'package:native_assets_cli/code_assets.dart'; -import 'package:path/path.dart' as path; - -const crateName = 'icu_capi'; +import 'package:hooks/hooks.dart'; +import 'package:intl4x/src/hook_helpers/build_libs.g.dart' show buildLib; +import 'package:intl4x/src/hook_helpers/build_options.dart' + show BuildModeEnum, BuildOptions; +import 'package:intl4x/src/hook_helpers/hashes.dart' show fileHashes; +import 'package:intl4x/src/hook_helpers/shared.dart' show assetId, package; +import 'package:intl4x/src/hook_helpers/version.dart' show version; void main(List args) async { await build(args, (input, output) async { - final buildOptions = await getBuildOptions( - input.outputDirectory.toFilePath(), - ); - if (buildOptions == null) { + BuildOptions buildOptions; + try { + buildOptions = BuildOptions.fromDefines(input.userDefines); + print('Got build options: ${buildOptions.toJson()}'); + } catch (e) { throw ArgumentError(''' +Error: $e + + +Set the build mode with either `fetch`, `local`, or `checkout` by writing into your pubspec: -Unknown build mode for icu4x. Set the build mode with either `fetch`, `local`, or `checkout` by writing into your pubspec: * fetch: Fetch the precompiled binary from a CDN. ``` -... -hook: - intl4x: - buildMode: fetch -... +hooks: + user_defines: + intl4x: + buildMode: fetch ``` + * local: Use a locally existing binary at the environment variable `LOCAL_ICU4X_BINARY`. ``` -... -hook: - intl4x: - buildMode: local - localDylibPath: path/to/dylib.so -... +hooks: + user_defines: + intl4x: + buildMode: local + localDylibPath: path/to/dylib.so ``` + * checkout: Build a fresh library from a local git checkout of the icu4x repository. ``` -... -hook: - intl4x: - buildMode: checkout - checkoutPath: path/to/checkout -... +hooks: + user_defines: + intl4x: + buildMode: checkout + checkoutPath: path/to/checkout ``` '''); @@ -70,25 +72,21 @@ hook: }; final builtLibrary = await buildMode.build(); - // For debugging purposes - // ignore: deprecated_member_use - output.addMetadatum('ICU4X_BUILD_MODE', buildOptions.buildMode.name); - final targetOS = input.config.code.targetOS; - final targetArchitecture = input.config.code.targetArchitecture; output.assets.code.add( CodeAsset( package: package, name: assetId, linkMode: DynamicLoadingBundled(), - architecture: targetArchitecture, - os: targetOS, file: builtLibrary, ), - linkInPackage: input.config.linkingEnabled ? package : null, + routing: + input.config.linkingEnabled + ? const ToLinkHook(package) + : const ToAppBundle(), ); - output.addDependencies(buildMode.dependencies); + output.addDependency(input.packageRoot.resolve('pubspec.yaml')); }); } @@ -155,12 +153,12 @@ final class FetchMode extends BuildMode { } final class LocalMode extends BuildMode { - final String? localPath; + final Uri? localPath; LocalMode(super.input, this.localPath, super.treeshake); String get _localLibraryPath { if (localPath != null) { - return localPath!; + return localPath!.toFilePath(windows: Platform.isWindows); } throw ArgumentError( '`LOCAL_ICU4X_BINARY` is empty. ' @@ -189,7 +187,7 @@ final class LocalMode extends BuildMode { } final class CheckoutMode extends BuildMode { - final String? checkoutPath; + final Uri? checkoutPath; CheckoutMode(super.input, this.checkoutPath, super.treeshake); @@ -198,140 +196,35 @@ final class CheckoutMode extends BuildMode { print('Running in `checkout` mode'); if (checkoutPath == null) { throw ArgumentError( - 'Specify the ICU4X checkout folder' - 'with the LOCAL_ICU4X_CHECKOUT variable', + 'Specify the ICU4X checkout folder with the `checkoutPath` key in your ' + 'pubspec build options.', ); } - return await buildLib(input, checkoutPath!, treeshake); - } - - @override - List get dependencies => [ - Uri.directory(checkoutPath!).resolve('Cargo.lock'), - ]; -} - -//TODO: Reuse code from package:icu4x as soon as it is published. -Future buildLib( - BuildInput input, - String workingDirectory, - bool treeshake, -) async { - final crateNameFixed = crateName.replaceAll('-', '_'); - final libFileName = input.config.filename(treeshake)(crateNameFixed); - final libFileUri = input.outputDirectory.resolve(libFileName); - - final code = input.config.code; - final targetOS = code.targetOS; - final targetArchitecture = code.targetArchitecture; - final buildStatic = input.config.buildStatic(treeshake); - - final isNoStd = _isNoStdTarget((targetOS, targetArchitecture)); - final target = asRustTarget(input); - - if (!isNoStd) { - final rustArguments = ['target', 'add', target]; - await runProcess( - 'rustup', - rustArguments, - workingDirectory: workingDirectory, + final builtLib = await buildLib( + input.config.code.targetOS, + input.config.code.targetArchitecture, + input.config.buildStatic(treeshake), + input.config.code.targetOS == OS.iOS && + input.config.code.iOS.targetSdk == IOSSdk.iPhoneSimulator, + Directory.fromUri(checkoutPath!), + [ + 'icu_collator', + 'icu_datetime', + 'icu_list', + 'icu_decimal', + 'icu_plurals', + 'experimental_components', + 'default_components', + 'compiled_data', + ], ); + return builtLib.uri; } - final stdFeatures = ['logging', 'simple_logger']; - final noStdFeatures = ['libc_alloc', 'panic_handler']; - final features = { - 'default_components', - 'icu_collator', - 'icu_datetime', - 'icu_list', - 'icu_decimal', - 'icu_plurals', - 'compiled_data', - 'buffer_provider', - 'experimental_components', - ...(isNoStd ? noStdFeatures : stdFeatures), - }; - final arguments = [ - if (buildStatic || isNoStd) '+nightly', - 'rustc', - '--manifest-path=$workingDirectory/ffi/capi/Cargo.toml', - '--crate-type=${buildStatic ? 'staticlib' : 'cdylib'}', - '--release', - '--config=profile.release.panic="abort"', - '--config=profile.release.codegen-units=1', - '--no-default-features', - '--features=${features.join(',')}', - if (isNoStd) '-Zbuild-std=core,alloc', - if (buildStatic || isNoStd) ...[ - '-Zbuild-std=std,panic_abort', - '-Zbuild-std-features=panic_immediate_abort', - ], - '--target=$target', - ]; - await runProcess('cargo', arguments, workingDirectory: workingDirectory); - - final builtPath = path.join( - workingDirectory, - 'target', - target, - 'release', - libFileName, - ); - final file = File(builtPath); - if (!(await file.exists())) { - throw FileSystemException('Building the dylib failed', builtPath); - } - await file.copy(libFileUri.toFilePath(windows: Platform.isWindows)); - return libFileUri; -} -String asRustTarget(BuildInput input) { - final rustTarget = _asRustTarget( - input.config.code.targetOS, - input.config.code.targetArchitecture, - input.config.code.targetOS == OS.iOS && - input.config.code.iOS.targetSdk == IOSSdk.iPhoneSimulator, - ); - return rustTarget; -} - -String _asRustTarget(OS os, Architecture? architecture, bool isSimulator) { - if (os == OS.iOS && architecture == Architecture.arm64 && isSimulator) { - return 'aarch64-apple-ios-sim'; - } - return switch ((os, architecture)) { - (OS.android, Architecture.arm) => 'armv7-linux-androideabi', - (OS.android, Architecture.arm64) => 'aarch64-linux-android', - (OS.android, Architecture.ia32) => 'i686-linux-android', - (OS.android, Architecture.riscv64) => 'riscv64-linux-android', - (OS.android, Architecture.x64) => 'x86_64-linux-android', - (OS.fuchsia, Architecture.arm64) => 'aarch64-unknown-fuchsia', - (OS.fuchsia, Architecture.x64) => 'x86_64-unknown-fuchsia', - (OS.iOS, Architecture.arm64) => 'aarch64-apple-ios', - (OS.iOS, Architecture.x64) => 'x86_64-apple-ios', - (OS.linux, Architecture.arm) => 'armv7-unknown-linux-gnueabihf', - (OS.linux, Architecture.arm64) => 'aarch64-unknown-linux-gnu', - (OS.linux, Architecture.ia32) => 'i686-unknown-linux-gnu', - (OS.linux, Architecture.riscv32) => 'riscv32gc-unknown-linux-gnu', - (OS.linux, Architecture.riscv64) => 'riscv64gc-unknown-linux-gnu', - (OS.linux, Architecture.x64) => 'x86_64-unknown-linux-gnu', - (OS.macOS, Architecture.arm64) => 'aarch64-apple-darwin', - (OS.macOS, Architecture.x64) => 'x86_64-apple-darwin', - (OS.windows, Architecture.arm64) => 'aarch64-pc-windows-msvc', - (OS.windows, Architecture.ia32) => 'i686-pc-windows-msvc', - (OS.windows, Architecture.x64) => 'x86_64-pc-windows-msvc', - (_, _) => - throw UnimplementedError( - 'Target ${(os, architecture)} not available for rust', - ), - }; + @override + List get dependencies => [checkoutPath!.resolve('Cargo.lock')]; } -bool _isNoStdTarget((OS os, Architecture? architecture) arg) => [ - (OS.android, Architecture.riscv64), - (OS.linux, Architecture.riscv64), -].contains(arg); - extension on BuildConfig { bool buildStatic(bool treeshake) => code.linkModePreference == LinkModePreference.static || diff --git a/pkgs/intl4x/hook/link.dart b/pkgs/intl4x/hook/link.dart index 48118278..4d85fc1e 100644 --- a/pkgs/intl4x/hook/link.dart +++ b/pkgs/intl4x/hook/link.dart @@ -5,10 +5,11 @@ import 'dart:convert'; import 'dart:io'; -import 'package:collection/collection.dart'; +import 'package:code_assets/code_assets.dart' show LinkInputCodeAssets; +import 'package:collection/collection.dart' show IterableExtension; +import 'package:hooks/hooks.dart' show LinkInput, link; import 'package:intl4x/src/hook_helpers/shared.dart' show assetId, package; import 'package:logging/logging.dart'; -import 'package:native_assets_cli/code_assets.dart'; import 'package:native_toolchain_c/native_toolchain_c.dart'; import 'package:record_use/record_use.dart' as record_use; @@ -31,22 +32,19 @@ Future main(List args) async { output.addDependency(staticLib.file!); - final usedSymbols = input.usages - .instancesOf(recordSymbolId)! - .map( - (instance) => - // Get the "symbol" field value from "RecordSymbol" - (instance.instanceConstant.fields.values.first - as record_use.StringConstant) - .value, - ); - final linker = CLinker.library( + final usages = input.usages; + final usedSymbols = usages + ?.constantsOf(recordSymbolId) + .map((instance) => instance['symbol'] as String); + + print('Using symbols: $usedSymbols'); + + await CLinker.library( name: input.packageName, assetName: assetId, sources: [staticLib.file!.path], linkerOptions: LinkerOptions.treeshake(symbols: usedSymbols), - ); - await linker.run( + ).run( input: input, output: output, logger: @@ -58,9 +56,11 @@ Future main(List args) async { } extension on LinkInput { - record_use.RecordedUsages get usages { - final usagesFile = recordedUsagesFile; - final usagesContent = File.fromUri(usagesFile!).readAsStringSync(); + record_use.RecordedUsages? get usages { + if (recordedUsagesFile == null) { + return null; + } + final usagesContent = File.fromUri(recordedUsagesFile!).readAsStringSync(); final usagesJson = jsonDecode(usagesContent) as Map; return record_use.RecordedUsages.fromJson(usagesJson); } diff --git a/pkgs/intl4x/lib/src/display_names/display_names_impl.dart b/pkgs/intl4x/lib/src/display_names/display_names_impl.dart index e971e224..07775d55 100644 --- a/pkgs/intl4x/lib/src/display_names/display_names_impl.dart +++ b/pkgs/intl4x/lib/src/display_names/display_names_impl.dart @@ -7,10 +7,10 @@ import '../ecma/ecma_policy.dart'; import '../locale/locale.dart'; import '../options.dart'; import '../utils.dart'; -import 'display_names_4x.dart' - if (dart.library.js) 'display_names_stub_4x.dart'; import 'display_names_options.dart'; import 'display_names_stub.dart' if (dart.library.js) 'display_names_ecma.dart'; +import 'display_names_stub_4x.dart' + if (dart.library.io) 'display_names_4x.dart'; /// This is an intermediate to defer to the actual implementations of /// Display naming. diff --git a/pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart b/pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart new file mode 100644 index 00000000..2692bf6c --- /dev/null +++ b/pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart @@ -0,0 +1,192 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +import 'dart:io'; + +import 'package:code_assets/code_assets.dart'; +import 'package:args/args.dart'; +import 'package:path/path.dart' as path; + +const crateName = 'icu_capi'; + +Future main(List args) async { + const fileKey = 'file'; + const osKey = 'os'; + const architectureKey = 'architecture'; + const simulatorKey = 'simulator'; + const compileTypeKey = 'compile_type'; + const cargoFeaturesKey = 'cargo_features'; + final argParser = + ArgParser() + ..addOption(fileKey, mandatory: true) + ..addOption( + compileTypeKey, + allowed: ['static', 'dynamic'], + mandatory: true, + ) + ..addFlag(simulatorKey, defaultsTo: false) + ..addOption(osKey, mandatory: true) + ..addOption(architectureKey, mandatory: true) + ..addMultiOption( + cargoFeaturesKey, + defaultsTo: ['default_components', 'compiled_data'], + ); + + ArgResults parsed; + try { + parsed = argParser.parse(args); + } catch (e) { + print('Error parsing $args'); + print(argParser.usage); + exit(1); + } + + final lib = await buildLib( + OS.values.firstWhere((o) => o.name == parsed.option(osKey)!), + Architecture.values.firstWhere( + (o) => o.name == parsed.option(architectureKey)!, + ), + parsed.option(compileTypeKey)! == 'static', + parsed.flag(simulatorKey), + File.fromUri(Platform.script).parent, + parsed.multiOption(cargoFeaturesKey), + ); + await lib.copy( + Uri.file(parsed.option(fileKey)!).toFilePath(windows: Platform.isWindows), + ); +} + +// Copied from Dart's package:intl4x build.dart, see +// https://github.com/dart-lang/i18n/blob/main/pkgs/intl4x/hook/build.dart +Future buildLib( + OS targetOS, + Architecture targetArchitecture, + bool buildStatic, + bool isSimulator, + Directory startingPoint, + List cargoFeatures, +) async { + // We assume that the first folder to contain a cargo.toml above the + // output directory is the directory containing the ICU4X code. + var workingDirectory = startingPoint; + while (!File.fromUri( + workingDirectory.uri.resolve('Cargo.toml'), + ).existsSync()) { + workingDirectory = workingDirectory.parent; + } + + final isNoStd = _isNoStdTarget((targetOS, targetArchitecture)); + final target = _asRustTarget(targetOS, targetArchitecture, isSimulator); + if (!isNoStd) { + final rustArguments = ['target', 'add', target]; + await runProcess( + 'rustup', + rustArguments, + workingDirectory: workingDirectory, + ); + } + + await runProcess('cargo', [ + if (buildStatic || isNoStd) '+nightly', + 'rustc', + '--manifest-path=ffi/capi/Cargo.toml', + '--crate-type=${buildStatic ? 'staticlib' : 'cdylib'}', + '--release', + '--config=profile.release.panic="abort"', + '--config=profile.release.codegen-units=1', + '--no-default-features', + '--features=${{ + ...cargoFeatures, + ...(isNoStd ? ['libc_alloc', 'panic_handler'] : ['logging', 'simple_logger']), + }.join(',')}', + if (isNoStd) '-Zbuild-std=core,alloc', + if (buildStatic || isNoStd) ...[ + '-Zbuild-std=std,panic_abort', + '-Zbuild-std-features=panic_immediate_abort', + ], + '--target=$target', + ], workingDirectory: workingDirectory); + + final file = File( + path.join( + workingDirectory.path, + 'target', + target, + 'release', + (buildStatic ? targetOS.staticlibFileName : targetOS.dylibFileName)( + crateName.replaceAll('-', '_'), + ), + ), + ); + if (!(await file.exists())) { + throw FileSystemException('Building the dylib failed', file.path); + } + return file; +} + +String _asRustTarget(OS os, Architecture? architecture, bool isSimulator) { + if (os == OS.iOS && architecture == Architecture.arm64 && isSimulator) { + return 'aarch64-apple-ios-sim'; + } + return switch ((os, architecture)) { + (OS.android, Architecture.arm) => 'armv7-linux-androideabi', + (OS.android, Architecture.arm64) => 'aarch64-linux-android', + (OS.android, Architecture.ia32) => 'i686-linux-android', + (OS.android, Architecture.riscv64) => 'riscv64-linux-android', + (OS.android, Architecture.x64) => 'x86_64-linux-android', + (OS.fuchsia, Architecture.arm64) => 'aarch64-unknown-fuchsia', + (OS.fuchsia, Architecture.x64) => 'x86_64-unknown-fuchsia', + (OS.iOS, Architecture.arm64) => 'aarch64-apple-ios', + (OS.iOS, Architecture.x64) => 'x86_64-apple-ios', + (OS.linux, Architecture.arm) => 'armv7-unknown-linux-gnueabihf', + (OS.linux, Architecture.arm64) => 'aarch64-unknown-linux-gnu', + (OS.linux, Architecture.ia32) => 'i686-unknown-linux-gnu', + (OS.linux, Architecture.riscv32) => 'riscv32gc-unknown-linux-gnu', + (OS.linux, Architecture.riscv64) => 'riscv64gc-unknown-linux-gnu', + (OS.linux, Architecture.x64) => 'x86_64-unknown-linux-gnu', + (OS.macOS, Architecture.arm64) => 'aarch64-apple-darwin', + (OS.macOS, Architecture.x64) => 'x86_64-apple-darwin', + (OS.windows, Architecture.arm64) => 'aarch64-pc-windows-msvc', + (OS.windows, Architecture.ia32) => 'i686-pc-windows-msvc', + (OS.windows, Architecture.x64) => 'x86_64-pc-windows-msvc', + (_, _) => + throw UnimplementedError( + 'Target ${(os, architecture)} not available for rust', + ), + }; +} + +bool _isNoStdTarget((OS os, Architecture? architecture) arg) => [ + (OS.android, Architecture.riscv64), + (OS.linux, Architecture.riscv64), +].contains(arg); + +Future runProcess( + String executable, + List arguments, { + Directory? workingDirectory, + bool dryRun = false, +}) async { + print('----------'); + print('Running `$executable $arguments` in $workingDirectory'); + if (!dryRun) { + final processResult = await Process.run( + executable, + arguments, + workingDirectory: workingDirectory?.path, + ); + print('stdout:'); + print(processResult.stdout); + if ((processResult.stderr as String).isNotEmpty) { + print('stderr:'); + print(processResult.stderr); + } + if (processResult.exitCode != 0) { + throw ProcessException(executable, arguments, '', processResult.exitCode); + } + } else { + print('Not running, as --dry-run is set.'); + } + print('=========='); +} diff --git a/pkgs/intl4x/lib/src/hook_helpers/build_options.dart b/pkgs/intl4x/lib/src/hook_helpers/build_options.dart index bb73ed2b..ba1dfe6a 100644 --- a/pkgs/intl4x/lib/src/hook_helpers/build_options.dart +++ b/pkgs/intl4x/lib/src/hook_helpers/build_options.dart @@ -2,44 +2,20 @@ // 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:convert' show JsonEncoder, json; +import 'dart:convert' show JsonEncoder; import 'dart:io'; +// ignore: implementation_imports +import 'package:collection/collection.dart'; +import 'package:hooks/hooks.dart' show HookInputUserDefines; import 'package:path/path.dart' as path; -import 'package:yaml/yaml.dart' show YamlMap, loadYaml; - -Future getBuildOptions(String searchDir) async { - final map = await readOptionsFromPubspec(searchDir); - print('Reading build options from $map'); - final buildOptions = BuildOptions.fromMap(map?['intl4x'] as Map? ?? {}); - print('Got build options: ${buildOptions.toJson()}'); - return buildOptions; -} - -Future readOptionsFromPubspec(String searchPath) async { - File pubspec(Directory dir) => File(path.join(dir.path, 'pubspec.yaml')); - - var directory = Directory(searchPath); - var counter = 0; - while (!pubspec(directory).existsSync()) { - directory = directory.parent; - counter++; - if (counter > 10) { - throw ArgumentError('Could not find pubspec at $searchPath'); - } - } - - final pubspecYaml = - loadYaml(pubspec(directory).readAsStringSync()) as YamlMap; - return pubspecYaml['hook'] as YamlMap?; -} enum BuildModeEnum { local, checkout, fetch } class BuildOptions { final BuildModeEnum buildMode; - final String? localDylibPath; - final String? checkoutPath; + final Uri? localDylibPath; + final Uri? checkoutPath; final bool? treeshake; BuildOptions({ @@ -52,25 +28,27 @@ class BuildOptions { Map toMap() { return { 'buildMode': buildMode.name, - if (localDylibPath != null) 'localDylibPath': localDylibPath, - if (checkoutPath != null) 'checkoutPath': checkoutPath, + if (localDylibPath != null) 'localDylibPath': localDylibPath.toString(), + if (checkoutPath != null) 'checkoutPath': checkoutPath.toString(), if (treeshake != null) 'treeshake': treeshake.toString(), }; } - factory BuildOptions.fromMap(Map map) { + factory BuildOptions.fromDefines(HookInputUserDefines defines) { return BuildOptions( - buildMode: BuildModeEnum.values.firstWhere( - (element) => element.name == map['buildMode'], - ), - localDylibPath: map['localDylibPath'] as String?, - checkoutPath: map['checkoutPath'] as String?, - treeshake: map['treeshake'] == true, + buildMode: + BuildModeEnum.values.firstWhereOrNull( + (element) => element.name == defines['buildMode'], + ) ?? + BuildModeEnum.fetch, + localDylibPath: defines.path('localDylibPath'), + checkoutPath: defines.path('checkoutPath'), + treeshake: (defines['treeshake'] ?? true) == true, ); } - String toJson() => const JsonEncoder.withIndent(' ').convert(toMap()); + static String getPath(Directory dir, String p) => + path.canonicalize(path.absolute(dir.path, p)); - factory BuildOptions.fromJson(String source) => - BuildOptions.fromMap(json.decode(source) as Map); + String toJson() => const JsonEncoder.withIndent(' ').convert(toMap()); } diff --git a/pkgs/intl4x/lib/src/hook_helpers/hashes.dart b/pkgs/intl4x/lib/src/hook_helpers/hashes.dart index 7a893391..0f8b5b28 100644 --- a/pkgs/intl4x/lib/src/hook_helpers/hashes.dart +++ b/pkgs/intl4x/lib/src/hook_helpers/hashes.dart @@ -7,7 +7,7 @@ // dart tool/regenerate_hashes.dart // -import 'package:native_assets_cli/code_assets.dart' show Architecture, OS; +import 'package:code_assets/code_assets.dart' show Architecture, OS; const fileHashes = <(OS, Architecture, String), String>{ (OS.linux, Architecture.arm, 'dynamic'): diff --git a/pkgs/intl4x/pubspec.yaml b/pkgs/intl4x/pubspec.yaml index a5f45724..656eea99 100644 --- a/pkgs/intl4x/pubspec.yaml +++ b/pkgs/intl4x/pubspec.yaml @@ -1,7 +1,7 @@ name: intl4x description: >- A lightweight modular library for internationalization (i18n) functionality. -version: 0.11.3 +version: 0.11.4 repository: https://github.com/dart-lang/i18n/tree/main/pkgs/intl4x issue_tracker: https://github.com/dart-lang/i18n/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aintl4x @@ -20,21 +20,21 @@ environment: sdk: ^3.7.0 dependencies: + args: ^2.7.0 + code_assets: ^0.19.3 collection: ^1.19.1 - crypto: ^3.0.3 - ffi: ^2.1.0 + crypto: ^3.0.6 + ffi: ^2.1.4 + hooks: ^0.19.3 logging: ^1.3.0 - meta: ^1.12.0 - native_assets_cli: ^0.11.0 - native_toolchain_c: ^0.8.0 - path: ^1.9.0 - record_use: ^0.3.0 - yaml: ^3.1.3 + meta: ^1.17.0 + native_toolchain_c: ^0.16.2 + path: ^1.9.1 + record_use: ^0.4.0 dev_dependencies: - args: ^2.4.2 - dart_flutter_team_lints: ^3.1.0 - test: ^1.22.1 + dart_flutter_team_lints: ^3.5.1 + test: ^1.26.2 yaml_edit: ^2.2.2 hook: diff --git a/pkgs/intl4x/tool/build_libs.g.dart b/pkgs/intl4x/tool/build_libs.g.dart index 52649391..b20b5d3b 100644 --- a/pkgs/intl4x/tool/build_libs.g.dart +++ b/pkgs/intl4x/tool/build_libs.g.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:args/args.dart'; -import 'package:native_assets_cli/code_assets.dart'; +import 'package:code_assets/code_assets.dart'; import 'package:path/path.dart' as path; const crateName = 'icu_capi'; @@ -14,7 +14,6 @@ Future main(List args) async { const fileKey = 'file'; const osKey = 'os'; const architectureKey = 'architecture'; - const workingDirectoryKey = 'working_directory'; const simulatorKey = 'simulator'; const compileTypeKey = 'compile_type'; const cargoFeaturesKey = 'cargo_features'; @@ -29,7 +28,6 @@ Future main(List args) async { ..addFlag(simulatorKey, defaultsTo: false) ..addOption(osKey, mandatory: true) ..addOption(architectureKey, mandatory: true) - ..addOption(workingDirectoryKey, mandatory: true) ..addMultiOption( cargoFeaturesKey, defaultsTo: ['default_components', 'compiled_data'], @@ -51,7 +49,7 @@ Future main(List args) async { ), parsed.option(compileTypeKey)! == 'static', parsed.flag(simulatorKey), - Directory(parsed.option(workingDirectoryKey)!), + File.fromUri(Platform.script).parent, parsed.multiOption(cargoFeaturesKey), ); await lib.copy( @@ -59,16 +57,23 @@ Future main(List args) async { ); } +// Copied from Dart's package:intl4x build.dart, see +// https://github.com/dart-lang/i18n/blob/main/pkgs/intl4x/hook/build.dart Future buildLib( OS targetOS, Architecture targetArchitecture, bool buildStatic, bool isSimulator, - Directory workingDirectory, + Directory startingPoint, List cargoFeatures, ) async { - if (!File.fromUri(workingDirectory.uri.resolve('Cargo.toml')).existsSync()) { - throw ArgumentError('No Cargo.toml found in $workingDirectory'); + // We assume that the first folder to contain a cargo.toml above the + // output directory is the directory containing the ICU4X code. + var workingDirectory = startingPoint; + while (!File.fromUri( + workingDirectory.uri.resolve('Cargo.toml'), + ).existsSync()) { + workingDirectory = workingDirectory.parent; } final isNoStd = _isNoStdTarget((targetOS, targetArchitecture)); @@ -82,12 +87,6 @@ Future buildLib( ); } - final features = { - ...cargoFeatures, - ...(isNoStd - ? ['libc_alloc', 'looping_panic_handler'] - : ['logging', 'simple_logger']), - }; await runProcess('cargo', [ if (buildStatic || isNoStd) '+nightly', 'rustc', @@ -97,7 +96,10 @@ Future buildLib( '--config=profile.release.panic="abort"', '--config=profile.release.codegen-units=1', '--no-default-features', - '--features=${features.join(',')}', + '--features=${{ + ...cargoFeatures, + ...(isNoStd ? ['libc_alloc', 'panic_handler'] : ['logging', 'simple_logger']), + }.join(',')}', if (isNoStd) '-Zbuild-std=core,alloc', if (buildStatic || isNoStd) ...[ '-Zbuild-std=std,panic_abort', diff --git a/pkgs/intl4x/tool/regenerate_hashes.dart b/pkgs/intl4x/tool/regenerate_hashes.dart index bac7dd6b..a7bbf746 100644 --- a/pkgs/intl4x/tool/regenerate_hashes.dart +++ b/pkgs/intl4x/tool/regenerate_hashes.dart @@ -4,9 +4,9 @@ import 'dart:io'; +import 'package:code_assets/code_assets.dart' show Architecture; import 'package:crypto/crypto.dart'; import 'package:intl4x/src/hook_helpers/version.dart'; -import 'package:native_assets_cli/code_assets.dart' show Architecture; Future main(List args) async { final httpClient = HttpClient(); @@ -44,7 +44,7 @@ Future main(List args) async { // dart tool/regenerate_hashes.dart // -import 'package:native_assets_cli/code_assets.dart' show Architecture, OS; +import 'package:code_assets/code_assets.dart' show Architecture, OS; const fileHashes = <(OS, Architecture, String), String>{ ${fileHashes.map((key, value) => MapEntry(('OS.${key.$1}', 'Architecture.${key.$2}', "'${key.$3}'"), "'$value'")).entries.map((e) => ' ${e.key}:\n ${e.value},').join('\n')} diff --git a/pkgs/intl4x/tool/write_option_file.dart b/pkgs/intl4x/tool/write_option_file.dart index bebfbbdb..42cc6b45 100644 --- a/pkgs/intl4x/tool/write_option_file.dart +++ b/pkgs/intl4x/tool/write_option_file.dart @@ -17,11 +17,11 @@ Future main(List args) async { final buildOptions = switch (buildMode) { BuildModeEnum.local => BuildOptions( buildMode: buildMode, - localDylibPath: pathString, + localDylibPath: Uri.parse(pathString!), ), BuildModeEnum.checkout => BuildOptions( buildMode: buildMode, - checkoutPath: pathString, + checkoutPath: Uri.parse(pathString!), ), BuildModeEnum.fetch => BuildOptions(buildMode: buildMode), }; diff --git a/tools/regenerate_bindings.sh b/tools/regenerate_bindings.sh index 21cc69cb..845a1236 100644 --- a/tools/regenerate_bindings.sh +++ b/tools/regenerate_bindings.sh @@ -1,6 +1,10 @@ rm pkgs/intl4x/lib/src/bindings/* cd pkgs/intl4x/lib/src/bindings/ cp -a ../../../../../submodules/icu4x/ffi/capi/bindings/dart/*.dart . +cd ../../../../../ cp submodules/icu4x/ffi/dart/tool/build_libs.dart pkgs/intl4x/tool/build_libs.g.dart -dart format . +cp submodules/icu4x/ffi/dart/tool/build_libs.dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart +dart format pkgs/intl4x/lib/src/bindings/ +dart format pkgs/intl4x/tool/build_libs.g.dart +dart format pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart