Skip to content

[infra] Prepare to add ffigen, objective_c, swift2objc, and swiftgen to the workspace #2330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jun 3, 2025
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
4 changes: 3 additions & 1 deletion .github/workflows/ffigen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ jobs:
brew: clang-format
- name: Build test dylib and bindings
run: dart test/setup.dart
- name: Install coverage
run: dart pub global activate coverage
- name: Run VM tests and collect coverage
run: dart run coverage:test_with_coverage --scope-output=ffigen --scope-output=objective_c
run: dart pub global run coverage:test_with_coverage --scope-output=ffigen --scope-output=objective_c
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the objective_c and ffigen workflows be merged into one? (Can be done in a separate PR.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably. I'll look into it

- name: Generate package:jni bindings
run: dart run tool/generate_ffi_bindings.dart
working-directory: pkgs/jni/
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/objective_c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ jobs:
- name: Build test dylib
# TODO(https://github.com/dart-lang/native/issues/1068): Remove this.
run: dart test/setup.dart
- name: Install coverage
run: dart pub global activate coverage
- name: Run VM tests and collect coverage
run: dart run coverage:test_with_coverage --scope-output=ffigen --scope-output=objective_c
run: dart pub global run coverage:test_with_coverage --scope-output=ffigen --scope-output=objective_c
- name: Verify generated code is up to date
# test/generate_code_test.dart runs the code generator, so if there are
# any git-diffs at this point, it means the generated code is outdated.
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/swift2objc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ jobs:
sdk: stable
- name: Install dependencies
run: dart pub get
- name: Install coverage
run: dart pub global activate coverage
- name: Run VM tests and collect coverage
run: dart run coverage:test_with_coverage --scope-output=swift2objc
run: dart pub global run coverage:test_with_coverage --scope-output=swift2objc
- name: Upload coverage
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b
with:
Expand Down
4 changes: 2 additions & 2 deletions pkgs/ffigen/lib/src/config_provider/config_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ class ConfigValue<TE> {
) {
ConfigValue<RE> returnValue;
if (transform != null) {
returnValue = this.withValue(transform.call(this), rawValue);
returnValue = withValue(transform.call(this), rawValue);
} else {
returnValue = this.withValue(this.value as RE, rawValue);
returnValue = withValue(value as RE, rawValue);
}
resultCallback?.call(returnValue);
return returnValue;
Expand Down
52 changes: 51 additions & 1 deletion pkgs/ffigen/lib/src/config_provider/overrideable_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,58 @@ final libclangOverridePaths = const <String>[];
/// Returns the root path of the package, for use during tests.
///
/// Note that `dart test` sets the current directory to the package root.
final packagePathForTests = p.current;
final packagePathForTests = _findPackageRoot('ffigen').toFilePath();

/// Returns a path to a config yaml in a unit test.
String configPathForTest(String directory, String file) =>
p.join(directory, file);

/// Test files are run in a variety of ways, find this package root in all.
///
/// Test files can be run from source from any working directory. The Dart SDK
/// `tools/test.py` runs them from the root of the SDK for example.
///
/// Test files can be run from dill from the root of package. `package:test`
/// does this.
///
/// https://github.com/dart-lang/test/issues/110
Uri _findPackageRoot(String packageName) {
final script = Platform.script;
final fileName = script.name;
if (fileName.endsWith('.dart')) {
// We're likely running from source in the package somewhere.
var directory = script.resolve('.');
while (true) {
final dirName = directory.name;
if (dirName == packageName) {
return directory;
}
final parent = directory.resolve('..');
if (parent == directory) break;
directory = parent;
}
} else if (fileName.endsWith('.dill')) {
// Probably from the package root.
final cwd = Directory.current.uri;
final dirName = cwd.name;
if (dirName == packageName) {
return cwd;
}
}
// Or the workspace root.
final cwd = Directory.current.uri;
final candidate = cwd.resolve('pkgs/$packageName/');
if (Directory.fromUri(candidate).existsSync()) {
return candidate;
}
throw StateError(
"Could not find package root for package '$packageName'. "
'Tried finding the package root via Platform.script '
"'${Platform.script.toFilePath()}' and Directory.current "
"'${Directory.current.uri.toFilePath()}'.",
);
}

extension on Uri {
String get name => pathSegments.where((e) => e != '').last;
}
3 changes: 1 addition & 2 deletions pkgs/ffigen/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ dependencies:

dev_dependencies:
async: ^2.11.0
coverage: ^1.11.0
dart_flutter_team_lints: ^2.0.0
json_schema: ^5.1.1
leak_tracker: ^10.0.7
objective_c: ^7.2.0
objective_c: ^8.0.0
test: ^1.16.2

dependency_overrides:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:ffigen/src/config_provider.dart';
import 'package:ffigen/src/header_parser.dart' as parser;
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

import '../test_utils.dart';
Expand All @@ -18,7 +19,12 @@ void main() {
final library = parser.parse(Config(
output: Uri.file('unused'),
entryPoints: [
Uri.file('test/collision_tests/reserved_keyword_collision.h')
Uri.file(path.join(
packagePathForTests,
'test',
'collision_tests',
'reserved_keyword_collision.h',
))
],
structDecl: DeclarationFilters.includeAll,
unionDecl: DeclarationFilters.includeAll,
Expand Down
16 changes: 10 additions & 6 deletions pkgs/ffigen/test/config_tests/json_schema_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import 'package:ffigen/src/strings.dart' as strings;
import 'package:file/local.dart';
import 'package:glob/glob.dart';
import 'package:json_schema/json_schema.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';

import '../test_utils.dart';

void main() {
group('json_schema_test', () {
final schema = YamlConfig.getsRootConfigSpec()
Expand All @@ -24,9 +27,10 @@ void main() {
YamlConfig.getsRootConfigSpec()
.generateJsonSchema(strings.ffigenJsonSchemaId),
);
final expectedJsonSchema = File(strings.ffigenJsonSchemaFileName)
.readAsStringSync()
.replaceAll('\r\n', '\n');
final expectedJsonSchema = File(path.join(
packagePathForTests,
strings.ffigenJsonSchemaFileName,
)).readAsStringSync().replaceAll('\r\n', '\n');
expect(actualJsonSchema, expectedJsonSchema);
});

Expand All @@ -37,16 +41,16 @@ void main() {

// Find all ffigen config files in the repo.
final configYamlGlob = Glob('**config.yaml');
final configYamlFiles =
configYamlGlob.listFileSystemSync(const LocalFileSystem());
final configYamlFiles = configYamlGlob
.listFileSystemSync(const LocalFileSystem(), root: packagePathForTests);
test('$configYamlGlob files not empty', () {
expect(configYamlFiles.isNotEmpty, true);
});

final sharedBindingsConfigYamlGlob =
Glob('example/shared_bindings/ffigen_configs/**.yaml');
final sharedBindingsConfigYamlFiles = sharedBindingsConfigYamlGlob
.listFileSystemSync(const LocalFileSystem());
.listFileSystemSync(const LocalFileSystem(), root: packagePathForTests);
test('$sharedBindingsConfigYamlGlob files not emty', () {
expect(sharedBindingsConfigYamlFiles.isNotEmpty, true);
});
Expand Down
8 changes: 6 additions & 2 deletions pkgs/ffigen/test/example_tests/cjson_example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ void main() {
logWarnings(Level.SEVERE);
});
test('c_json', () {
final config =
testConfigFromPath(path.join('example', 'c_json', 'config.yaml'));
final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'c_json',
'config.yaml',
));
final library = parse(config);

matchLibraryWithExpected(
Expand Down
8 changes: 6 additions & 2 deletions pkgs/ffigen/test/example_tests/ffinative_example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ void main() {
});

test('ffinative', () {
final config =
testConfigFromPath(path.join('example', 'ffinative', 'config.yaml'));
final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'ffinative',
'config.yaml',
));
final library = parse(config);

matchLibraryWithExpected(
Expand Down
9 changes: 6 additions & 3 deletions pkgs/ffigen/test/example_tests/libclang_example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ void main() {
logWarnings(Level.SEVERE);
});
test('libclang-example', () {
final configYaml =
File(path.join('example', 'libclang-example', 'config.yaml'))
.absolute;
final configYaml = File(path.join(
packagePathForTests,
'example',
'libclang-example',
'config.yaml',
)).absolute;
late Config config;
late Library library;
withChDir(configYaml.path, () {
Expand Down
8 changes: 6 additions & 2 deletions pkgs/ffigen/test/example_tests/objective_c_example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ void main() {
});

test('objective_c', () {
final config = testConfigFromPath(
path.join('example', 'objective_c', 'config.yaml'));
final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'objective_c',
'config.yaml',
));
final output = parse(config).generate();

// Verify that the output contains all the methods and classes that the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void main() {

test('a_shared_base bindings', () {
final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'shared_bindings',
'ffigen_configs',
Expand All @@ -33,6 +34,7 @@ void main() {

test('base symbol file output', () {
final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'shared_bindings',
'ffigen_configs',
Expand Down
1 change: 1 addition & 0 deletions pkgs/ffigen/test/example_tests/simple_example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ void main() {

test('simple', () {
final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'simple',
'config.yaml',
Expand Down
3 changes: 2 additions & 1 deletion pkgs/ffigen/test/example_tests/swift_example_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ void main() {
'-o',
'libswiftapi.dylib',
],
workingDirectory: path.join(Directory.current.path, 'example/swift'));
workingDirectory: path.join(packagePathForTests, 'example/swift'));
unawaited(stdout.addStream(process.stdout));
unawaited(stderr.addStream(process.stderr));
final result = await process.exitCode;
expect(result, 0);

final config = testConfigFromPath(path.join(
packagePathForTests,
'example',
'swift',
'config.yaml',
Expand Down
7 changes: 6 additions & 1 deletion pkgs/ffigen/test/header_parser_tests/globals_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ void main() {
expected = expectedLibrary();
actual = parser.parse(
testConfigFromPath(configPath(
path.join('test', 'header_parser_tests'), 'globals_config.yaml')),
path.join(
packagePathForTests,
'test',
'header_parser_tests',
),
'globals_config.yaml')),
);
});

Expand Down
7 changes: 6 additions & 1 deletion pkgs/ffigen/test/header_parser_tests/macros_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ void main() {
expected = expectedLibrary();
actual = parser.parse(
testConfigFromPath(configPath(
path.join('test', 'header_parser_tests'), 'macros_config.yaml')),
path.join(
packagePathForTests,
'test',
'header_parser_tests',
),
'macros_config.yaml')),
);
});
test('Total bindings count', () {
Expand Down
10 changes: 9 additions & 1 deletion pkgs/ffigen/test/header_parser_tests/sort_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:ffigen/src/code_generator.dart';
import 'package:ffigen/src/config_provider.dart';
import 'package:ffigen/src/header_parser.dart' as parser;
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

import '../test_utils.dart';
Expand All @@ -17,7 +18,14 @@ void main() {
logWarnings();
actual = parser.parse(Config(
output: Uri.file('unused'),
entryPoints: [Uri.file('test/header_parser_tests/sort.h')],
entryPoints: [
Uri.file(path.join(
packagePathForTests,
'test',
'header_parser_tests',
'sort.h',
))
],
structDecl: DeclarationFilters.includeAll,
unionDecl: DeclarationFilters.includeAll,
typedefs: DeclarationFilters.includeAll,
Expand Down
26 changes: 23 additions & 3 deletions pkgs/ffigen/test/large_integration_tests/large_objc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import 'package:ffigen/ffigen.dart';
import 'package:ffigen/src/code_generator/utils.dart';
import 'package:ffigen/src/config_provider/config_types.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as path;
import 'package:pub_semver/pub_semver.dart';
import 'package:test/test.dart';

import '../test_utils.dart';

Future<int> run(String exe, List<String> args) async {
final process =
await Process.start(exe, args, mode: ProcessStartMode.inheritStdio);
Expand All @@ -41,14 +44,31 @@ void main() {
randInclude('$kind.memb', clazz, method),
);

const outFile = 'test/large_integration_tests/large_objc_bindings.dart';
const outObjCFile = 'test/large_integration_tests/large_objc_bindings.m';
final outFile = path.join(
packagePathForTests,
'test',
'large_integration_tests',
'large_objc_bindings.dart',
);
final outObjCFile = path.join(
packagePathForTests,
'test',
'large_integration_tests',
'large_objc_bindings.m',
);
final config = Config(
wrapperName: 'LargeObjCLibrary',
language: Language.objc,
output: Uri.file(outFile),
outputObjC: Uri.file(outObjCFile),
entryPoints: [Uri.file('test/large_integration_tests/large_objc_test.h')],
entryPoints: [
Uri.file(path.join(
packagePathForTests,
'test',
'large_integration_tests',
'large_objc_test.h',
))
],
formatOutput: false,
includeTransitiveObjCInterfaces: false,
includeTransitiveObjCProtocols: false,
Expand Down
Loading
Loading