blob: ad36423ac49ac417bdd441b7a8e4064db457fa78 [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// 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.
// 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 setup.dart [target-triple]
import 'dart:convert';
import 'dart:io';
Uri getSdkDir() {
// The common case, and how cli_util.dart computes the Dart SDK directory,
// path.dirname called twice on Platform.resolvedExecutable.
final exe = Uri.file(Platform.resolvedExecutable);
final commonSdkDir = exe.resolve('../../dart-sdk/');
if (Directory(commonSdkDir.path).existsSync()) {
return commonSdkDir;
}
// This is the less common case where the user is in the checked out Dart
// SDK, and is executing dart via:
// ./out/ReleaseX64/dart ...
final checkedOutSdkDir = exe.resolve('../dart-sdk/');
if (Directory(checkedOutSdkDir.path).existsSync()) {
return checkedOutSdkDir;
}
// If neither returned above, we return the common case:
return commonSdkDir;
}
Uri getOutDir(Uri root) {
// Traverse up until we see a `.dart_tool/package_config.json` file.
do {
if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
.existsSync()) {
return root.resolve('.dart_tool/wasm/');
}
} while (root != (root = root.resolve('..')));
throw Exception(".dart_tool/package_config.json not found");
}
String getOutLib(String target) {
final os = RegExp(r'^.*-.*-(.*)').firstMatch(target)?.group(1) ?? '';
if (os == 'darwin' || os == 'ios') {
return 'libwasmer.dylib';
} else if (os == 'windows') {
return 'wasmer.dll';
}
return 'libwasmer.so';
}
getTargetTriple() async {
final process = await Process.start('rustc', ['--print', 'cfg']);
process.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen((line) => stderr.writeln(line));
final cfg = {};
await process.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen((line) {
final match = RegExp(r'^([^=]+)="(.*)"$').firstMatch(line);
if (match != null) cfg[match.group(1)] = match.group(2);
}).asFuture();
String arch = cfg['target_arch'] ?? 'unknown';
String vendor = cfg['target_vendor'] ?? 'unknown';
String os = cfg['target_os'] ?? 'unknown';
String env = cfg['target_env'] ?? 'unknown';
return '$arch-$vendor-$os-$env';
}
run(String exe, List<String> args) async {
print('\n$exe ${args.join(' ')}\n');
final process = await Process.start(exe, args);
process.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen((line) => print(line));
process.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen((line) => stderr.writeln(line));
final exitCode = await process.exitCode;
if (exitCode != 0) {
print('Command failed with exit code ${exitCode}');
exit(exitCode);
}
}
main(List<String> args) async {
if (args.length > 1) {
print('Usage: dart setup.dart [target-triple]');
exit(1);
}
final target = args.length >= 1 ? args[0] : await getTargetTriple();
final sdkDir = getSdkDir();
final binDir = Platform.script;
final outDir = getOutDir(binDir);
final outLib = outDir.resolve(getOutLib(target)).path;
print('Dart SDK directory: ${sdkDir.path}');
print('Script directory: ${binDir.path}');
print('Output directory: ${outDir.path}');
print('Target: $target');
print('Output library: $outLib');
// Build wasmer crate.
await run('cargo', [
'build',
'--target',
target,
'--target-dir',
outDir.path,
'--manifest-path',
binDir.resolve('Cargo.toml').path,
'--release'
]);
// Hack around a bug with dart_api_dl_impl.h include path in dart_api_dl.c.
if (!File.fromUri(sdkDir.resolve('include/internal/dart_api_dl_impl.h'))
.existsSync()) {
Directory(outDir.resolve('include/internal/').path)
.createSync(recursive: true);
File.fromUri(sdkDir.resolve('include/runtime/dart_api_dl_impl.h'))
.copy(outDir.resolve('include/internal/dart_api_dl_impl.h').path);
}
// Build dart_api_dl.o.
await run('clang', [
'-DDART_SHARED_LIB',
'-DNDEBUG',
'-fno-exceptions',
'-fPIC',
'-O3',
'-target',
target,
'-I',
sdkDir.resolve('include/').path,
'-I',
outDir.resolve('include/').path,
'-c',
sdkDir.resolve('include/dart_api_dl.c').path,
'-o',
outDir.resolve('dart_api_dl.o').path
]);
// Build finalizers.o.
await run('clang++', [
'-DDART_SHARED_LIB',
'-DNDEBUG',
'-fno-exceptions',
'-fno-rtti',
'-fPIC',
'-O3',
'-std=c++11',
'-target',
target,
'-I',
sdkDir.path,
'-I',
outDir.resolve('include/').path,
'-c',
binDir.resolve('finalizers.cc').path,
'-o',
outDir.resolve('finalizers.o').path
]);
// Link wasmer, dart_api_dl, and finalizers to create the output library.
await run('clang++', [
'-shared',
'-Wl,--no-as-needed',
'-Wl,--fatal-warnings',
'-Wl,-z,now',
'-Wl,-z,noexecstack',
'-Wl,-z,relro',
'-Wl,--build-id=none',
'-fPIC',
'-Wl,-O1',
'-Wl,--gc-sections',
'-target',
target,
outDir.resolve('dart_api_dl.o').path,
outDir.resolve('finalizers.o').path,
outDir.resolve('' + target + '/release/libwasmer.a').path,
'-o',
outLib
]);
}