Skip to content
This repository has been archived by the owner on Jul 1, 2023. It is now read-only.

Add flags to setup.dart required to get Android build working #48

Merged
merged 6 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
146 changes: 116 additions & 30 deletions bin/setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> main(List<String> args) async {
if (args.length > 1) {
print('Usage: $invocationString [target-triple]');
exitCode = 64; // bad usage
Future<void> main(List<String> 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`');
Expand Down Expand Up @@ -144,9 +192,9 @@ String _getWasmerLib(String os) {
return 'libwasmer.a';
}

Future<String> _getTargetTriple() async {
Future<String> _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())
Expand All @@ -170,21 +218,42 @@ Future<String> _getTargetTriple() async {
.join('-');
}

Future<void> _run(String exe, List<String> args) async {
Future<void> _run(
String exe,
List<String> args, {
Map<String, String>? 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<void> _main(String target) async {
String _toUpperUnderscore(String string) {
return string.toUpperCase().replaceAll('-', '_');
}

Future<void> _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();

Expand All @@ -196,17 +265,32 @@ Future<void> _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';
Expand All @@ -218,7 +302,7 @@ Future<void> _main(String target) async {
}

// Build dart_api_dl.o.
await _run('clang', [
await _run(clang, [
'-DDART_SHARED_LIB',
'-DNDEBUG',
'-fno-exceptions',
Expand All @@ -237,7 +321,7 @@ Future<void> _main(String target) async {
]);

// Build finalizers.o.
await _run('clang++', [
await _run(clangpp, [
'-DDART_SHARED_LIB',
'-DNDEBUG',
'-fno-exceptions',
Expand All @@ -258,8 +342,9 @@ Future<void> _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',
Expand All @@ -271,6 +356,7 @@ Future<void> _main(String target) async {
'-z',
'/NODEFAULTLIB:MSVCRT',
],
'-lm',
'-target',
target,
outDir.resolve('dart_api_dl.o').toFilePath(),
Expand Down
10 changes: 8 additions & 2 deletions lib/src/runtime.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,32 @@ class _WasiStreamIterable extends Iterable<List<int>> {

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');
}

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);
if (path != null) return path;
throw WasmError('Wasm library not found. Did you `$invocationString`?');
}

DynamicLibrary _loadDynamicLib() {
return Platform.isIOS
? DynamicLibrary.process()
: DynamicLibrary.open(_getLibPath());
}

String getSignatureString(
String name,
List<int> argTypes,
Expand Down
13 changes: 1 addition & 12 deletions lib/src/runtime.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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<WasmerModule> compile(
Object owner,
Uint8List data,
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
13 changes: 1 addition & 12 deletions tool/runtime_template.dart.t
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class WasmRuntime {

/* <RUNTIME_MEMB> */

WasmRuntime._init() : _lib = _load_dynamic_lib() {
WasmRuntime._init() : _lib = _loadDynamicLib() {
/* <RUNTIME_LOAD> */

if (_Dart_InitializeApiDL(NativeApi.initializeApiDLData) != 0) {
Expand All @@ -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<WasmerModule> compile(
Object owner,
Uint8List data,
Expand Down