11b81715ad
Change-Id: I7b5e5dd768c87f28848ee02050582d23f3604cb1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426286 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com> Auto-Submit: Bob Nystrom <rnystrom@google.com>
217 lines
6.2 KiB
Dart
217 lines
6.2 KiB
Dart
// 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 'dart:ffi';
|
|
|
|
final repoRoot = File.fromUri(Platform.script).parent.parent.parent.path;
|
|
final runtimeRoot = '$repoRoot/runtime';
|
|
final buildtoolsRoot = '$repoRoot/buildtools';
|
|
final clangBinDir =
|
|
'$buildtoolsRoot/$currentPlatformBuildtoolsSubdir/clang/bin';
|
|
final clangFormatBin = '$clangBinDir/clang-format';
|
|
|
|
final currentPlatformBuildtoolsSubdir = switch (Abi.current()) {
|
|
Abi.macosX64 => 'mac-x64',
|
|
Abi.macosArm64 => 'mac-arm64',
|
|
Abi.linuxX64 => 'linux-x64',
|
|
Abi.linuxArm64 => 'linux-arm64',
|
|
Abi.windowsX64 => 'win-x64',
|
|
Abi.windowsArm64 => 'win-arm64',
|
|
_ => throw UnimplementedError(),
|
|
};
|
|
|
|
void main(List<String> args) {
|
|
final checkUpToDate = args.contains('--check-up-to-date');
|
|
|
|
final dartApiHFile = File('$runtimeRoot/include/dart_api.h');
|
|
final dartNativeApiHFile = File('$runtimeRoot/include/dart_native_api.h');
|
|
final dartApiWinCFile = File('$runtimeRoot/bin/dart_api_win.c');
|
|
final dartApiWinCTmpFile = File('$runtimeRoot/bin/dart_api_win_tmp.c');
|
|
final dartApiHContents = dartApiHFile.readAsStringSync();
|
|
final dartNativeApiHContents = dartNativeApiHFile.readAsStringSync();
|
|
|
|
final procedureRegexp = RegExp(
|
|
r'(DART_\w+\s+)+(?<returnType>[\w\s\*]+)\s+(?<name>\w+)\((?<arguments>[^)]*)\);',
|
|
multiLine: true,
|
|
);
|
|
|
|
final matches = [
|
|
...procedureRegexp.allMatches(dartApiHContents),
|
|
...procedureRegexp.allMatches(dartNativeApiHContents),
|
|
];
|
|
|
|
final procedures = <Procedure>[];
|
|
|
|
for (final match in matches) {
|
|
final returnType = match.namedGroup('returnType')!;
|
|
final name = match.namedGroup('name')!;
|
|
final argumentsString = match.namedGroup('arguments') ?? '';
|
|
final argumentList = argumentsString
|
|
.split(',')
|
|
.where((arg) => arg != 'void')
|
|
.map((arg) {
|
|
final parts = arg.trim().split(' ');
|
|
return (
|
|
type: parts.sublist(0, parts.length - 1).join(' '),
|
|
name: parts[parts.length - 1],
|
|
);
|
|
})
|
|
.toList();
|
|
procedures.add((
|
|
name: name,
|
|
returnType: returnType,
|
|
arguments: argumentList,
|
|
));
|
|
}
|
|
|
|
final buffer = StringBuffer();
|
|
|
|
buffer.writeln('''
|
|
// 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.
|
|
|
|
// DO NOT EDIT. This file is generated by runtime/tools/generate_dart_api_win_c.dart.
|
|
|
|
#include <windows.h>
|
|
|
|
#include <include/dart_api.h>
|
|
#include <include/dart_native_api.h>
|
|
|
|
''');
|
|
|
|
// Generate typedefs for all procedures.
|
|
for (final procedure in procedures) {
|
|
buffer.write('typedef ');
|
|
buffer.write(procedure.returnType);
|
|
buffer.write(' (*');
|
|
buffer.write(procedure.typedefName);
|
|
buffer.write(')(');
|
|
for (final (i, argument) in procedure.arguments.indexed) {
|
|
buffer.write(argument.type);
|
|
if (i < procedure.arguments.length - 1) {
|
|
buffer.write(', ');
|
|
}
|
|
}
|
|
buffer.writeln(');');
|
|
}
|
|
|
|
buffer.writeln();
|
|
|
|
// Generate function pointers for all procedures.
|
|
for (final procedure in procedures) {
|
|
buffer.write('static ');
|
|
buffer.write(procedure.typedefName);
|
|
buffer.write(' ');
|
|
buffer.write(procedure.functionPointerName);
|
|
buffer.writeln(' = NULL;');
|
|
}
|
|
|
|
buffer.writeln();
|
|
|
|
// Generate the DllMain function that initializes all function pointers.
|
|
buffer.writeln('''
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
|
|
if (fdwReason == DLL_PROCESS_ATTACH) {
|
|
HMODULE process = GetModuleHandle(NULL);
|
|
''');
|
|
|
|
for (final procedure in procedures) {
|
|
buffer.write(' ');
|
|
buffer.write(procedure.functionPointerName);
|
|
buffer.write(' = (');
|
|
buffer.write(procedure.typedefName);
|
|
buffer.write(') GetProcAddress(process, "');
|
|
buffer.write(procedure.name);
|
|
buffer.writeln('");');
|
|
}
|
|
|
|
buffer.writeln('''
|
|
}
|
|
|
|
return TRUE;
|
|
}''');
|
|
|
|
buffer.writeln();
|
|
|
|
// Generate redirecting implementations for all procedures.
|
|
for (final procedure in procedures) {
|
|
final (:name, :returnType, :arguments) = procedure;
|
|
buffer.write(returnType);
|
|
buffer.write(' ');
|
|
buffer.write(name);
|
|
buffer.write('(');
|
|
for (final (i, (:name, :type)) in arguments.indexed) {
|
|
buffer.write(type);
|
|
buffer.write(' ');
|
|
buffer.write(name);
|
|
if (i < arguments.length - 1) {
|
|
buffer.write(', ');
|
|
}
|
|
}
|
|
buffer.writeln(') {');
|
|
buffer.write(' ');
|
|
if (procedure.returnType != 'void') {
|
|
buffer.write('return ');
|
|
}
|
|
buffer.write(procedure.functionPointerName);
|
|
buffer.write('(');
|
|
for (final (i, argument) in arguments.indexed) {
|
|
buffer.write(argument.name);
|
|
if (i < arguments.length - 1) {
|
|
buffer.write(', ');
|
|
}
|
|
}
|
|
buffer.writeln(');');
|
|
buffer.writeln('}');
|
|
buffer.writeln();
|
|
}
|
|
|
|
buffer.writeln();
|
|
|
|
dartApiWinCTmpFile.writeAsStringSync(buffer.toString());
|
|
|
|
try {
|
|
// Run clang-format on the generated file.
|
|
final clangFormatResult = Process.runSync(
|
|
clangFormatBin,
|
|
['-i', dartApiWinCTmpFile.path],
|
|
// Allows us to specify the path to the clang-format binary without the
|
|
// .exe extension on Windows.
|
|
runInShell: Platform.isWindows,
|
|
);
|
|
if (clangFormatResult.exitCode != 0) {
|
|
print(clangFormatResult.stdout);
|
|
print(clangFormatResult.stderr);
|
|
exitCode = 1;
|
|
} else {
|
|
final changed =
|
|
!dartApiWinCFile.existsSync() ||
|
|
dartApiWinCTmpFile.readAsStringSync() !=
|
|
dartApiWinCFile.readAsStringSync();
|
|
if (changed) {
|
|
if (checkUpToDate) {
|
|
exitCode = 1;
|
|
} else {
|
|
dartApiWinCTmpFile.copySync(dartApiWinCFile.path);
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
dartApiWinCTmpFile.deleteSync();
|
|
}
|
|
}
|
|
|
|
typedef Procedure = ({
|
|
String name,
|
|
String returnType,
|
|
List<({String name, String type})> arguments,
|
|
});
|
|
|
|
extension on Procedure {
|
|
String get typedefName => '${name}Type';
|
|
String get functionPointerName => '${name}Fn';
|
|
}
|