blob: 8e74d878dd927bdcdfdf0aa6b6f1a75c4bb791ac [file] [log] [blame]
// Copyright (c) 2022, 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:async';
import 'dart:io';
Future<void> _buildLib(String input, String output) async {
final args = [
'-shared',
'-fpic',
'-x',
'objective-c',
input,
'-framework',
'Foundation',
'-o',
output,
];
final process = await Process.start('clang', args);
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
final result = await process.exitCode;
if (result != 0) {
throw ProcessException('clang', args, 'Build failed', result);
}
print('Generated file: $output');
}
Future<void> _buildSwift(
String input, String outputHeader, String outputLib) async {
final args = [
'-c',
input,
'-emit-objc-header-path',
outputHeader,
'-emit-library',
'-o',
outputLib,
];
final process = await Process.start('swiftc', args);
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
final result = await process.exitCode;
if (result != 0) {
throw ProcessException('swiftc', args, 'Build failed', result);
}
print('Generated files: $outputHeader and $outputLib');
}
Future<void> _generateBindings(String config) async {
final args = [
'run',
'ffigen',
'--config',
'test/native_objc_test/$config',
];
final process =
await Process.start(Platform.executable, args, workingDirectory: '../..');
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
final result = await process.exitCode;
if (result != 0) {
throw ProcessException('dart', args, 'Generating bindings', result);
}
print('Generated bindings for: $config');
}
List<String> _getTestNames() {
const configSuffix = '_config.yaml';
final names = <String>[];
for (final entity in Directory.current.listSync()) {
final filename = entity.uri.pathSegments.last;
if (filename.endsWith(configSuffix)) {
names.add(filename.substring(0, filename.length - configSuffix.length));
}
}
return names;
}
Future<void> build(List<String> testNames) async {
print('Building Dynamic Library for Objective C Native Tests...');
for (final name in testNames) {
final mFile = '${name}_test.m';
if (await File(mFile).exists()) {
await _buildLib(mFile, '${name}_test.dylib');
}
}
print('Building Dynamic Library and Header for Swift Tests...');
for (final name in testNames) {
final swiftFile = '${name}_test.swift';
if (await File(swiftFile).exists()) {
await _buildSwift(
swiftFile, '${name}_test-Swift.h', '${name}_test.dylib');
}
}
print('Generating Bindings for Objective C Native Tests...');
for (final name in testNames) {
await _generateBindings('${name}_config.yaml');
}
}
Future<void> clean(List<String> testNames) async {
print('Deleting generated and built files...');
final filenames = [
for (final name in testNames) ...[
'${name}_bindings.dart',
'${name}_test_bindings.dart',
'${name}_test.dylib'
],
];
Future.wait(filenames.map((fileName) async {
final file = File(fileName);
final exists = await file.exists();
if (exists) await file.delete();
}));
}
Future<void> main(List<String> arguments) async {
// Allow running this script directly from any path (or an IDE).
Directory.current = Platform.script.resolve('.').toFilePath();
if (!Platform.isMacOS) {
throw OSError('Objective C tests are only supported on MacOS');
}
if (arguments.isNotEmpty && arguments[0] == 'clean') {
return await clean(_getTestNames());
}
return await build(arguments.isNotEmpty ? arguments : _getTestNames());
}