From a7d36c0fe10f41ae28fdf453c009fb8c348adf01 Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Wed, 13 Oct 2021 10:06:31 -0700 Subject: [PATCH 1/5] Add a bunch of args to setup.dart to customize the build --- bin/setup.dart | 159 +++++++++++++++++++++++++++++++++++++++---------- pubspec.yaml | 1 + 2 files changed, 130 insertions(+), 30 deletions(-) diff --git a/bin/setup.dart b/bin/setup.dart index f29140d..8985745 100644 --- a/bin/setup.dart +++ b/bin/setup.dart @@ -3,27 +3,75 @@ // BSD-style license that can be found in the LICENSE file. // Builds the wasmer runtime library, to by used by package:wasm. Requires -// rustc, cargo, clang, and clang++. If a target triple is not specified, it -// will default to the host target. -// Usage: dart run wasm:setup [optional target-triple] +// Rust (rustc, rustup, cargo), and Clang (clang, clang++, ar). +// Usage: dart run wasm:setup +// For more details use the --help option. import 'dart:convert'; import 'dart:io' hide exit; +import 'package:args/args.dart'; import 'package:package_config/package_config.dart' show findPackageConfig; import 'package:wasm/src/shared.dart'; -Future main(List args) async { - if (args.length > 1) { - print('Usage: $invocationString [target-triple]'); - exitCode = 64; // bad usage +Future main(List arguments) async { + final parser = ArgParser() + ..addOption( + 'target', + abbr: 't', + help: 'Target triple. Defaults to host target.', + ) + ..addOption( + 'out-dir', + abbr: 'o', + help: 'Output directory. Defaults to the directory that package:wasm ' + 'searches.', + ) + ..addOption( + 'rustc', + help: "Path of rustc. Defaults to assuming it's in PATH variable.", + ) + ..addOption( + 'rustup', + help: "Path of rustup. Defaults to assuming it's in PATH variable.", + ) + ..addOption( + 'cargo', + help: "Path of cargo. Defaults to assuming it's in PATH variable.", + ) + ..addOption( + 'clang', + help: "Path of clang. Defaults to assuming it's in PATH variable.", + ) + ..addOption( + 'clangpp', + help: "Path of clang++. Defaults to assuming it's in PATH variable.", + ) + ..addOption( + 'ar', + help: "Path of ar. Defaults to assuming it's in PATH variable.", + ) + ..addOption( + 'sysroot', + help: 'Sysroot argument passed to linker.', + ) + ..addFlag( + 'help', + abbr: 'h', + negatable: false, + help: 'Show this help.', + ); + final args = parser.parse(arguments); + + if (args['help'] as bool) { + print('Usage: $invocationString [OPTION...]\n'); + print(parser.usage); + exitCode = 0; // ok return; } - final target = args.isNotEmpty ? args[0] : await _getTargetTriple(); - try { - await _main(target); + await _main(args); } on ProcessException catch (e) { final invocation = [e.executable, ...e.arguments].join(' '); print('FAILED with exit code ${e.errorCode} `$invocation`'); @@ -144,9 +192,9 @@ String _getWasmerLib(String os) { return 'libwasmer.a'; } -Future _getTargetTriple() async { +Future _getTargetTriple(String rustc) async { final _regexp = RegExp(r'^([^=]+)="(.*)"$'); - final process = await Process.start('rustc', ['--print', 'cfg']); + final process = await Process.start(rustc, ['--print', 'cfg']); final sub = process.stderr .transform(utf8.decoder) .transform(const LineSplitter()) @@ -170,21 +218,56 @@ Future _getTargetTriple() async { .join('-'); } -Future _run(String exe, List args) async { +Future _run( + String exe, + List args, { + Map? environment, +}) async { print('\n$exe ${args.join(' ')}\n'); - final process = - await Process.start(exe, args, mode: ProcessStartMode.inheritStdio); + final process = await Process.start( + exe, + args, + mode: ProcessStartMode.inheritStdio, + environment: environment, + ); final result = await process.exitCode; if (result != 0) { throw ProcessException(exe, args, '', result); } } -Future _main(String target) async { +String _findToolInPath(String tool) { + final delim = Platform.isWindows ? ';' : ':'; + for (final path in (Platform.environment['PATH'] ?? '').split(delim)) { + final file = Uri.directory(path).resolve(tool).toFilePath(); + if (FileSystemEntity.isFileSync(file)) { + return file; + } + } + throw FileSystemException( + "Can't find $tool in PATH variable", + Platform.environment['PATH'], + ); +} + +String _toUpperUnderscore(String string) { + return string.toUpperCase().replaceAll('-', '_'); +} + +Future _main(ArgResults args) async { + final rustc = args['rustc'] as String? ?? 'rustc'; + final rustup = args['rustup'] as String? ?? 'rustup'; + final cargo = args['cargo'] as String? ?? 'cargo'; + final clang = args['clang'] as String? ?? 'clang'; + final clangpp = args['clangpp'] as String? ?? 'clang++'; + + final target = args['target'] as String? ?? await _getTargetTriple(rustc); final sdkDir = _getSdkDir(); final sdkIncDir = _getSdkIncDir(sdkDir); final srcDir = await _getSrcDir(); - final outDir = _getOutDir(Directory.current.uri); + final outDir = args['out-dir'] != null + ? Uri.directory(args['out-dir'] as String) + : _getOutDir(Directory.current.uri); final os = _getOsFromTarget(target); final outLib = outDir.resolve(_getOutLib(os)).toFilePath(); @@ -196,17 +279,32 @@ Future _main(String target) async { print('OS: $os'); print('Output library: $outLib'); + // Make sure rust libs are installed for the target. + await _run(rustup, ['target', 'add', target]); + // Build wasmer crate. - await _run('cargo', [ - 'build', - '--target', - target, - '--target-dir', - outDir.toFilePath(), - '--manifest-path', - srcDir.resolve('Cargo.toml').toFilePath(), - '--release' - ]); + await _run( + cargo, + [ + 'build', + '--target', + target, + '--target-dir', + outDir.toFilePath(), + '--manifest-path', + srcDir.resolve('Cargo.toml').toFilePath(), + '--release' + ], + environment: { + if (args['clangpp'] != null) ...{ + 'CC': clangpp, + 'CXX': clangpp, + 'LINKER': clangpp, + 'CARGO_TARGET_${_toUpperUnderscore(target)}_LINKER': clangpp, + }, + if (args['ar'] != null) 'AR': args['ar'] as String, + }, + ); // Hack around a bug with dart_api_dl_impl.h include path in dart_api_dl.c. const dartApiDlImplPath = 'include/internal/dart_api_dl_impl.h'; @@ -218,7 +316,7 @@ Future _main(String target) async { } // Build dart_api_dl.o. - await _run('clang', [ + await _run(clang, [ '-DDART_SHARED_LIB', '-DNDEBUG', '-fno-exceptions', @@ -237,7 +335,7 @@ Future _main(String target) async { ]); // Build finalizers.o. - await _run('clang++', [ + await _run(clangpp, [ '-DDART_SHARED_LIB', '-DNDEBUG', '-fno-exceptions', @@ -258,8 +356,9 @@ Future _main(String target) async { ]); // Link wasmer, dart_api_dl, and finalizers to create the output library. - await _run('clang++', [ + await _run(clang, [ '-shared', + if (args['sysroot'] != null) '--sysroot=${args['sysroot']}', if (os != 'windows') '-fPIC', if (os == 'windows') ...[ '-lws2_32', diff --git a/pubspec.yaml b/pubspec.yaml index a597a1d..0e29a60 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,6 +7,7 @@ environment: sdk: '>=2.12.0 <3.0.0' dependencies: + args: ^2.3.0 ffi: ^1.0.0 package_config: ^2.0.0 From 88b35a164e024d2f0105949130812ffad655b0e7 Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Wed, 13 Oct 2021 10:07:51 -0700 Subject: [PATCH 2/5] Remove unused function --- bin/setup.dart | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/bin/setup.dart b/bin/setup.dart index 8985745..e0977f9 100644 --- a/bin/setup.dart +++ b/bin/setup.dart @@ -236,20 +236,6 @@ Future _run( } } -String _findToolInPath(String tool) { - final delim = Platform.isWindows ? ';' : ':'; - for (final path in (Platform.environment['PATH'] ?? '').split(delim)) { - final file = Uri.directory(path).resolve(tool).toFilePath(); - if (FileSystemEntity.isFileSync(file)) { - return file; - } - } - throw FileSystemException( - "Can't find $tool in PATH variable", - Platform.environment['PATH'], - ); -} - String _toUpperUnderscore(String string) { return string.toUpperCase().replaceAll('-', '_'); } From 8a7150b842a0b0cc396d718ce7b5805ab7e99f46 Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Wed, 13 Oct 2021 11:10:36 -0700 Subject: [PATCH 3/5] Fix a linker error --- README.md | 4 +++- bin/setup.dart | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 93829fa..1fc04c4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -Provides utilities for loading and running WASM modules +Provides utilities for loading and running WASM modules. Built on top of the [Wasmer](https://github.com/wasmerio/wasmer) runtime. +Flutter and web are **not supported** at the moment. Stay tuned though ;) + ## Setup Start by installing the tools needed to build the Wasmer runtime: diff --git a/bin/setup.dart b/bin/setup.dart index e0977f9..81c05aa 100644 --- a/bin/setup.dart +++ b/bin/setup.dart @@ -356,6 +356,7 @@ Future _main(ArgResults args) async { '-z', '/NODEFAULTLIB:MSVCRT', ], + '-lm', '-target', target, outDir.resolve('dart_api_dl.o').toFilePath(), From 6ede5ba37cd877b82917d6e11e63f9abd74bda80 Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Wed, 13 Oct 2021 11:36:31 -0700 Subject: [PATCH 4/5] Fix DynamicLibrary load path --- lib/src/runtime.dart | 10 ++++++++-- lib/src/runtime.g.dart | 13 +------------ tool/runtime_template.dart.t | 13 +------------ 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/lib/src/runtime.dart b/lib/src/runtime.dart index 38f0576..5a1c3e3 100644 --- a/lib/src/runtime.dart +++ b/lib/src/runtime.dart @@ -99,7 +99,7 @@ class _WasiStreamIterable extends Iterable> { String _getLibName() { if (Platform.isMacOS) return appleLib; - if (Platform.isLinux) return linuxLib; + if (Platform.isLinux || Platform.isAndroid) return linuxLib; if (Platform.isWindows) return windowsLib; // TODO(dartbug.com/37882): Support more platforms. throw WasmError('Wasm not currently supported on this platform'); @@ -107,11 +107,11 @@ String _getLibName() { String? _getLibPathFrom(Uri root) { final pkgRoot = packageRootUri(root); - return pkgRoot?.resolve('$wasmToolDir${_getLibName()}').toFilePath(); } String _getLibPath() { + if (Platform.isAndroid) return _getLibName(); var path = _getLibPathFrom(Platform.script.resolve('./')); if (path != null) return path; path = _getLibPathFrom(Directory.current.uri); @@ -119,6 +119,12 @@ String _getLibPath() { throw WasmError('Wasm library not found. Did you `$invocationString`?'); } +DynamicLibrary _loadDynamicLib() { + return Platform.isIOS + ? DynamicLibrary.process() + : DynamicLibrary.open(_getLibPath()); +} + String getSignatureString( String name, List argTypes, diff --git a/lib/src/runtime.g.dart b/lib/src/runtime.g.dart index c1cbb50..c4771bc 100644 --- a/lib/src/runtime.g.dart +++ b/lib/src/runtime.g.dart @@ -116,7 +116,7 @@ class WasmRuntime { late final WasmerWasmerLastErrorLengthFn _wasmer_last_error_length; late final WasmerWasmerLastErrorMessageFn _wasmer_last_error_message; - WasmRuntime._init() : _lib = _load_dynamic_lib() { + WasmRuntime._init() : _lib = _loadDynamicLib() { _Dart_InitializeApiDL = _lib.lookupFunction< NativeWasmerDartInitializeApiDLFn, WasmerDartInitializeApiDLFn>( 'Dart_InitializeApiDL', @@ -511,17 +511,6 @@ class WasmRuntime { _set_finalizer_for_store(this, _store); } - static DynamicLibrary _load_dynamic_lib() { - try { - return DynamicLibrary.open(_getLibPath()); - } catch (e) { - throw WasmError( - 'Failed to load Wasm dynamic library. ' - 'Have you run `dart run wasm:setup`?\n $e', - ); - } - } - Pointer compile( Object owner, Uint8List data, diff --git a/tool/runtime_template.dart.t b/tool/runtime_template.dart.t index f9b5fc6..b8f8651 100644 --- a/tool/runtime_template.dart.t +++ b/tool/runtime_template.dart.t @@ -18,7 +18,7 @@ class WasmRuntime { /* */ - WasmRuntime._init() : _lib = _load_dynamic_lib() { + WasmRuntime._init() : _lib = _loadDynamicLib() { /* */ if (_Dart_InitializeApiDL(NativeApi.initializeApiDLData) != 0) { @@ -32,17 +32,6 @@ class WasmRuntime { _set_finalizer_for_store(this, _store); } - static DynamicLibrary _load_dynamic_lib() { - try { - return DynamicLibrary.open(_getLibPath()); - } catch (e) { - throw WasmError( - 'Failed to load Wasm dynamic library. ' - 'Have you run `dart run wasm:setup`?\n $e', - ); - } - } - Pointer compile( Object owner, Uint8List data, From 8a96bac8bc6d54d34c54c3619c4a74ac8da565dd Mon Sep 17 00:00:00 2001 From: Liam Appelbe Date: Wed, 13 Oct 2021 13:23:42 -0700 Subject: [PATCH 5/5] Changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36e572c..e148ac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Update to Wasmer 2.0.0 - All WASM modules and isntances use a singleton store, to enable sharing of memory and functions. +- Add options to setup.dart for configuring the build. ## 0.1.0+1