From d95ca04519179d0efe9f2b245db02388abcdb8fb Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 10:49:17 +0800 Subject: [PATCH 1/7] rename ffi-native 'asset' to 'assetId' and add tests --- README.md | 2 +- example/ffinative/config.yaml | 2 +- example/ffinative/generated_bindings.dart | 14 +- ffigen.schema.json | 4 +- lib/src/code_generator/func.dart | 4 +- lib/src/config_provider/config_types.dart | 4 +- lib/src/config_provider/spec_utils.dart | 2 +- lib/src/strings.dart | 2 +- test/ffi_native_test/.gitignore | 3 + .../_expected_ffi_native_test_bindings.dart | 122 ++++++++++++++ test/ffi_native_test/build_test_dylib.dart | 129 +++++++++++++++ test/ffi_native_test/config.yaml | 23 +++ test/ffi_native_test/ffi_native_test.dart | 153 ++++++++++++++++++ test/ffi_native_test/native_test.c | 74 +++++++++ test/ffi_native_test/native_test.def | 20 +++ test/regen.dart | 2 + 16 files changed, 545 insertions(+), 15 deletions(-) create mode 100644 test/ffi_native_test/.gitignore create mode 100644 test/ffi_native_test/_expected_ffi_native_test_bindings.dart create mode 100644 test/ffi_native_test/build_test_dylib.dart create mode 100644 test/ffi_native_test/config.yaml create mode 100644 test/ffi_native_test/ffi_native_test.dart create mode 100644 test/ffi_native_test/native_test.c create mode 100644 test/ffi_native_test/native_test.def diff --git a/README.md b/README.md index 61464fde..3f2d0d8b 100644 --- a/README.md +++ b/README.md @@ -543,7 +543,7 @@ type-map: ```yaml ffi-native: - asset: 'myasset' # Optional. + assetId: 'myasset' # Optional. ``` diff --git a/example/ffinative/config.yaml b/example/ffinative/config.yaml index 397dbba8..283794a9 100644 --- a/example/ffinative/config.yaml +++ b/example/ffinative/config.yaml @@ -2,7 +2,7 @@ name: NativeLibrary ffi-native: - # asset: 'assetname' # (optional) + assetId: 'assetname' # (optional) description: Bindings to `headers/example.h`. output: 'generated_bindings.dart' headers: diff --git a/example/ffinative/generated_bindings.dart b/example/ffinative/generated_bindings.dart index 389620d8..bbefd052 100644 --- a/example/ffinative/generated_bindings.dart +++ b/example/ffinative/generated_bindings.dart @@ -7,28 +7,32 @@ import 'dart:ffi' as ffi; /// Adds 2 integers. -@ffi.Native(symbol: 'sum') +@ffi.Native( + symbol: 'sum', assetId: 'assetname') external int sum( int a, int b, ); /// Subtracts 2 integers. -@ffi.Native(symbol: 'subtract') +@ffi.Native( + symbol: 'subtract', assetId: 'assetname') external int subtract( int a, int b, ); /// Multiplies 2 integers, returns pointer to an integer,. -@ffi.Native Function(ffi.Int, ffi.Int)>(symbol: 'multiply') +@ffi.Native Function(ffi.Int, ffi.Int)>( + symbol: 'multiply', assetId: 'assetname') external ffi.Pointer multiply( int a, int b, ); /// Divides 2 integers, returns pointer to a float. -@ffi.Native Function(ffi.Int, ffi.Int)>(symbol: 'divide') +@ffi.Native Function(ffi.Int, ffi.Int)>( + symbol: 'divide', assetId: 'assetname') external ffi.Pointer divide( int a, int b, @@ -36,7 +40,7 @@ external ffi.Pointer divide( /// Divides 2 floats, returns a pointer to double. @ffi.Native Function(ffi.Float, ffi.Float)>( - symbol: 'dividePrecision') + symbol: 'dividePrecision', assetId: 'assetname') external ffi.Pointer dividePrecision( double a, double b, diff --git a/ffigen.schema.json b/ffigen.schema.json index a557a87c..5c196f1f 100644 --- a/ffigen.schema.json +++ b/ffigen.schema.json @@ -418,12 +418,12 @@ "type": "object", "additionalProperties": false, "properties": { - "asset": { + "assetId": { "type": "string" } }, "required": [ - "asset" + "assetId" ] } ] diff --git a/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart index 5e081cf7..cbdebe7e 100644 --- a/lib/src/code_generator/func.dart +++ b/lib/src/code_generator/func.dart @@ -111,8 +111,8 @@ class Func extends LookUpBinding { functionType.getFfiDartType(w, writeArgumentNames: false); if (ffiNativeConfig.enabled) { - final assetString = ffiNativeConfig.asset != null - ? ", asset: '${ffiNativeConfig.asset}'" + final assetString = ffiNativeConfig.assetId != null + ? ", assetId: '${ffiNativeConfig.assetId}'" : ''; final isLeafString = isLeaf ? ', isLeaf: true' : ''; s.write( diff --git a/lib/src/config_provider/config_types.dart b/lib/src/config_provider/config_types.dart index 75d5fcae..a4cf1426 100644 --- a/lib/src/config_provider/config_types.dart +++ b/lib/src/config_provider/config_types.dart @@ -384,9 +384,9 @@ class ObjCModulePrefixer { class FfiNativeConfig { final bool enabled; - final String? asset; + final String? assetId; - const FfiNativeConfig({required this.enabled, this.asset}); + const FfiNativeConfig({required this.enabled, this.assetId}); } class SymbolFile { diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart index ff4e1b76..86a4bc5a 100644 --- a/lib/src/config_provider/spec_utils.dart +++ b/lib/src/config_provider/spec_utils.dart @@ -602,6 +602,6 @@ FfiNativeConfig ffiNativeExtractor(dynamic yamlConfig) { final yamlMap = yamlConfig as Map?; return FfiNativeConfig( enabled: true, - asset: yamlMap?[strings.ffiNativeAsset] as String?, + assetId: yamlMap?[strings.ffiNativeAsset] as String?, ); } diff --git a/lib/src/strings.dart b/lib/src/strings.dart index 7613289a..0918f48e 100644 --- a/lib/src/strings.dart +++ b/lib/src/strings.dart @@ -263,7 +263,7 @@ const doubleNaN = 'double.nan'; const dartHandleUsr = 'c:@S@_Dart_Handle'; const ffiNative = 'ffi-native'; -const ffiNativeAsset = 'asset'; +const ffiNativeAsset = 'assetId'; Directory? _tmpDir; diff --git a/test/ffi_native_test/.gitignore b/test/ffi_native_test/.gitignore new file mode 100644 index 00000000..d97e2fcb --- /dev/null +++ b/test/ffi_native_test/.gitignore @@ -0,0 +1,3 @@ +# Ignore files generated by clang on windows. +native_test.exp +native_test.lib diff --git a/test/ffi_native_test/_expected_ffi_native_test_bindings.dart b/test/ffi_native_test/_expected_ffi_native_test_bindings.dart new file mode 100644 index 00000000..a623df6e --- /dev/null +++ b/test/ffi_native_test/_expected_ffi_native_test_bindings.dart @@ -0,0 +1,122 @@ +// ignore_for_file: camel_case_types, non_constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint +import 'dart:ffi' as ffi; + +@ffi.Native( + symbol: 'Function1Bool', assetId: 'native_test') +external bool Function1Bool( + bool x, +); + +@ffi.Native( + symbol: 'Function1Uint8', assetId: 'native_test') +external int Function1Uint8( + int x, +); + +@ffi.Native( + symbol: 'Function1Uint16', assetId: 'native_test') +external int Function1Uint16( + int x, +); + +@ffi.Native( + symbol: 'Function1Uint32', assetId: 'native_test') +external int Function1Uint32( + int x, +); + +@ffi.Native( + symbol: 'Function1Uint64', assetId: 'native_test') +external int Function1Uint64( + int x, +); + +@ffi.Native( + symbol: 'Function1Int8', assetId: 'native_test') +external int Function1Int8( + int x, +); + +@ffi.Native( + symbol: 'Function1Int16', assetId: 'native_test') +external int Function1Int16( + int x, +); + +@ffi.Native( + symbol: 'Function1Int32', assetId: 'native_test') +external int Function1Int32( + int x, +); + +@ffi.Native( + symbol: 'Function1Int64', assetId: 'native_test') +external int Function1Int64( + int x, +); + +@ffi.Native( + symbol: 'Function1IntPtr', assetId: 'native_test') +external int Function1IntPtr( + int x, +); + +@ffi.Native( + symbol: 'Function1UintPtr', assetId: 'native_test') +external int Function1UintPtr( + int x, +); + +@ffi.Native( + symbol: 'Function1Float', assetId: 'native_test') +external double Function1Float( + double x, +); + +@ffi.Native( + symbol: 'Function1Double', assetId: 'native_test') +external double Function1Double( + double x, +); + +@ffi.Native Function()>( + symbol: 'getStruct1', assetId: 'native_test') +external ffi.Pointer getStruct1(); + +@ffi.Native( + symbol: 'Function1StructReturnByValue', assetId: 'native_test') +external Struct3 Function1StructReturnByValue( + int a, + int b, + int c, +); + +@ffi.Native( + symbol: 'Function1StructPassByValue', assetId: 'native_test') +external int Function1StructPassByValue( + Struct3 sum_a_b_c, +); + +final class Struct1 extends ffi.Struct { + @ffi.Int8() + external int a; + + @ffi.Array.multi([3, 1, 2]) + external ffi.Array>> data; +} + +final class Struct3 extends ffi.Struct { + @ffi.Int() + external int a; + + @ffi.Int() + external int b; + + @ffi.Int() + external int c; +} diff --git a/test/ffi_native_test/build_test_dylib.dart b/test/ffi_native_test/build_test_dylib.dart new file mode 100644 index 00000000..a41f6863 --- /dev/null +++ b/test/ffi_native_test/build_test_dylib.dart @@ -0,0 +1,129 @@ +// Copyright (c) 2020, 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. + +/// ======================================================================= +/// ==== Script to generate dynamic library for native_function_tests ===== +/// ======================================================================= +/// This Script effectively calls the following (but user can provide +/// command line args which will replace the defaults shown below)- +/// +/// Linux: +/// ``` +/// clang -shared -fpic native_test.c -o native_test.so +/// ``` +/// MacOS: +/// ``` +/// clang -shared -fpic native_test.c -o native_test.dylib +/// ``` +/// Windows: +/// ``` +/// call clang -shared native_test.c -o native_test.dll -Wl,"/DEF:native_test.def" +/// del native_test.exp +/// del native_test.lib +/// ``` +/// ======================================================================= +/// ======================================================================= +/// ======================================================================= + +import 'dart:io'; + +const macOS = 'macos'; +const windows = 'windows'; +const linux = 'linux'; + +Map platformOptions = { + linux: Options( + outputfilename: 'native_test.so', + sharedFlag: '-shared', + inputHeader: 'native_test.c', + fPIC: '-fpic', + ), + windows: Options( + outputfilename: 'native_test.dll', + sharedFlag: '-shared', + inputHeader: 'native_test.c', + moduleDefPath: '-Wl,/DEF:native_test.def', + ), + macOS: Options( + outputfilename: 'native_test.dylib', + sharedFlag: '-shared', + inputHeader: 'native_test.c', + fPIC: '-fpic', + ), +}; + +void main(List arguments) { + print('Building Dynamic Library for Native Tests... '); + final options = getPlatformOptions()!; + + // Run clang compiler to generate the dynamic library. + final processResult = runClangProcess(options); + printSuccess(processResult, options); +} + +/// Calls the clang compiler. +ProcessResult runClangProcess(Options options) { + final result = Process.runSync( + 'clang', + [ + options.sharedFlag, + options.fPIC, + options.inputHeader, + '-o', + options.outputfilename, + options.moduleDefPath, + '-Wno-nullability-completeness', + ], + ); + return result; +} + +/// Prints success message (or process error if any). +void printSuccess(ProcessResult result, Options options) { + print(result.stdout); + if ((result.stderr as String).isEmpty) { + print('Generated file: ${options.outputfilename}'); + } else { + print(result.stderr); + } +} + +/// Get options based on current platform. +Options? getPlatformOptions() { + if (Platform.isMacOS) { + return platformOptions[macOS]; + } else if (Platform.isWindows) { + return platformOptions[windows]; + } else if (Platform.isLinux) { + return platformOptions[linux]; + } else { + throw Exception('Unknown Platform.'); + } +} + +/// Hold options which would be passed to clang. +class Options { + /// Name of dynamic library to generate. + final String outputfilename; + + /// Tells compiler to generate a shared library. + final String sharedFlag; + + /// Flag for generating Position Independant Code (Not used on windows). + final String fPIC; + + /// Input file. + final String inputHeader; + + /// Path to `.def` file containing symbols to export, windows use only. + final String moduleDefPath; + + Options({ + required this.outputfilename, + required this.sharedFlag, + required this.inputHeader, + this.fPIC = '', + this.moduleDefPath = '', + }); +} diff --git a/test/ffi_native_test/config.yaml b/test/ffi_native_test/config.yaml new file mode 100644 index 00000000..f9546031 --- /dev/null +++ b/test/ffi_native_test/config.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2020, 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. + +# =================== GENERATING TEST BINDINGS ================== +# dart run ffigen --config test/native_test/config.yaml +# =============================================================== + +name: FfiNative +description: 'ffi-native tests.' +output: '_expected_ffi_native_test_bindings.dart' +headers: + entry-points: + - 'native_test.c' + include-directives: + - '**native_test.c' +ffi-native: + assetId: "native_test" + +compiler-opts: '-Wno-nullability-completeness' +preamble: | + // ignore_for_file: camel_case_types, non_constant_identifier_names + diff --git a/test/ffi_native_test/ffi_native_test.dart b/test/ffi_native_test/ffi_native_test.dart new file mode 100644 index 00000000..aaf336c1 --- /dev/null +++ b/test/ffi_native_test/ffi_native_test.dart @@ -0,0 +1,153 @@ +// Copyright (c) 2020, 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:ffi'; +import 'dart:io'; +import 'dart:math'; + +import 'package:ffigen/ffigen.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; +import '../test_utils.dart'; +import '_expected_ffi_native_test_bindings.dart' as bindings; + +void main() { + group('native_test', () { + setUpAll(() { + logWarnings(); + var dylibName = 'test/ffi_native_test/native_test.so'; + if (Platform.isMacOS) { + dylibName = 'test/ffi_native_test/native_test.dylib'; + } else if (Platform.isWindows) { + dylibName = r'test\ffi_native_test\native_test.dll'; + } + final dylib = File(dylibName); + verifySetupFile(dylib); + DynamicLibrary.open(dylib.absolute.path); + }); + + test('generate_bindings', () { + final configFile = + File(path.join('test', 'ffi_native_test', 'config.yaml')).absolute; + final outFile = File( + path.join('test', 'debug_generated', + '_expected_ffi_native_test_bindings.dart'), + ).absolute; + + late Config config; + withChDir(configFile.path, () { + config = testConfigFromPath(configFile.path); + }); + final library = parse(config); + + library.generateFile(outFile); + + try { + final actual = outFile.readAsStringSync().replaceAll('\r', ''); + final expected = File(path.join(config.output)) + .readAsStringSync() + .replaceAll('\r', ''); + expect(actual, expected); + if (outFile.existsSync()) { + outFile.delete(); + } + } catch (e) { + print('Failed test: Debug generated file: ${outFile.absolute.path}'); + rethrow; + } + }); + test('bool', () { + expect(bindings.Function1Bool(true), false); + expect(bindings.Function1Bool(false), true); + }); + test('uint8_t', () { + expect(bindings.Function1Uint8(pow(2, 8).toInt()), 42); + }); + test('uint16_t', () { + expect(bindings.Function1Uint16(pow(2, 16).toInt()), 42); + }); + test('uint32_t', () { + expect(bindings.Function1Uint32(pow(2, 32).toInt()), 42); + }); + test('uint64_t', () { + expect(bindings.Function1Uint64(pow(2, 64).toInt()), 42); + }); + test('int8_t', () { + expect( + bindings.Function1Int8(pow(2, 7).toInt()), -pow(2, 7).toInt() + 42); + }); + test('int16_t', () { + expect(bindings.Function1Int16(pow(2, 15).toInt()), + -pow(2, 15).toInt() + 42); + }); + test('int32_t', () { + expect(bindings.Function1Int32(pow(2, 31).toInt()), + -pow(2, 31).toInt() + 42); + }); + test('int64_t', () { + expect(bindings.Function1Int64(pow(2, 63).toInt()), + -pow(2, 63).toInt() + 42); + }); + test('intptr_t', () { + expect(bindings.Function1IntPtr(0), 42); + }); + test('float', () { + expect(bindings.Function1Float(0), 42.0); + }); + test('double', () { + expect(bindings.Function1Double(0), 42.0); + }); + test('Array Test: Order of access', () { + final struct1 = bindings.getStruct1(); + var expectedValue = 1; + final dimensions = [3, 1, 2]; + for (var i = 0; i < dimensions[0]; i++) { + for (var j = 0; j < dimensions[1]; j++) { + for (var k = 0; k < dimensions[2]; k++) { + expect(struct1.ref.data[i][j][k], expectedValue); + expectedValue++; + } + } + } + }); + test('Array Workaround: Range Errors', () { + final struct1 = bindings.getStruct1(); + // Index (get) above range. + expect( + () => struct1.ref.data[4][0][0], throwsA(TypeMatcher())); + expect( + () => struct1.ref.data[0][2][0], throwsA(TypeMatcher())); + expect( + () => struct1.ref.data[0][0][3], throwsA(TypeMatcher())); + // Index (get) below range. + expect( + () => struct1.ref.data[-1][0][0], throwsA(TypeMatcher())); + expect( + () => struct1.ref.data[-1][0][0], throwsA(TypeMatcher())); + expect( + () => struct1.ref.data[0][0][-1], throwsA(TypeMatcher())); + + // Index (set) above range. + expect(() => struct1.ref.data[4][0][0] = 0, + throwsA(TypeMatcher())); + expect(() => struct1.ref.data[0][2][0] = 0, + throwsA(TypeMatcher())); + expect(() => struct1.ref.data[0][0][3] = 0, + throwsA(TypeMatcher())); + // Index (get) below range. + expect(() => struct1.ref.data[-1][0][0] = 0, + throwsA(TypeMatcher())); + expect(() => struct1.ref.data[-1][0][0] = 0, + throwsA(TypeMatcher())); + expect(() => struct1.ref.data[0][0][-1] = 0, + throwsA(TypeMatcher())); + }); + test('Struct By Value', () { + final r = Random(); + final a = r.nextInt(100), b = r.nextInt(100), c = r.nextInt(100); + final s = bindings.Function1StructReturnByValue(a, b, c); + expect(bindings.Function1StructPassByValue(s), a + b + c); + }); + }); +} diff --git a/test/ffi_native_test/native_test.c b/test/ffi_native_test/native_test.c new file mode 100644 index 00000000..f971ac6c --- /dev/null +++ b/test/ffi_native_test/native_test.c @@ -0,0 +1,74 @@ +// Copyright (c) 2020, 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. +#define aloc(T) ((T *)malloc(sizeof(T))) + +#include +#include +#include + +bool Function1Bool(bool x) { return !x; } + +uint8_t Function1Uint8(uint8_t x) { return x + 42; } + +uint16_t Function1Uint16(uint16_t x) { return x + 42; } + +uint32_t Function1Uint32(uint32_t x) { return x + 42; } + +uint64_t Function1Uint64(uint64_t x) { return x + 42; } + +int8_t Function1Int8(int8_t x) { return x + 42; } + +int16_t Function1Int16(int16_t x) { return x + 42; } + +int32_t Function1Int32(int32_t x) { return x + 42; } + +int64_t Function1Int64(int64_t x) { return x + 42; } + +intptr_t Function1IntPtr(intptr_t x) { return x + 42; } + +uintptr_t Function1UintPtr(uintptr_t x) { return x + 42; } + +float Function1Float(float x) { return x + 42.0f; } + +double Function1Double(double x) { return x + 42.0; } + +struct Struct1 +{ + int8_t a; + int32_t data[3][1][2]; +}; + +struct Struct1 *getStruct1() +{ + struct Struct1 *s = aloc(struct Struct1); + s->a = 0; + s->data[0][0][0] = 1; + s->data[0][0][1] = 2; + s->data[1][0][0] = 3; + s->data[1][0][1] = 4; + s->data[2][0][0] = 5; + s->data[2][0][1] = 6; + return s; +} + +struct Struct3 +{ + int a; + int b; + int c; +}; + +struct Struct3 Function1StructReturnByValue(int a, int b, int c) +{ + struct Struct3 s; + s.a = a; + s.b = b; + s.c = c; + return s; +} + +int Function1StructPassByValue(struct Struct3 sum_a_b_c) +{ + return sum_a_b_c.a + sum_a_b_c.b + sum_a_b_c.c; +} diff --git a/test/ffi_native_test/native_test.def b/test/ffi_native_test/native_test.def new file mode 100644 index 00000000..b6bf2e0b --- /dev/null +++ b/test/ffi_native_test/native_test.def @@ -0,0 +1,20 @@ +; Copyright (c) 2020, 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. + +EXPORTS +Function1Bool +Function1Uint8 +Function1Uint16 +Function1Uint32 +Function1Uint64 +Function1Int8 +Function1Int16 +Function1Int32 +Function1Int64 +Function1IntPtr +Function1Float +Function1Double +getStruct1 +Function1StructReturnByValue +Function1StructPassByValue diff --git a/test/regen.dart b/test/regen.dart index ec529644..437a2d7f 100644 --- a/test/regen.dart +++ b/test/regen.dart @@ -54,6 +54,8 @@ Future main(List args) async { _regenConfig('test/native_test/config.yaml', 'test/native_test/_expected_native_test_bindings.dart'); + _regenConfig('test/ffi_native_test/config.yaml', + 'test/ffi_native_test/_expected_ffi_native_test_bindings.dart'); _regenConfig('example/libclang-example/config.yaml', 'example/libclang-example/generated_bindings.dart'); _regenConfig( From 473eb53038066cf41a90822565bb8c9e7fd20299 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 10:52:59 +0800 Subject: [PATCH 2/7] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d90855d..2e6d0142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ generate a typedef for the `Function`. - Use Dart wrapper types in args and returns of ObjCBlocks. - Bump min SDK version to 3.2.0-114.0.dev. +- Renamed `asset` to `assetId` for `ffi-native` # 9.0.1 From e0e0b0edf536d0b84f5d1f5b945be98cf46ae151 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 15:32:52 +0800 Subject: [PATCH 3/7] fix per comments on PR --- CHANGELOG.md | 2 +- example/ffinative/config.yaml | 4 +- .../{ => lib}/generated_bindings.dart | 14 +- test/ffi_native_test/.gitignore | 3 - .../_expected_ffi_native_test_bindings.dart | 122 -------------- test/ffi_native_test/build_test_dylib.dart | 129 --------------- test/ffi_native_test/ffi_native_test.dart | 153 ------------------ test/ffi_native_test/native_test.c | 74 --------- test/ffi_native_test/native_test.def | 20 --- .../config_with_asset_id.yaml} | 8 +- test/native_test/native_test.dart | 34 ++++ 11 files changed, 49 insertions(+), 514 deletions(-) rename example/ffinative/{ => lib}/generated_bindings.dart (68%) delete mode 100644 test/ffi_native_test/.gitignore delete mode 100644 test/ffi_native_test/_expected_ffi_native_test_bindings.dart delete mode 100644 test/ffi_native_test/build_test_dylib.dart delete mode 100644 test/ffi_native_test/ffi_native_test.dart delete mode 100644 test/ffi_native_test/native_test.c delete mode 100644 test/ffi_native_test/native_test.def rename test/{ffi_native_test/config.yaml => native_test/config_with_asset_id.yaml} (82%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e6d0142..3de820db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ generate a typedef for the `Function`. - Use Dart wrapper types in args and returns of ObjCBlocks. - Bump min SDK version to 3.2.0-114.0.dev. -- Renamed `asset` to `assetId` for `ffi-native` +- Renamed `asset` to `assetId` for `ffi-native`. # 9.0.1 diff --git a/example/ffinative/config.yaml b/example/ffinative/config.yaml index 283794a9..1bb3dac0 100644 --- a/example/ffinative/config.yaml +++ b/example/ffinative/config.yaml @@ -2,9 +2,9 @@ name: NativeLibrary ffi-native: - assetId: 'assetname' # (optional) + assetId: 'package:ffinative_example/generated_bindings.dart' # (optional) description: Bindings to `headers/example.h`. -output: 'generated_bindings.dart' +output: 'lib/generated_bindings.dart' headers: entry-points: - 'headers/example.h' diff --git a/example/ffinative/generated_bindings.dart b/example/ffinative/lib/generated_bindings.dart similarity index 68% rename from example/ffinative/generated_bindings.dart rename to example/ffinative/lib/generated_bindings.dart index bbefd052..13c7d2b9 100644 --- a/example/ffinative/generated_bindings.dart +++ b/example/ffinative/lib/generated_bindings.dart @@ -8,7 +8,7 @@ import 'dart:ffi' as ffi; /// Adds 2 integers. @ffi.Native( - symbol: 'sum', assetId: 'assetname') + symbol: 'sum', assetId: 'package:ffinative_example/generated_bindings.dart') external int sum( int a, int b, @@ -16,7 +16,8 @@ external int sum( /// Subtracts 2 integers. @ffi.Native( - symbol: 'subtract', assetId: 'assetname') + symbol: 'subtract', + assetId: 'package:ffinative_example/generated_bindings.dart') external int subtract( int a, int b, @@ -24,7 +25,8 @@ external int subtract( /// Multiplies 2 integers, returns pointer to an integer,. @ffi.Native Function(ffi.Int, ffi.Int)>( - symbol: 'multiply', assetId: 'assetname') + symbol: 'multiply', + assetId: 'package:ffinative_example/generated_bindings.dart') external ffi.Pointer multiply( int a, int b, @@ -32,7 +34,8 @@ external ffi.Pointer multiply( /// Divides 2 integers, returns pointer to a float. @ffi.Native Function(ffi.Int, ffi.Int)>( - symbol: 'divide', assetId: 'assetname') + symbol: 'divide', + assetId: 'package:ffinative_example/generated_bindings.dart') external ffi.Pointer divide( int a, int b, @@ -40,7 +43,8 @@ external ffi.Pointer divide( /// Divides 2 floats, returns a pointer to double. @ffi.Native Function(ffi.Float, ffi.Float)>( - symbol: 'dividePrecision', assetId: 'assetname') + symbol: 'dividePrecision', + assetId: 'package:ffinative_example/generated_bindings.dart') external ffi.Pointer dividePrecision( double a, double b, diff --git a/test/ffi_native_test/.gitignore b/test/ffi_native_test/.gitignore deleted file mode 100644 index d97e2fcb..00000000 --- a/test/ffi_native_test/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Ignore files generated by clang on windows. -native_test.exp -native_test.lib diff --git a/test/ffi_native_test/_expected_ffi_native_test_bindings.dart b/test/ffi_native_test/_expected_ffi_native_test_bindings.dart deleted file mode 100644 index a623df6e..00000000 --- a/test/ffi_native_test/_expected_ffi_native_test_bindings.dart +++ /dev/null @@ -1,122 +0,0 @@ -// ignore_for_file: camel_case_types, non_constant_identifier_names - -// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -// ignore_for_file: type=lint -import 'dart:ffi' as ffi; - -@ffi.Native( - symbol: 'Function1Bool', assetId: 'native_test') -external bool Function1Bool( - bool x, -); - -@ffi.Native( - symbol: 'Function1Uint8', assetId: 'native_test') -external int Function1Uint8( - int x, -); - -@ffi.Native( - symbol: 'Function1Uint16', assetId: 'native_test') -external int Function1Uint16( - int x, -); - -@ffi.Native( - symbol: 'Function1Uint32', assetId: 'native_test') -external int Function1Uint32( - int x, -); - -@ffi.Native( - symbol: 'Function1Uint64', assetId: 'native_test') -external int Function1Uint64( - int x, -); - -@ffi.Native( - symbol: 'Function1Int8', assetId: 'native_test') -external int Function1Int8( - int x, -); - -@ffi.Native( - symbol: 'Function1Int16', assetId: 'native_test') -external int Function1Int16( - int x, -); - -@ffi.Native( - symbol: 'Function1Int32', assetId: 'native_test') -external int Function1Int32( - int x, -); - -@ffi.Native( - symbol: 'Function1Int64', assetId: 'native_test') -external int Function1Int64( - int x, -); - -@ffi.Native( - symbol: 'Function1IntPtr', assetId: 'native_test') -external int Function1IntPtr( - int x, -); - -@ffi.Native( - symbol: 'Function1UintPtr', assetId: 'native_test') -external int Function1UintPtr( - int x, -); - -@ffi.Native( - symbol: 'Function1Float', assetId: 'native_test') -external double Function1Float( - double x, -); - -@ffi.Native( - symbol: 'Function1Double', assetId: 'native_test') -external double Function1Double( - double x, -); - -@ffi.Native Function()>( - symbol: 'getStruct1', assetId: 'native_test') -external ffi.Pointer getStruct1(); - -@ffi.Native( - symbol: 'Function1StructReturnByValue', assetId: 'native_test') -external Struct3 Function1StructReturnByValue( - int a, - int b, - int c, -); - -@ffi.Native( - symbol: 'Function1StructPassByValue', assetId: 'native_test') -external int Function1StructPassByValue( - Struct3 sum_a_b_c, -); - -final class Struct1 extends ffi.Struct { - @ffi.Int8() - external int a; - - @ffi.Array.multi([3, 1, 2]) - external ffi.Array>> data; -} - -final class Struct3 extends ffi.Struct { - @ffi.Int() - external int a; - - @ffi.Int() - external int b; - - @ffi.Int() - external int c; -} diff --git a/test/ffi_native_test/build_test_dylib.dart b/test/ffi_native_test/build_test_dylib.dart deleted file mode 100644 index a41f6863..00000000 --- a/test/ffi_native_test/build_test_dylib.dart +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2020, 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. - -/// ======================================================================= -/// ==== Script to generate dynamic library for native_function_tests ===== -/// ======================================================================= -/// This Script effectively calls the following (but user can provide -/// command line args which will replace the defaults shown below)- -/// -/// Linux: -/// ``` -/// clang -shared -fpic native_test.c -o native_test.so -/// ``` -/// MacOS: -/// ``` -/// clang -shared -fpic native_test.c -o native_test.dylib -/// ``` -/// Windows: -/// ``` -/// call clang -shared native_test.c -o native_test.dll -Wl,"/DEF:native_test.def" -/// del native_test.exp -/// del native_test.lib -/// ``` -/// ======================================================================= -/// ======================================================================= -/// ======================================================================= - -import 'dart:io'; - -const macOS = 'macos'; -const windows = 'windows'; -const linux = 'linux'; - -Map platformOptions = { - linux: Options( - outputfilename: 'native_test.so', - sharedFlag: '-shared', - inputHeader: 'native_test.c', - fPIC: '-fpic', - ), - windows: Options( - outputfilename: 'native_test.dll', - sharedFlag: '-shared', - inputHeader: 'native_test.c', - moduleDefPath: '-Wl,/DEF:native_test.def', - ), - macOS: Options( - outputfilename: 'native_test.dylib', - sharedFlag: '-shared', - inputHeader: 'native_test.c', - fPIC: '-fpic', - ), -}; - -void main(List arguments) { - print('Building Dynamic Library for Native Tests... '); - final options = getPlatformOptions()!; - - // Run clang compiler to generate the dynamic library. - final processResult = runClangProcess(options); - printSuccess(processResult, options); -} - -/// Calls the clang compiler. -ProcessResult runClangProcess(Options options) { - final result = Process.runSync( - 'clang', - [ - options.sharedFlag, - options.fPIC, - options.inputHeader, - '-o', - options.outputfilename, - options.moduleDefPath, - '-Wno-nullability-completeness', - ], - ); - return result; -} - -/// Prints success message (or process error if any). -void printSuccess(ProcessResult result, Options options) { - print(result.stdout); - if ((result.stderr as String).isEmpty) { - print('Generated file: ${options.outputfilename}'); - } else { - print(result.stderr); - } -} - -/// Get options based on current platform. -Options? getPlatformOptions() { - if (Platform.isMacOS) { - return platformOptions[macOS]; - } else if (Platform.isWindows) { - return platformOptions[windows]; - } else if (Platform.isLinux) { - return platformOptions[linux]; - } else { - throw Exception('Unknown Platform.'); - } -} - -/// Hold options which would be passed to clang. -class Options { - /// Name of dynamic library to generate. - final String outputfilename; - - /// Tells compiler to generate a shared library. - final String sharedFlag; - - /// Flag for generating Position Independant Code (Not used on windows). - final String fPIC; - - /// Input file. - final String inputHeader; - - /// Path to `.def` file containing symbols to export, windows use only. - final String moduleDefPath; - - Options({ - required this.outputfilename, - required this.sharedFlag, - required this.inputHeader, - this.fPIC = '', - this.moduleDefPath = '', - }); -} diff --git a/test/ffi_native_test/ffi_native_test.dart b/test/ffi_native_test/ffi_native_test.dart deleted file mode 100644 index aaf336c1..00000000 --- a/test/ffi_native_test/ffi_native_test.dart +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2020, 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:ffi'; -import 'dart:io'; -import 'dart:math'; - -import 'package:ffigen/ffigen.dart'; -import 'package:path/path.dart' as path; -import 'package:test/test.dart'; -import '../test_utils.dart'; -import '_expected_ffi_native_test_bindings.dart' as bindings; - -void main() { - group('native_test', () { - setUpAll(() { - logWarnings(); - var dylibName = 'test/ffi_native_test/native_test.so'; - if (Platform.isMacOS) { - dylibName = 'test/ffi_native_test/native_test.dylib'; - } else if (Platform.isWindows) { - dylibName = r'test\ffi_native_test\native_test.dll'; - } - final dylib = File(dylibName); - verifySetupFile(dylib); - DynamicLibrary.open(dylib.absolute.path); - }); - - test('generate_bindings', () { - final configFile = - File(path.join('test', 'ffi_native_test', 'config.yaml')).absolute; - final outFile = File( - path.join('test', 'debug_generated', - '_expected_ffi_native_test_bindings.dart'), - ).absolute; - - late Config config; - withChDir(configFile.path, () { - config = testConfigFromPath(configFile.path); - }); - final library = parse(config); - - library.generateFile(outFile); - - try { - final actual = outFile.readAsStringSync().replaceAll('\r', ''); - final expected = File(path.join(config.output)) - .readAsStringSync() - .replaceAll('\r', ''); - expect(actual, expected); - if (outFile.existsSync()) { - outFile.delete(); - } - } catch (e) { - print('Failed test: Debug generated file: ${outFile.absolute.path}'); - rethrow; - } - }); - test('bool', () { - expect(bindings.Function1Bool(true), false); - expect(bindings.Function1Bool(false), true); - }); - test('uint8_t', () { - expect(bindings.Function1Uint8(pow(2, 8).toInt()), 42); - }); - test('uint16_t', () { - expect(bindings.Function1Uint16(pow(2, 16).toInt()), 42); - }); - test('uint32_t', () { - expect(bindings.Function1Uint32(pow(2, 32).toInt()), 42); - }); - test('uint64_t', () { - expect(bindings.Function1Uint64(pow(2, 64).toInt()), 42); - }); - test('int8_t', () { - expect( - bindings.Function1Int8(pow(2, 7).toInt()), -pow(2, 7).toInt() + 42); - }); - test('int16_t', () { - expect(bindings.Function1Int16(pow(2, 15).toInt()), - -pow(2, 15).toInt() + 42); - }); - test('int32_t', () { - expect(bindings.Function1Int32(pow(2, 31).toInt()), - -pow(2, 31).toInt() + 42); - }); - test('int64_t', () { - expect(bindings.Function1Int64(pow(2, 63).toInt()), - -pow(2, 63).toInt() + 42); - }); - test('intptr_t', () { - expect(bindings.Function1IntPtr(0), 42); - }); - test('float', () { - expect(bindings.Function1Float(0), 42.0); - }); - test('double', () { - expect(bindings.Function1Double(0), 42.0); - }); - test('Array Test: Order of access', () { - final struct1 = bindings.getStruct1(); - var expectedValue = 1; - final dimensions = [3, 1, 2]; - for (var i = 0; i < dimensions[0]; i++) { - for (var j = 0; j < dimensions[1]; j++) { - for (var k = 0; k < dimensions[2]; k++) { - expect(struct1.ref.data[i][j][k], expectedValue); - expectedValue++; - } - } - } - }); - test('Array Workaround: Range Errors', () { - final struct1 = bindings.getStruct1(); - // Index (get) above range. - expect( - () => struct1.ref.data[4][0][0], throwsA(TypeMatcher())); - expect( - () => struct1.ref.data[0][2][0], throwsA(TypeMatcher())); - expect( - () => struct1.ref.data[0][0][3], throwsA(TypeMatcher())); - // Index (get) below range. - expect( - () => struct1.ref.data[-1][0][0], throwsA(TypeMatcher())); - expect( - () => struct1.ref.data[-1][0][0], throwsA(TypeMatcher())); - expect( - () => struct1.ref.data[0][0][-1], throwsA(TypeMatcher())); - - // Index (set) above range. - expect(() => struct1.ref.data[4][0][0] = 0, - throwsA(TypeMatcher())); - expect(() => struct1.ref.data[0][2][0] = 0, - throwsA(TypeMatcher())); - expect(() => struct1.ref.data[0][0][3] = 0, - throwsA(TypeMatcher())); - // Index (get) below range. - expect(() => struct1.ref.data[-1][0][0] = 0, - throwsA(TypeMatcher())); - expect(() => struct1.ref.data[-1][0][0] = 0, - throwsA(TypeMatcher())); - expect(() => struct1.ref.data[0][0][-1] = 0, - throwsA(TypeMatcher())); - }); - test('Struct By Value', () { - final r = Random(); - final a = r.nextInt(100), b = r.nextInt(100), c = r.nextInt(100); - final s = bindings.Function1StructReturnByValue(a, b, c); - expect(bindings.Function1StructPassByValue(s), a + b + c); - }); - }); -} diff --git a/test/ffi_native_test/native_test.c b/test/ffi_native_test/native_test.c deleted file mode 100644 index f971ac6c..00000000 --- a/test/ffi_native_test/native_test.c +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2020, 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. -#define aloc(T) ((T *)malloc(sizeof(T))) - -#include -#include -#include - -bool Function1Bool(bool x) { return !x; } - -uint8_t Function1Uint8(uint8_t x) { return x + 42; } - -uint16_t Function1Uint16(uint16_t x) { return x + 42; } - -uint32_t Function1Uint32(uint32_t x) { return x + 42; } - -uint64_t Function1Uint64(uint64_t x) { return x + 42; } - -int8_t Function1Int8(int8_t x) { return x + 42; } - -int16_t Function1Int16(int16_t x) { return x + 42; } - -int32_t Function1Int32(int32_t x) { return x + 42; } - -int64_t Function1Int64(int64_t x) { return x + 42; } - -intptr_t Function1IntPtr(intptr_t x) { return x + 42; } - -uintptr_t Function1UintPtr(uintptr_t x) { return x + 42; } - -float Function1Float(float x) { return x + 42.0f; } - -double Function1Double(double x) { return x + 42.0; } - -struct Struct1 -{ - int8_t a; - int32_t data[3][1][2]; -}; - -struct Struct1 *getStruct1() -{ - struct Struct1 *s = aloc(struct Struct1); - s->a = 0; - s->data[0][0][0] = 1; - s->data[0][0][1] = 2; - s->data[1][0][0] = 3; - s->data[1][0][1] = 4; - s->data[2][0][0] = 5; - s->data[2][0][1] = 6; - return s; -} - -struct Struct3 -{ - int a; - int b; - int c; -}; - -struct Struct3 Function1StructReturnByValue(int a, int b, int c) -{ - struct Struct3 s; - s.a = a; - s.b = b; - s.c = c; - return s; -} - -int Function1StructPassByValue(struct Struct3 sum_a_b_c) -{ - return sum_a_b_c.a + sum_a_b_c.b + sum_a_b_c.c; -} diff --git a/test/ffi_native_test/native_test.def b/test/ffi_native_test/native_test.def deleted file mode 100644 index b6bf2e0b..00000000 --- a/test/ffi_native_test/native_test.def +++ /dev/null @@ -1,20 +0,0 @@ -; Copyright (c) 2020, 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. - -EXPORTS -Function1Bool -Function1Uint8 -Function1Uint16 -Function1Uint32 -Function1Uint64 -Function1Int8 -Function1Int16 -Function1Int32 -Function1Int64 -Function1IntPtr -Function1Float -Function1Double -getStruct1 -Function1StructReturnByValue -Function1StructPassByValue diff --git a/test/ffi_native_test/config.yaml b/test/native_test/config_with_asset_id.yaml similarity index 82% rename from test/ffi_native_test/config.yaml rename to test/native_test/config_with_asset_id.yaml index f9546031..3942f6f2 100644 --- a/test/ffi_native_test/config.yaml +++ b/test/native_test/config_with_asset_id.yaml @@ -6,16 +6,14 @@ # dart run ffigen --config test/native_test/config.yaml # =============================================================== -name: FfiNative -description: 'ffi-native tests.' -output: '_expected_ffi_native_test_bindings.dart' +name: NativeLibrary +description: 'Native tests.' +output: '_expected_native_test_bindings.dart' headers: entry-points: - 'native_test.c' include-directives: - '**native_test.c' -ffi-native: - assetId: "native_test" compiler-opts: '-Wno-nullability-completeness' preamble: | diff --git a/test/native_test/native_test.dart b/test/native_test/native_test.dart index cc31709e..134290f8 100644 --- a/test/native_test/native_test.dart +++ b/test/native_test/native_test.dart @@ -58,6 +58,39 @@ void main() { rethrow; } }); + + test('generate_bindings with assetId', () { + final configFile = + File(path.join('test', 'native_test', 'config_with_asset_id.yaml')) + .absolute; + final outFile = File( + path.join('test', 'debug_generated', + '_expected_native_test_bindings_with_asset_id.dart'), + ).absolute; + + late Config config; + withChDir(configFile.path, () { + config = testConfigFromPath(configFile.path); + }); + final library = parse(config); + + library.generateFile(outFile); + + try { + final actual = outFile.readAsStringSync().replaceAll('\r', ''); + final expected = File(path.join(config.output)) + .readAsStringSync() + .replaceAll('\r', ''); + expect(actual, expected); + if (outFile.existsSync()) { + outFile.delete(); + } + } catch (e) { + print('Failed test: Debug generated file: ${outFile.absolute.path}'); + rethrow; + } + }); + test('bool', () { expect(bindings.Function1Bool(true), false); expect(bindings.Function1Bool(false), true); @@ -112,6 +145,7 @@ void main() { } } }); + test('Array Workaround: Range Errors', () { final struct1 = bindings.getStruct1(); // Index (get) above range. From adc94bf6491d4effcf4bc56735d756e2cd71f37d Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 15:40:32 +0800 Subject: [PATCH 4/7] add assetId YAML + generated bindings for native_test --- ...ed_native_test_bindings_with_asset_id.dart | 264 ++++++++++++++++++ test/native_test/config_with_asset_id.yaml | 2 +- 2 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 test/native_test/_expected_native_test_bindings_with_asset_id.dart diff --git a/test/native_test/_expected_native_test_bindings_with_asset_id.dart b/test/native_test/_expected_native_test_bindings_with_asset_id.dart new file mode 100644 index 00000000..58934cf4 --- /dev/null +++ b/test/native_test/_expected_native_test_bindings_with_asset_id.dart @@ -0,0 +1,264 @@ +// ignore_for_file: camel_case_types, non_constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint +import 'dart:ffi' as ffi; + +/// Native tests. +class NativeLibrary { + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + NativeLibrary(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + NativeLibrary.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + bool Function1Bool( + bool x, + ) { + return _Function1Bool( + x, + ); + } + + late final _Function1BoolPtr = + _lookup>('Function1Bool'); + late final _Function1Bool = + _Function1BoolPtr.asFunction(); + + int Function1Uint8( + int x, + ) { + return _Function1Uint8( + x, + ); + } + + late final _Function1Uint8Ptr = + _lookup>( + 'Function1Uint8'); + late final _Function1Uint8 = + _Function1Uint8Ptr.asFunction(); + + int Function1Uint16( + int x, + ) { + return _Function1Uint16( + x, + ); + } + + late final _Function1Uint16Ptr = + _lookup>( + 'Function1Uint16'); + late final _Function1Uint16 = + _Function1Uint16Ptr.asFunction(); + + int Function1Uint32( + int x, + ) { + return _Function1Uint32( + x, + ); + } + + late final _Function1Uint32Ptr = + _lookup>( + 'Function1Uint32'); + late final _Function1Uint32 = + _Function1Uint32Ptr.asFunction(); + + int Function1Uint64( + int x, + ) { + return _Function1Uint64( + x, + ); + } + + late final _Function1Uint64Ptr = + _lookup>( + 'Function1Uint64'); + late final _Function1Uint64 = + _Function1Uint64Ptr.asFunction(); + + int Function1Int8( + int x, + ) { + return _Function1Int8( + x, + ); + } + + late final _Function1Int8Ptr = + _lookup>('Function1Int8'); + late final _Function1Int8 = _Function1Int8Ptr.asFunction(); + + int Function1Int16( + int x, + ) { + return _Function1Int16( + x, + ); + } + + late final _Function1Int16Ptr = + _lookup>( + 'Function1Int16'); + late final _Function1Int16 = + _Function1Int16Ptr.asFunction(); + + int Function1Int32( + int x, + ) { + return _Function1Int32( + x, + ); + } + + late final _Function1Int32Ptr = + _lookup>( + 'Function1Int32'); + late final _Function1Int32 = + _Function1Int32Ptr.asFunction(); + + int Function1Int64( + int x, + ) { + return _Function1Int64( + x, + ); + } + + late final _Function1Int64Ptr = + _lookup>( + 'Function1Int64'); + late final _Function1Int64 = + _Function1Int64Ptr.asFunction(); + + int Function1IntPtr( + int x, + ) { + return _Function1IntPtr( + x, + ); + } + + late final _Function1IntPtrPtr = + _lookup>( + 'Function1IntPtr'); + late final _Function1IntPtr = + _Function1IntPtrPtr.asFunction(); + + int Function1UintPtr( + int x, + ) { + return _Function1UintPtr( + x, + ); + } + + late final _Function1UintPtrPtr = + _lookup>( + 'Function1UintPtr'); + late final _Function1UintPtr = + _Function1UintPtrPtr.asFunction(); + + double Function1Float( + double x, + ) { + return _Function1Float( + x, + ); + } + + late final _Function1FloatPtr = + _lookup>( + 'Function1Float'); + late final _Function1Float = + _Function1FloatPtr.asFunction(); + + double Function1Double( + double x, + ) { + return _Function1Double( + x, + ); + } + + late final _Function1DoublePtr = + _lookup>( + 'Function1Double'); + late final _Function1Double = + _Function1DoublePtr.asFunction(); + + ffi.Pointer getStruct1() { + return _getStruct1(); + } + + late final _getStruct1Ptr = + _lookup Function()>>( + 'getStruct1'); + late final _getStruct1 = + _getStruct1Ptr.asFunction Function()>(); + + Struct3 Function1StructReturnByValue( + int a, + int b, + int c, + ) { + return _Function1StructReturnByValue( + a, + b, + c, + ); + } + + late final _Function1StructReturnByValuePtr = + _lookup>( + 'Function1StructReturnByValue'); + late final _Function1StructReturnByValue = _Function1StructReturnByValuePtr + .asFunction(); + + int Function1StructPassByValue( + Struct3 sum_a_b_c, + ) { + return _Function1StructPassByValue( + sum_a_b_c, + ); + } + + late final _Function1StructPassByValuePtr = + _lookup>( + 'Function1StructPassByValue'); + late final _Function1StructPassByValue = + _Function1StructPassByValuePtr.asFunction(); +} + +final class Struct1 extends ffi.Struct { + @ffi.Int8() + external int a; + + @ffi.Array.multi([3, 1, 2]) + external ffi.Array>> data; +} + +final class Struct3 extends ffi.Struct { + @ffi.Int() + external int a; + + @ffi.Int() + external int b; + + @ffi.Int() + external int c; +} diff --git a/test/native_test/config_with_asset_id.yaml b/test/native_test/config_with_asset_id.yaml index 3942f6f2..9c7039ef 100644 --- a/test/native_test/config_with_asset_id.yaml +++ b/test/native_test/config_with_asset_id.yaml @@ -8,7 +8,7 @@ name: NativeLibrary description: 'Native tests.' -output: '_expected_native_test_bindings.dart' +output: '_expected_native_test_bindings_with_asset_id.dart' headers: entry-points: - 'native_test.c' From 64cef92531356f09bac942ab44d00258a30a782f Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 15:42:18 +0800 Subject: [PATCH 5/7] update generated bindings for assetId --- ...ed_native_test_bindings_with_asset_id.dart | 348 ++++++------------ test/native_test/config_with_asset_id.yaml | 2 + 2 files changed, 113 insertions(+), 237 deletions(-) diff --git a/test/native_test/_expected_native_test_bindings_with_asset_id.dart b/test/native_test/_expected_native_test_bindings_with_asset_id.dart index 58934cf4..8bdd482e 100644 --- a/test/native_test/_expected_native_test_bindings_with_asset_id.dart +++ b/test/native_test/_expected_native_test_bindings_with_asset_id.dart @@ -6,243 +6,117 @@ // ignore_for_file: type=lint import 'dart:ffi' as ffi; -/// Native tests. -class NativeLibrary { - /// Holds the symbol lookup function. - final ffi.Pointer Function(String symbolName) - _lookup; - - /// The symbols are looked up in [dynamicLibrary]. - NativeLibrary(ffi.DynamicLibrary dynamicLibrary) - : _lookup = dynamicLibrary.lookup; - - /// The symbols are looked up with [lookup]. - NativeLibrary.fromLookup( - ffi.Pointer Function(String symbolName) - lookup) - : _lookup = lookup; - - bool Function1Bool( - bool x, - ) { - return _Function1Bool( - x, - ); - } - - late final _Function1BoolPtr = - _lookup>('Function1Bool'); - late final _Function1Bool = - _Function1BoolPtr.asFunction(); - - int Function1Uint8( - int x, - ) { - return _Function1Uint8( - x, - ); - } - - late final _Function1Uint8Ptr = - _lookup>( - 'Function1Uint8'); - late final _Function1Uint8 = - _Function1Uint8Ptr.asFunction(); - - int Function1Uint16( - int x, - ) { - return _Function1Uint16( - x, - ); - } - - late final _Function1Uint16Ptr = - _lookup>( - 'Function1Uint16'); - late final _Function1Uint16 = - _Function1Uint16Ptr.asFunction(); - - int Function1Uint32( - int x, - ) { - return _Function1Uint32( - x, - ); - } - - late final _Function1Uint32Ptr = - _lookup>( - 'Function1Uint32'); - late final _Function1Uint32 = - _Function1Uint32Ptr.asFunction(); - - int Function1Uint64( - int x, - ) { - return _Function1Uint64( - x, - ); - } - - late final _Function1Uint64Ptr = - _lookup>( - 'Function1Uint64'); - late final _Function1Uint64 = - _Function1Uint64Ptr.asFunction(); - - int Function1Int8( - int x, - ) { - return _Function1Int8( - x, - ); - } - - late final _Function1Int8Ptr = - _lookup>('Function1Int8'); - late final _Function1Int8 = _Function1Int8Ptr.asFunction(); - - int Function1Int16( - int x, - ) { - return _Function1Int16( - x, - ); - } - - late final _Function1Int16Ptr = - _lookup>( - 'Function1Int16'); - late final _Function1Int16 = - _Function1Int16Ptr.asFunction(); - - int Function1Int32( - int x, - ) { - return _Function1Int32( - x, - ); - } - - late final _Function1Int32Ptr = - _lookup>( - 'Function1Int32'); - late final _Function1Int32 = - _Function1Int32Ptr.asFunction(); - - int Function1Int64( - int x, - ) { - return _Function1Int64( - x, - ); - } - - late final _Function1Int64Ptr = - _lookup>( - 'Function1Int64'); - late final _Function1Int64 = - _Function1Int64Ptr.asFunction(); - - int Function1IntPtr( - int x, - ) { - return _Function1IntPtr( - x, - ); - } - - late final _Function1IntPtrPtr = - _lookup>( - 'Function1IntPtr'); - late final _Function1IntPtr = - _Function1IntPtrPtr.asFunction(); - - int Function1UintPtr( - int x, - ) { - return _Function1UintPtr( - x, - ); - } - - late final _Function1UintPtrPtr = - _lookup>( - 'Function1UintPtr'); - late final _Function1UintPtr = - _Function1UintPtrPtr.asFunction(); - - double Function1Float( - double x, - ) { - return _Function1Float( - x, - ); - } - - late final _Function1FloatPtr = - _lookup>( - 'Function1Float'); - late final _Function1Float = - _Function1FloatPtr.asFunction(); - - double Function1Double( - double x, - ) { - return _Function1Double( - x, - ); - } - - late final _Function1DoublePtr = - _lookup>( - 'Function1Double'); - late final _Function1Double = - _Function1DoublePtr.asFunction(); - - ffi.Pointer getStruct1() { - return _getStruct1(); - } - - late final _getStruct1Ptr = - _lookup Function()>>( - 'getStruct1'); - late final _getStruct1 = - _getStruct1Ptr.asFunction Function()>(); - - Struct3 Function1StructReturnByValue( - int a, - int b, - int c, - ) { - return _Function1StructReturnByValue( - a, - b, - c, - ); - } - - late final _Function1StructReturnByValuePtr = - _lookup>( - 'Function1StructReturnByValue'); - late final _Function1StructReturnByValue = _Function1StructReturnByValuePtr - .asFunction(); - - int Function1StructPassByValue( - Struct3 sum_a_b_c, - ) { - return _Function1StructPassByValue( - sum_a_b_c, - ); - } - - late final _Function1StructPassByValuePtr = - _lookup>( - 'Function1StructPassByValue'); - late final _Function1StructPassByValue = - _Function1StructPassByValuePtr.asFunction(); -} +@ffi.Native( + symbol: 'Function1Bool', + assetId: 'package:ffinative_example/generated_bindings.dart') +external bool Function1Bool( + bool x, +); + +@ffi.Native( + symbol: 'Function1Uint8', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Uint8( + int x, +); + +@ffi.Native( + symbol: 'Function1Uint16', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Uint16( + int x, +); + +@ffi.Native( + symbol: 'Function1Uint32', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Uint32( + int x, +); + +@ffi.Native( + symbol: 'Function1Uint64', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Uint64( + int x, +); + +@ffi.Native( + symbol: 'Function1Int8', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Int8( + int x, +); + +@ffi.Native( + symbol: 'Function1Int16', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Int16( + int x, +); + +@ffi.Native( + symbol: 'Function1Int32', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Int32( + int x, +); + +@ffi.Native( + symbol: 'Function1Int64', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1Int64( + int x, +); + +@ffi.Native( + symbol: 'Function1IntPtr', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1IntPtr( + int x, +); + +@ffi.Native( + symbol: 'Function1UintPtr', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1UintPtr( + int x, +); + +@ffi.Native( + symbol: 'Function1Float', + assetId: 'package:ffinative_example/generated_bindings.dart') +external double Function1Float( + double x, +); + +@ffi.Native( + symbol: 'Function1Double', + assetId: 'package:ffinative_example/generated_bindings.dart') +external double Function1Double( + double x, +); + +@ffi.Native Function()>( + symbol: 'getStruct1', + assetId: 'package:ffinative_example/generated_bindings.dart') +external ffi.Pointer getStruct1(); + +@ffi.Native( + symbol: 'Function1StructReturnByValue', + assetId: 'package:ffinative_example/generated_bindings.dart') +external Struct3 Function1StructReturnByValue( + int a, + int b, + int c, +); + +@ffi.Native( + symbol: 'Function1StructPassByValue', + assetId: 'package:ffinative_example/generated_bindings.dart') +external int Function1StructPassByValue( + Struct3 sum_a_b_c, +); final class Struct1 extends ffi.Struct { @ffi.Int8() diff --git a/test/native_test/config_with_asset_id.yaml b/test/native_test/config_with_asset_id.yaml index 9c7039ef..658210f0 100644 --- a/test/native_test/config_with_asset_id.yaml +++ b/test/native_test/config_with_asset_id.yaml @@ -14,6 +14,8 @@ headers: - 'native_test.c' include-directives: - '**native_test.c' +ffi-native: + assetId: 'package:ffinative_example/generated_bindings.dart' # (optional) compiler-opts: '-Wno-nullability-completeness' preamble: | From e1457c03d8be84c297480d558af020a8b0ee049d Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 15:43:19 +0800 Subject: [PATCH 6/7] revert change to test/regen.dart --- test/regen.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/regen.dart b/test/regen.dart index 437a2d7f..ec529644 100644 --- a/test/regen.dart +++ b/test/regen.dart @@ -54,8 +54,6 @@ Future main(List args) async { _regenConfig('test/native_test/config.yaml', 'test/native_test/_expected_native_test_bindings.dart'); - _regenConfig('test/ffi_native_test/config.yaml', - 'test/ffi_native_test/_expected_ffi_native_test_bindings.dart'); _regenConfig('example/libclang-example/config.yaml', 'example/libclang-example/generated_bindings.dart'); _regenConfig( From 6d735e4d0d9d8fc6bd8033e3d151e4b7ca24c45c Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 1 Nov 2023 15:55:29 +0800 Subject: [PATCH 7/7] remove native_test codegen test for assetId --- ...ed_native_test_bindings_with_asset_id.dart | 138 ------------------ test/native_test/config_with_asset_id.yaml | 23 --- test/native_test/native_test.dart | 32 ---- 3 files changed, 193 deletions(-) delete mode 100644 test/native_test/_expected_native_test_bindings_with_asset_id.dart delete mode 100644 test/native_test/config_with_asset_id.yaml diff --git a/test/native_test/_expected_native_test_bindings_with_asset_id.dart b/test/native_test/_expected_native_test_bindings_with_asset_id.dart deleted file mode 100644 index 8bdd482e..00000000 --- a/test/native_test/_expected_native_test_bindings_with_asset_id.dart +++ /dev/null @@ -1,138 +0,0 @@ -// ignore_for_file: camel_case_types, non_constant_identifier_names - -// AUTO GENERATED FILE, DO NOT EDIT. -// -// Generated by `package:ffigen`. -// ignore_for_file: type=lint -import 'dart:ffi' as ffi; - -@ffi.Native( - symbol: 'Function1Bool', - assetId: 'package:ffinative_example/generated_bindings.dart') -external bool Function1Bool( - bool x, -); - -@ffi.Native( - symbol: 'Function1Uint8', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Uint8( - int x, -); - -@ffi.Native( - symbol: 'Function1Uint16', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Uint16( - int x, -); - -@ffi.Native( - symbol: 'Function1Uint32', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Uint32( - int x, -); - -@ffi.Native( - symbol: 'Function1Uint64', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Uint64( - int x, -); - -@ffi.Native( - symbol: 'Function1Int8', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Int8( - int x, -); - -@ffi.Native( - symbol: 'Function1Int16', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Int16( - int x, -); - -@ffi.Native( - symbol: 'Function1Int32', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Int32( - int x, -); - -@ffi.Native( - symbol: 'Function1Int64', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1Int64( - int x, -); - -@ffi.Native( - symbol: 'Function1IntPtr', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1IntPtr( - int x, -); - -@ffi.Native( - symbol: 'Function1UintPtr', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1UintPtr( - int x, -); - -@ffi.Native( - symbol: 'Function1Float', - assetId: 'package:ffinative_example/generated_bindings.dart') -external double Function1Float( - double x, -); - -@ffi.Native( - symbol: 'Function1Double', - assetId: 'package:ffinative_example/generated_bindings.dart') -external double Function1Double( - double x, -); - -@ffi.Native Function()>( - symbol: 'getStruct1', - assetId: 'package:ffinative_example/generated_bindings.dart') -external ffi.Pointer getStruct1(); - -@ffi.Native( - symbol: 'Function1StructReturnByValue', - assetId: 'package:ffinative_example/generated_bindings.dart') -external Struct3 Function1StructReturnByValue( - int a, - int b, - int c, -); - -@ffi.Native( - symbol: 'Function1StructPassByValue', - assetId: 'package:ffinative_example/generated_bindings.dart') -external int Function1StructPassByValue( - Struct3 sum_a_b_c, -); - -final class Struct1 extends ffi.Struct { - @ffi.Int8() - external int a; - - @ffi.Array.multi([3, 1, 2]) - external ffi.Array>> data; -} - -final class Struct3 extends ffi.Struct { - @ffi.Int() - external int a; - - @ffi.Int() - external int b; - - @ffi.Int() - external int c; -} diff --git a/test/native_test/config_with_asset_id.yaml b/test/native_test/config_with_asset_id.yaml deleted file mode 100644 index 658210f0..00000000 --- a/test/native_test/config_with_asset_id.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2020, 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. - -# =================== GENERATING TEST BINDINGS ================== -# dart run ffigen --config test/native_test/config.yaml -# =============================================================== - -name: NativeLibrary -description: 'Native tests.' -output: '_expected_native_test_bindings_with_asset_id.dart' -headers: - entry-points: - - 'native_test.c' - include-directives: - - '**native_test.c' -ffi-native: - assetId: 'package:ffinative_example/generated_bindings.dart' # (optional) - -compiler-opts: '-Wno-nullability-completeness' -preamble: | - // ignore_for_file: camel_case_types, non_constant_identifier_names - diff --git a/test/native_test/native_test.dart b/test/native_test/native_test.dart index 134290f8..9c734a56 100644 --- a/test/native_test/native_test.dart +++ b/test/native_test/native_test.dart @@ -59,38 +59,6 @@ void main() { } }); - test('generate_bindings with assetId', () { - final configFile = - File(path.join('test', 'native_test', 'config_with_asset_id.yaml')) - .absolute; - final outFile = File( - path.join('test', 'debug_generated', - '_expected_native_test_bindings_with_asset_id.dart'), - ).absolute; - - late Config config; - withChDir(configFile.path, () { - config = testConfigFromPath(configFile.path); - }); - final library = parse(config); - - library.generateFile(outFile); - - try { - final actual = outFile.readAsStringSync().replaceAll('\r', ''); - final expected = File(path.join(config.output)) - .readAsStringSync() - .replaceAll('\r', ''); - expect(actual, expected); - if (outFile.existsSync()) { - outFile.delete(); - } - } catch (e) { - print('Failed test: Debug generated file: ${outFile.absolute.path}'); - rethrow; - } - }); - test('bool', () { expect(bindings.Function1Bool(true), false); expect(bindings.Function1Bool(false), true);