blob: 182a6561a138a4c07c910f384b6ca00cd7a721ca [file] [log] [blame]
// Copyright (c) 2025, 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.
import 'dart:io';
import 'package:args/args.dart';
import 'package:kernel/ast.dart' show Library;
import 'package:kernel/kernel.dart' show loadComponentFromBinary;
import 'package:path/path.dart' as path;
import 'package:vm/embedder/visitor.dart' as visitor show visitLibrary;
import 'package:vm/embedder/writer.dart' show EntryPointShimWriter;
final String _usage = '''
Usage: generate_entry_point_shims [options] source.dill out/basename
Creates appropriate entry point shims for the entry points in the component
encoded by the provided dill. If the component has a main method, then only
translates entry points in the same package as the main method, otherwise
requires a package to be specified via the command-line options.
out/basename.h contains the declarations of the shim functions and
out/basename.cc contains the definitions.
Options:
''';
void main(List<String> args) async {
final parser =
ArgParser()
..addFlag(
'uninitialized',
abbr: 'u',
help:
'Create allocation and initializion methods for uninitialized instances',
)
..addFlag(
'error-unhandled',
abbr: 'e',
help: 'Error for entry points that cannot be shimmed',
)
..addFlag(
'help',
abbr: 'h',
help: 'Prints usage information and exits',
negatable: false,
)
..addOption(
'package',
abbr: 'p',
help: 'Consider entry points only from the specified package',
valueHelp: 'URI',
);
Never usageFail([String? prefix]) {
if (prefix != null) {
print(prefix);
print('');
}
print(_usage);
print(parser.usage);
exit(1);
}
final argResults = parser.parse(args);
if (argResults['help'] || argResults.rest.length != 2) {
usageFail();
}
final outputPath = path.normalize(argResults.rest[1]);
final outputDir = Directory(path.dirname(outputPath));
if (!outputDir.existsSync()) {
outputDir.createSync(recursive: true);
}
final source = argResults.rest[0];
final component = loadComponentFromBinary(source);
Library? library;
final uriString = argResults['package'];
if (uriString == null) {
final mainMethod = component.mainMethod;
if (mainMethod == null) {
usageFail('No main method found, so -p/--package is required.');
}
} else {
final uri = Uri.tryParse(uriString);
if (uri == null) {
usageFail('${argResults['package']} is not a valid URI.');
}
for (final l in component.libraries) {
if (l.importUri == uri) {
library = l;
break;
}
}
if (library == null) {
usageFail('No package found with URI ${argResults['package']}.');
}
}
final createUninitializedInstanceMethods = argResults['uninitialized'];
final collector = visitor.visitLibrary(
component,
library ?? component.mainMethod!.enclosingLibrary,
createUninitializedInstanceMethods: createUninitializedInstanceMethods,
errorOnUnhandledEntryPoints: argResults['error-unhandled'],
);
final declarations = StringBuffer();
final definitions = StringBuffer();
for (final buffer in [declarations, definitions]) {
buffer.write('''
/*
Generated with:
dart pkg/vm/tool/generate_entry_point_shims.dart \\
''');
if (createUninitializedInstanceMethods) {
buffer.write('-u ');
}
if (uriString != null) {
buffer.write('''-p $uriString \\
''');
}
buffer.writeln('''$source \\
$outputPath
*/
''');
}
final headerPath = outputPath + '.h';
final writer = EntryPointShimWriter(headerPath, library, collector);
writer.write(declarations, definitions);
final implPath = outputPath + '.cc';
File(headerPath).writeAsStringSync(declarations.toString(), flush: true);
File(implPath).writeAsStringSync(definitions.toString(), flush: true);
}