Update headers config. (#60)
Closes #52
- Updated headers config to have sub-fields `entry-points` and `include-directives`, removed `header-filter` config.
- Globs are supported by both subkeys.
- Updated tests, examples, readme, changelog.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9a32792..bcd11c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 0.2.0-dev
+- Updated header config. Header `entry-points` and `include-directives` are now specified under `headers` key. Glob syntax is allowed.
+
# 0.1.5
- Added support for parsing macros and anonymous unnamed enums. These are generated as top level constants.
diff --git a/README.md b/README.md
index 604a1bc..7cee823 100644
--- a/README.md
+++ b/README.md
@@ -75,20 +75,17 @@
</tr>
<tr>
<td>headers<br><i>(Required)</i></td>
- <td>List of C headers to use. Glob syntax is allowed.</td>
+ <td>The header entry-points and include-directives. Glob syntax is allowed.</td>
<td><pre lang="yaml"><code>
headers:
- - 'folder/**.h'
- - 'folder/specific_header.h'</code></pre></td>
- </tr>
- <tr>
- <td>header-filter</td>
- <td>Name of headers to include/exclude.</td>
- <td><pre lang="yaml"><code>
-header-filter:
- include:
- - 'index.h'
- - 'platform.h'</code></pre></td>
+ entry-points:
+ - 'folder/**.h'
+ - 'folder/specific_header.h'
+ include-directives:
+ - '**index.h'
+ - '**/clang-c/**'
+ - '/full/path/to/a/header.h'
+ </code></pre></td>
</tr>
<tr>
<td>name<br><i>(Prefer)</i></td>
diff --git a/example/c_json/pubspec.yaml b/example/c_json/pubspec.yaml
index ef1f484..1058579 100644
--- a/example/c_json/pubspec.yaml
+++ b/example/c_json/pubspec.yaml
@@ -19,8 +19,8 @@
name: 'CJson'
description: 'Holds bindings to cJSON.'
headers:
- - '../../third_party/cjson_library/cJSON.h'
- header-filter:
- include:
- - 'cJSON.h'
+ entry-points:
+ - '../../third_party/cjson_library/cJSON.h'
+ include-directives:
+ - '**cJSON.h'
comments: false
diff --git a/example/libclang-example/pubspec.yaml b/example/libclang-example/pubspec.yaml
index 7cb89db..b05796f 100644
--- a/example/libclang-example/pubspec.yaml
+++ b/example/libclang-example/pubspec.yaml
@@ -18,13 +18,11 @@
# Bash style Glob matching is also supported.
# TODO(11): Globs dont work on windows if they begin with '.' or '..'.
headers:
- - ../../third_party/libclang/include/clang-c/Index.h
-
- # Excludes included headers based on their names (not fullpath name).
- header-filter:
- include:
- - 'CXString.h'
- - 'Index.h'
+ entry-points:
+ - ../../third_party/libclang/include/clang-c/Index.h
+ include-directives: # use glob syntax to match with header file path.
+ - '**CXString.h'
+ - '**Index.h'
compiler-opts: '-I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -IC:\Progra~1\LLVM\include -I/usr/local/opt/llvm/include/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -Wno-nullability-completeness'
functions:
diff --git a/example/simple/pubspec.yaml b/example/simple/pubspec.yaml
index 58aaa7e..c742a26 100644
--- a/example/simple/pubspec.yaml
+++ b/example/simple/pubspec.yaml
@@ -16,4 +16,5 @@
description: Bindings to `headers/example.h`.
output: 'generated_bindings.dart'
headers:
- - 'headers/example.h'
+ entry-points:
+ - 'headers/example.h'
diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart
index 9fd8d05..dec4c2c 100644
--- a/lib/src/code_generator/struc.dart
+++ b/lib/src/code_generator/struc.dart
@@ -248,8 +248,8 @@
s.write('''
${helperClassGroupName}_level${dim + 1} operator [](int index) {
$checkBoundsFunctionIdentifier(index);
- int offset = index;
- for (int i = level + 1; i < $dimensionsIdentifier.length; i++) {
+ var offset = index;
+ for (var i = level + 1; i < $dimensionsIdentifier.length; i++) {
offset *= $dimensionsIdentifier[i];
}
return ${helperClassGroupName}_level${dim + 1}(
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index eb75b80..583287d 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -23,13 +23,8 @@
/// output file name.
String output;
- /// Path to headers.
- ///
- /// This contains all the headers, after extraction from Globs.
- List<String> headers;
-
- /// Filter for headers.
- HeaderFilter headerFilter;
+ // Holds headers and filters for header.
+ Headers headers;
/// CommandLine Arguments to pass to clang_compiler.
List<String> compilerOpts;
@@ -135,30 +130,18 @@
Map<String, Specification> _getSpecs() {
return <String, Specification>{
strings.output: Specification<String>(
- description: 'Output file name',
requirement: Requirement.yes,
validator: outputValidator,
extractor: outputExtractor,
extractedResult: (dynamic result) => output = result as String,
),
- strings.headers: Specification<List<String>>(
- description: 'List of C headers to generate bindings of',
+ strings.headers: Specification<Headers>(
requirement: Requirement.yes,
validator: headersValidator,
extractor: headersExtractor,
- extractedResult: (dynamic result) => headers = result as List<String>,
- ),
- strings.headerFilter: Specification<HeaderFilter>(
- description: 'Include/Exclude inclusion headers',
- validator: headerFilterValidator,
- extractor: headerFilterExtractor,
- defaultValue: () => HeaderFilter(),
- extractedResult: (dynamic result) {
- return headerFilter = result as HeaderFilter;
- },
+ extractedResult: (dynamic result) => headers = result as Headers,
),
strings.compilerOpts: Specification<List<String>>(
- description: 'Raw compiler options to pass to clang compiler',
requirement: Requirement.no,
validator: compilerOptsValidator,
extractor: compilerOptsExtractor,
@@ -166,7 +149,6 @@
compilerOpts = result as List<String>,
),
strings.functions: Specification<Declaration>(
- description: 'Filter for functions',
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -176,7 +158,6 @@
},
),
strings.structs: Specification<Declaration>(
- description: 'Filter for Structs',
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -186,7 +167,6 @@
},
),
strings.enums: Specification<Declaration>(
- description: 'Filter for enums',
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -196,7 +176,6 @@
},
),
strings.macros: Specification<Declaration>(
- description: 'Filter for macros',
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
@@ -206,7 +185,6 @@
},
),
strings.sizemap: Specification<Map<int, SupportedNativeType>>(
- description: 'map of types: byte size in int',
validator: sizemapValidator,
extractor: sizemapExtractor,
defaultValue: () => <int, SupportedNativeType>{},
@@ -220,7 +198,6 @@
},
),
strings.sort: Specification<bool>(
- description: 'whether or not to sort the bindings alphabetically',
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
@@ -228,7 +205,6 @@
extractedResult: (dynamic result) => sort = result as bool,
),
strings.useSupportedTypedefs: Specification<bool>(
- description: 'whether or not to directly map supported typedef by name',
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
@@ -237,7 +213,6 @@
useSupportedTypedefs = result as bool,
),
strings.comments: Specification<CommentType>(
- description: 'Type of comment to extract',
requirement: Requirement.no,
validator: commentValidator,
extractor: commentExtractor,
@@ -246,8 +221,6 @@
commentType = result as CommentType,
),
strings.arrayWorkaround: Specification<bool>(
- description:
- 'whether or not to generate workarounds for inline arrays in structures',
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
@@ -255,7 +228,6 @@
extractedResult: (dynamic result) => arrayWorkaround = result as bool,
),
strings.unnamedEnums: Specification<bool>(
- description: 'whether or not to generate constants for unnamed enums.',
requirement: Requirement.no,
validator: booleanValidator,
extractor: booleanExtractor,
@@ -263,7 +235,6 @@
extractedResult: (dynamic result) => unnamedEnums = result as bool,
),
strings.name: Specification<String>(
- description: 'Name of the wrapper class',
requirement: Requirement.prefer,
validator: dartClassNameValidator,
extractor: stringExtractor,
@@ -271,7 +242,6 @@
extractedResult: (dynamic result) => wrapperName = result as String,
),
strings.description: Specification<String>(
- description: 'Doc comment for the wrapper class',
requirement: Requirement.prefer,
validator: nonEmptyStringValidator,
extractor: stringExtractor,
@@ -280,7 +250,6 @@
wrapperDocComment = result as String,
),
strings.preamble: Specification<String>(
- description: 'Raw header string for the generated file',
requirement: Requirement.no,
validator: nonEmptyStringValidator,
extractor: stringExtractor,
diff --git a/lib/src/config_provider/config_types.dart b/lib/src/config_provider/config_types.dart
index c44a72b..a417a18 100644
--- a/lib/src/config_provider/config_types.dart
+++ b/lib/src/config_provider/config_types.dart
@@ -5,6 +5,7 @@
/// Contains all the neccesary classes required by config.
import 'package:meta/meta.dart';
+import 'package:quiver/pattern.dart' as quiver;
class CommentType {
CommentStyle style;
@@ -30,7 +31,6 @@
///
/// [E] is the return type of the extractedResult.
class Specification<E> {
- final String description;
final bool Function(String name, dynamic value) validator;
final E Function(dynamic map) extractor;
final E Function() defaultValue;
@@ -40,7 +40,6 @@
Specification({
@required this.extractedResult,
- @required this.description,
@required this.validator,
@required this.extractor,
this.defaultValue,
@@ -50,14 +49,46 @@
enum Requirement { yes, prefer, no }
-class HeaderFilter {
- Set<String> includedInclusionHeaders;
- Set<String> excludedInclusionHeaders;
+// Holds headers and filters for header.
+class Headers {
+ /// Path to headers.
+ ///
+ /// This contains all the headers, after extraction from Globs.
+ List<String> entryPoints = [];
- HeaderFilter({
- this.includedInclusionHeaders = const {},
- this.excludedInclusionHeaders = const {},
+ /// Include filter for headers.
+ HeaderIncludeFilter includeFilter = GlobHeaderFilter();
+
+ Headers({this.entryPoints, this.includeFilter});
+}
+
+abstract class HeaderIncludeFilter {
+ bool shouldInclude(String headerSourceFile);
+}
+
+class GlobHeaderFilter extends HeaderIncludeFilter {
+ List<quiver.Glob> includeGlobs = [];
+
+ GlobHeaderFilter({
+ this.includeGlobs,
});
+
+ @override
+ bool shouldInclude(String header) {
+ // Return true if header was included.
+ for (final globPattern in includeGlobs) {
+ if (quiver.matchesFull(globPattern, header)) {
+ return true;
+ }
+ }
+
+ // If any includedInclusionHeaders is provided, return false.
+ if (includeGlobs.isNotEmpty) {
+ return false;
+ } else {
+ return true;
+ }
+ }
}
/// A generic declaration config.
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 5170e5f..d6d08cf 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -9,6 +9,7 @@
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;
import 'package:yaml/yaml.dart';
+import 'package:quiver/pattern.dart' as quiver;
import '../strings.dart' as strings;
import 'config_types.dart';
@@ -24,16 +25,19 @@
}
}
+/// Checks if type of value is [T], logs an error if it's not.
+bool checkType<T>(String key, dynamic value) {
+ if (value is! T) {
+ _logger.severe("Expected value of key '$key' to be of type '${T}'.");
+ return false;
+ }
+ return true;
+}
+
bool booleanExtractor(dynamic value) => value as bool;
-bool booleanValidator(String name, dynamic value) {
- if (value is! bool) {
- _logger.severe("Expected value of key '$name' to be a bool.");
- return false;
- } else {
- return true;
- }
-}
+bool booleanValidator(String name, dynamic value) =>
+ checkType<bool>(name, value);
Map<int, SupportedNativeType> sizemapExtractor(dynamic yamlConfig) {
final resultMap = <int, SupportedNativeType>{};
@@ -52,8 +56,7 @@
}
bool sizemapValidator(String name, dynamic yamlConfig) {
- if (yamlConfig is! YamlMap) {
- _logger.severe("Expected value of key '$name' to be a Map.");
+ if (!checkType<YamlMap>(name, yamlConfig)) {
return false;
}
for (final key in (yamlConfig as YamlMap).keys) {
@@ -68,71 +71,65 @@
List<String> compilerOptsExtractor(dynamic value) =>
(value as String)?.split(' ');
-bool compilerOptsValidator(String name, dynamic value) {
- if (value is! String) {
- _logger.severe("Expected value of key '$name' to be a string.");
- return false;
- } else {
- return true;
- }
-}
+bool compilerOptsValidator(String name, dynamic value) =>
+ checkType<String>(name, value);
-HeaderFilter headerFilterExtractor(dynamic yamlConfig) {
- final includedInclusionHeaders = <String>{};
- final excludedInclusionHeaders = <String>{};
-
- final headerFilter = yamlConfig as YamlMap;
- if (headerFilter != null) {
- // Add include/excluded header-filter from Yaml.
- final include = headerFilter[strings.include] as YamlList;
- include?.cast<String>()?.forEach(includedInclusionHeaders.add);
-
- final exclude = headerFilter[strings.exclude] as YamlList;
- exclude?.cast<String>()?.forEach(excludedInclusionHeaders.add);
- }
-
- return HeaderFilter(
- includedInclusionHeaders: includedInclusionHeaders,
- excludedInclusionHeaders: excludedInclusionHeaders,
- );
-}
-
-bool headerFilterValidator(String name, dynamic value) {
- if (value is! YamlMap) {
- _logger.severe("Expected value of key '$name' to be a Map.");
- return false;
- } else {
- return true;
- }
-}
-
-List<String> headersExtractor(dynamic yamlConfig) {
- final headers = <String>[];
- for (final h in (yamlConfig as YamlList)) {
- final headerGlob = h as String;
- // Add file directly to header if it's not a Glob but a File.
- if (File(headerGlob).existsSync()) {
- final osSpecificPath = _replaceSeparators(headerGlob);
- headers.add(osSpecificPath);
- _logger.fine('Adding header/file: $headerGlob');
- } else {
- final glob = Glob(headerGlob);
- for (final file in glob.listSync(followLinks: true)) {
- final fixedPath = _replaceSeparators(file.path);
- headers.add(fixedPath);
- _logger.fine('Adding header/file: ${fixedPath}');
+Headers headersExtractor(dynamic yamlConfig) {
+ final entryPoints = <String>[];
+ final includeGlobs = <quiver.Glob>[];
+ for (final key in (yamlConfig as YamlMap).keys) {
+ if (key == strings.entryPoints) {
+ for (final h in (yamlConfig[key] as YamlList)) {
+ final headerGlob = h as String;
+ // Add file directly to header if it's not a Glob but a File.
+ if (File(headerGlob).existsSync()) {
+ final osSpecificPath = _replaceSeparators(headerGlob);
+ entryPoints.add(osSpecificPath);
+ _logger.fine('Adding header/file: $headerGlob');
+ } else {
+ final glob = Glob(headerGlob);
+ for (final file in glob.listSync(followLinks: true)) {
+ final fixedPath = _replaceSeparators(file.path);
+ entryPoints.add(fixedPath);
+ _logger.fine('Adding header/file: ${fixedPath}');
+ }
+ }
+ }
+ }
+ if (key == strings.includeDirectives) {
+ for (final h in (yamlConfig[key] as YamlList)) {
+ final headerGlob = h as String;
+ includeGlobs.add(quiver.Glob(headerGlob));
}
}
}
- return headers;
+ return Headers(
+ entryPoints: entryPoints,
+ includeFilter: GlobHeaderFilter(
+ includeGlobs: includeGlobs,
+ ),
+ );
}
bool headersValidator(String name, dynamic value) {
- if (value is! YamlList) {
- _logger.severe(
- "Expected value of key '${strings.headers}' to be a List of String.");
+ if (!checkType<YamlMap>(name, value)) {
+ return false;
+ }
+ if (!(value as YamlMap).containsKey(strings.entryPoints)) {
+ _logger.severe("Expected '$name -> ${strings.entryPoints}' to be a Map.");
return false;
} else {
+ for (final key in (value as YamlMap).keys) {
+ if (key == strings.entryPoints || key == strings.includeDirectives) {
+ if (!checkType<YamlList>(key as String, value[key])) {
+ _logger.severe("Expected '$name -> $key' to be a Map.");
+ return false;
+ }
+ } else {
+ _logger.severe("Unknown key '$key' in '$name'.");
+ return false;
+ }
+ }
return true;
}
}
@@ -140,8 +137,7 @@
String libclangDylibExtractor(dynamic value) => getDylibPath(value as String);
bool libclangDylibValidator(String name, dynamic value) {
- if (value is! String) {
- _logger.severe("Expected value of key '$name' to be a string.");
+ if (!checkType<String>(name, value)) {
return false;
} else {
final dylibPath = getDylibPath(value as String);
@@ -170,14 +166,8 @@
String outputExtractor(dynamic value) => _replaceSeparators(value as String);
-bool outputValidator(String name, dynamic value) {
- if (value is String) {
- return true;
- } else {
- _logger.severe("Expected value of key '$name' to be a String.");
- return false;
- }
-}
+bool outputValidator(String name, dynamic value) =>
+ checkType<String>(name, value);
Declaration declarationConfigExtractor(dynamic yamlMap) {
List<String> includeMatchers, includeFull, excludeMatchers, excludeFull;
diff --git a/lib/src/header_parser/includer.dart b/lib/src/header_parser/includer.dart
index b00fa4f..c17b13e 100644
--- a/lib/src/header_parser/includer.dart
+++ b/lib/src/header_parser/includer.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:ffigen/src/code_generator.dart';
-import 'package:path/path.dart' as p;
import 'data.dart';
/// Utility functions to check whether a binding should be parsed or not
@@ -58,7 +57,10 @@
}
}
-/// True if a cursor should be included based on header-filter, use for root
+/// Cache for headers.
+final _headerCache = <String, bool>{};
+
+/// True if a cursor should be included based on headers config, used on root
/// declarations.
bool shouldIncludeRootCursor(String sourceFile) {
// Handle null in case of system headers or macros.
@@ -66,22 +68,13 @@
return false;
}
- final name = p.basename(sourceFile);
-
- if (config.headerFilter.excludedInclusionHeaders.contains(name)) {
- return false;
+ // Add header to cache if its not.
+ if (!_headerCache.containsKey(sourceFile)) {
+ _headerCache[sourceFile] =
+ config.headers.includeFilter.shouldInclude(sourceFile);
}
- if (config.headerFilter.includedInclusionHeaders.contains(name)) {
- return true;
- }
-
- // If any includedInclusionHeaders is provided, return false.
- if (config.headerFilter.includedInclusionHeaders.isNotEmpty) {
- return false;
- } else {
- return true;
- }
+ return _headerCache[sourceFile];
}
bool isSeenStruc(String originalName) {
diff --git a/lib/src/header_parser/parser.dart b/lib/src/header_parser/parser.dart
index 6730d22..29a86e5 100644
--- a/lib/src/header_parser/parser.dart
+++ b/lib/src/header_parser/parser.dart
@@ -86,9 +86,9 @@
final bindings = <Binding>[];
// Log all headers for user.
- _logger.info('Input Headers: ${config.headers}');
+ _logger.info('Input Headers: ${config.headers.entryPoints}');
- for (final headerLocation in config.headers) {
+ for (final headerLocation in config.headers.entryPoints) {
_logger.fine('Creating TranslationUnit for header: $headerLocation');
final tu = clang.clang_parseTranslationUnit(
diff --git a/lib/src/header_parser/sub_parsers/macro_parser.dart b/lib/src/header_parser/sub_parsers/macro_parser.dart
index 4da1b04..3971daf 100644
--- a/lib/src/header_parser/sub_parsers/macro_parser.dart
+++ b/lib/src/header_parser/sub_parsers/macro_parser.dart
@@ -195,7 +195,7 @@
// Write file contents.
final sb = StringBuffer();
- for (final h in config.headers) {
+ for (final h in config.headers.entryPoints) {
sb.writeln('#include "$h"');
}
diff --git a/lib/src/header_parser/translation_unit_parser.dart b/lib/src/header_parser/translation_unit_parser.dart
index 4723fe4..4c1f36c 100644
--- a/lib/src/header_parser/translation_unit_parser.dart
+++ b/lib/src/header_parser/translation_unit_parser.dart
@@ -64,7 +64,7 @@
}
} else {
_logger.finest(
- 'rootCursorVisitor:(excluded in header-filter) ${cursor.completeStringRepr()}');
+ 'rootCursorVisitor:(not included) ${cursor.completeStringRepr()}');
}
cursor.dispose();
diff --git a/lib/src/strings.dart b/lib/src/strings.dart
index cfa1f5d..6196075 100644
--- a/lib/src/strings.dart
+++ b/lib/src/strings.dart
@@ -27,10 +27,14 @@
const ffigenFolderName = 'ffigen';
const output = 'output';
+
const headers = 'headers';
-const headerFilter = 'header-filter';
+
+// Sub-fields of headers
+const entryPoints = 'entry-points';
+const includeDirectives = 'include-directives';
+
const compilerOpts = 'compiler-opts';
-const filters = 'filters';
// Declarations.
const functions = 'functions';
diff --git a/pubspec.yaml b/pubspec.yaml
index fb8ad12..3151c7d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
name: ffigen
-version: 0.1.5
+version: 0.2.0-dev
homepage: https://github.com/dart-lang/ffigen
description: Experimental generator for FFI bindings, using LibClang to parse C/C++ header files.
@@ -18,6 +18,7 @@
logging: ^0.11.4
glob: ^1.2.0
path: ^1.7.0
+ quiver: ^2.1.3
dev_dependencies:
pedantic: ^1.9.2
diff --git a/test/example_tests/cjson_example_test.dart b/test/example_tests/cjson_example_test.dart
new file mode 100644
index 0000000..b4093a8
--- /dev/null
+++ b/test/example_tests/cjson_example_test.dart
@@ -0,0 +1,40 @@
+// 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 'package:ffigen/src/header_parser.dart';
+import 'package:logging/logging.dart';
+import 'package:yaml/yaml.dart';
+import 'package:ffigen/src/config_provider/config.dart';
+import 'package:ffigen/src/strings.dart' as strings;
+import 'package:test/test.dart';
+
+import '../test_utils.dart';
+
+void main() {
+ group('cjson_example_test', () {
+ setUpAll(() {
+ logWarnings(Level.SEVERE);
+ });
+ test('c_json', () {
+ final config = Config.fromYaml(loadYaml('''
+${strings.output}: 'cjson_generated_bindings.dart'
+${strings.name}: 'CJson'
+${strings.description}: 'Holds bindings to cJSON.'
+${strings.headers}:
+ ${strings.entryPoints}:
+ - 'third_party/cjson_library/cJSON.h'
+ ${strings.includeDirectives}:
+ - '**cJSON.h'
+${strings.comments}: false
+''') as YamlMap);
+ final library = parse(config);
+
+ matchLibraryWithExpected(
+ library,
+ ['test', 'debug_generated', 'c_json.dart'],
+ ['example', 'c_json', config.output],
+ );
+ });
+ });
+}
diff --git a/test/example_tests/libclang_example_test.dart b/test/example_tests/libclang_example_test.dart
new file mode 100644
index 0000000..761dddc
--- /dev/null
+++ b/test/example_tests/libclang_example_test.dart
@@ -0,0 +1,65 @@
+// 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 'package:ffigen/src/header_parser.dart';
+import 'package:logging/logging.dart';
+import 'package:yaml/yaml.dart';
+import 'package:ffigen/src/config_provider/config.dart';
+import 'package:ffigen/src/strings.dart' as strings;
+import 'package:test/test.dart';
+
+import '../test_utils.dart';
+
+void main() {
+ group('example_test', () {
+ setUpAll(() {
+ logWarnings(Level.SEVERE);
+ });
+ test('libclang-example', () {
+ final config = Config.fromYaml(loadYaml('''
+${strings.output}: 'generated_bindings.dart'
+${strings.sort}: true
+${strings.headers}:
+ ${strings.entryPoints}:
+ - third_party/libclang/include/clang-c/Index.h
+ ${strings.include}-directives:
+ - '**CXString.h'
+ - '**Index.h'
+
+${strings.compilerOpts}: '-I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -IC:\Progra~1\LLVM\include -I/usr/local/opt/llvm/include/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -Wno-nullability-completeness'
+${strings.functions}:
+ ${strings.include}:
+ ${strings.matches}:
+ - 'clang_.*'
+${strings.structs}:
+ ${strings.include}:
+ ${strings.matches}:
+ - 'CX.*'
+${strings.enums}:
+ ${strings.include}:
+ ${strings.names}:
+ - 'CXTypeKind'
+ - 'CXGlobalOptFlags'
+
+${strings.name}: 'LibClang'
+${strings.description}: 'Holds bindings to LibClang.'
+${strings.arrayWorkaround}: true
+${strings.preamble}: |
+ /// AUTO GENERATED FILE, DO NOT EDIT.
+ ///
+ /// Generated by `package:ffigen`.
+${strings.comments}:
+ ${strings.style}: ${strings.doxygen}
+ ${strings.length}: ${strings.full}
+''') as YamlMap);
+ final library = parse(config);
+
+ matchLibraryWithExpected(
+ library,
+ ['test', 'debug_generated', 'libclang-example.dart'],
+ ['example', 'libclang-example', config.output],
+ );
+ });
+ });
+}
diff --git a/test/example_tests/simple_example_test.dart b/test/example_tests/simple_example_test.dart
new file mode 100644
index 0000000..5b22de7
--- /dev/null
+++ b/test/example_tests/simple_example_test.dart
@@ -0,0 +1,38 @@
+// 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 'package:ffigen/src/header_parser.dart';
+import 'package:logging/logging.dart';
+import 'package:yaml/yaml.dart';
+import 'package:ffigen/src/config_provider/config.dart';
+import 'package:ffigen/src/strings.dart' as strings;
+import 'package:test/test.dart';
+
+import '../test_utils.dart';
+
+void main() {
+ group('simple_example_test', () {
+ setUpAll(() {
+ logWarnings(Level.SEVERE);
+ });
+
+ test('simple', () {
+ final config = Config.fromYaml(loadYaml('''
+${strings.name}: NativeLibrary
+${strings.description}: Bindings to `headers/example.h`.
+${strings.output}: 'generated_bindings.dart'
+${strings.headers}:
+ ${strings.entryPoints}:
+ - 'example/simple/headers/example.h'
+''') as YamlMap);
+ final library = parse(config);
+
+ matchLibraryWithExpected(
+ library,
+ ['test', 'debug_generated', 'simple.dart'],
+ ['example', 'simple', config.output],
+ );
+ });
+ });
+}
diff --git a/test/header_parser_tests/function_n_struct_test.dart b/test/header_parser_tests/function_n_struct_test.dart
index 872bf1b..b3da1d8 100644
--- a/test/header_parser_tests/function_n_struct_test.dart
+++ b/test/header_parser_tests/function_n_struct_test.dart
@@ -26,7 +26,8 @@
${strings.output}: 'unused'
${strings.headers}:
- - 'test/header_parser_tests/function_n_struct.h'
+ ${strings.entryPoints}:
+ - 'test/header_parser_tests/function_n_struct.h'
''') as yaml.YamlMap),
);
});
diff --git a/test/header_parser_tests/functions_test.dart b/test/header_parser_tests/functions_test.dart
index c88fd55..aba98e6 100644
--- a/test/header_parser_tests/functions_test.dart
+++ b/test/header_parser_tests/functions_test.dart
@@ -25,10 +25,10 @@
${strings.output}: 'unused'
${strings.headers}:
- - 'test/header_parser_tests/functions.h'
-${strings.headerFilter}:
- ${strings.include}:
- - 'functions.h'
+ ${strings.entryPoints}:
+ - 'test/header_parser_tests/functions.h'
+ ${strings.includeDirectives}:
+ - '**functions.h'
''') as yaml.YamlMap),
);
});
diff --git a/test/header_parser_tests/macros_test.dart b/test/header_parser_tests/macros_test.dart
index b912f78..74bbcfc 100644
--- a/test/header_parser_tests/macros_test.dart
+++ b/test/header_parser_tests/macros_test.dart
@@ -25,10 +25,8 @@
${strings.description}: 'Macros Test'
${strings.output}: 'unused'
${strings.headers}:
- - 'test/header_parser_tests/macros.h'
-${strings.headerFilter}:
- ${strings.include}:
- - 'macros.h'
+ ${strings.entryPoints}:
+ - 'test/header_parser_tests/macros.h'
''') as yaml.YamlMap),
);
});
diff --git a/test/header_parser_tests/nested_parsing_test.dart b/test/header_parser_tests/nested_parsing_test.dart
index 0736231..ed1bacf 100644
--- a/test/header_parser_tests/nested_parsing_test.dart
+++ b/test/header_parser_tests/nested_parsing_test.dart
@@ -25,14 +25,12 @@
${strings.output}: 'unused'
${strings.headers}:
- - 'test/header_parser_tests/nested_parsing.h'
-structs:
- include:
- names:
- - Struct1
-${strings.headerFilter}:
+ ${strings.entryPoints}:
+ - 'test/header_parser_tests/nested_parsing.h'
+${strings.structs}:
${strings.include}:
- - 'nested_parsing.h'
+ ${strings.names}:
+ - Struct1
''') as yaml.YamlMap),
);
});
diff --git a/test/header_parser_tests/unnamed_enums_test.dart b/test/header_parser_tests/unnamed_enums_test.dart
index 7c07602..a7ee4c4 100644
--- a/test/header_parser_tests/unnamed_enums_test.dart
+++ b/test/header_parser_tests/unnamed_enums_test.dart
@@ -24,10 +24,8 @@
${strings.description}: 'Unnamed Enums Test'
${strings.output}: 'unused'
${strings.headers}:
- - 'test/header_parser_tests/unnamed_enums.h'
-${strings.headerFilter}:
- ${strings.include}:
- - 'unnamed_enums.h'
+ ${strings.entryPoints}:
+ - 'test/header_parser_tests/unnamed_enums.h'
${strings.enums}:
${strings.exclude}:
${strings.names}:
diff --git a/test/large_integration_tests/large_test.dart b/test/large_integration_tests/large_test.dart
index 542b3ce..b18f52b 100644
--- a/test/large_integration_tests/large_test.dart
+++ b/test/large_integration_tests/large_test.dart
@@ -2,8 +2,6 @@
// 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:ffigen/src/header_parser.dart';
import 'package:logging/logging.dart';
import 'package:yaml/yaml.dart';
@@ -30,36 +28,24 @@
${strings.style}: ${strings.doxygen}
${strings.length}: ${strings.brief}
${strings.headers}:
- - third_party/libclang/include/clang-c/Index.h
-${strings.headerFilter}:
- include:
- - 'BuildSystem.h'
- - 'CXCompilationDatabase.h'
- - 'CXErrorCode.h'
- - 'CXString.h'
- - 'Documentation.h'
- - 'FataErrorHandler.h'
- - 'Index.h'
+ ${strings.entryPoints}:
+ - third_party/libclang/include/clang-c/Index.h
+ ${strings.includeDirectives}:
+ - '**BuildSystem.h'
+ - '**CXCompilationDatabase.h'
+ - '**CXErrorCode.h'
+ - '**CXString.h'
+ - '**Documentation.h'
+ - '**FataErrorHandler.h'
+ - '**Index.h'
''') as YamlMap);
final library = parse(config);
- final file = File(
- path.join('test', 'debug_generated', 'large_test_libclang.dart'),
- );
- library.generateFile(file);
- try {
- final actual = file.readAsStringSync();
- final expected = File(path.join('test', 'large_integration_tests',
- '_expected_libclang_bindings.dart'))
- .readAsStringSync();
- expect(actual, expected);
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- print('Failed test: Debug generated file: ${file.absolute?.path}');
- rethrow;
- }
+ matchLibraryWithExpected(
+ library,
+ ['test', 'debug_generated', 'large_test_libclang.dart'],
+ ['test', 'large_integration_tests', '_expected_libclang_bindings.dart'],
+ );
});
test('CJSON test', () {
@@ -71,30 +57,18 @@
${strings.length}: ${strings.full}
${strings.arrayWorkaround}: true
${strings.headers}:
- - third_party/cjson_library/cJSON.h
-${strings.headerFilter}:
- include:
- - 'cJSON.h'
+ ${strings.entryPoints}:
+ - third_party/cjson_library/cJSON.h
+ ${strings.includeDirectives}:
+ - '**cJSON.h'
''') as YamlMap);
final library = parse(config);
- final file = File(
- path.join('test', 'debug_generated', 'large_test_cjson.dart'),
- );
- library.generateFile(file);
- try {
- final actual = file.readAsStringSync();
- final expected = File(path.join('test', 'large_integration_tests',
- '_expected_cjson_bindings.dart'))
- .readAsStringSync();
- expect(actual, expected);
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- print('Failed test: Debug generated file: ${file.absolute?.path}');
- rethrow;
- }
+ matchLibraryWithExpected(
+ library,
+ ['test', 'debug_generated', 'large_test_cjson.dart'],
+ ['test', 'large_integration_tests', '_expected_cjson_bindings.dart'],
+ );
});
test('SQLite test', () {
@@ -109,10 +83,10 @@
${strings.style}: ${strings.any}
${strings.length}: ${strings.full}
${strings.headers}:
- - third_party/sqlite/sqlite3.h
-${strings.headerFilter}:
- ${strings.include}:
- - 'sqlite3.h'
+ ${strings.entryPoints}:
+ - third_party/sqlite/sqlite3.h
+ ${strings.includeDirectives}:
+ - '**sqlite3.h'
${strings.functions}:
${strings.exclude}:
${strings.names}:
@@ -121,24 +95,12 @@
- sqlite3_str_vappendf
''') as YamlMap);
final library = parse(config);
- final file = File(
- path.join('test', 'debug_generated', 'large_test_sqlite.dart'),
- );
- library.generateFile(file);
- try {
- final actual = file.readAsStringSync();
- final expected = File(path.join('test', 'large_integration_tests',
- '_expected_sqlite_bindings.dart'))
- .readAsStringSync();
- expect(actual, expected);
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- print('Failed test: Debug generated file: ${file.absolute?.path}');
- rethrow;
- }
+ matchLibraryWithExpected(
+ library,
+ ['test', 'debug_generated', 'large_test_sqlite.dart'],
+ ['test', 'large_integration_tests', '_expected_sqlite_bindings.dart'],
+ );
});
});
}
diff --git a/test/native_test/config.yaml b/test/native_test/config.yaml
index 479988d..a81d932 100644
--- a/test/native_test/config.yaml
+++ b/test/native_test/config.yaml
@@ -3,14 +3,16 @@
# BSD-style license that can be found in the LICENSE file.
# =================== GENERATING TEST BINDINGS ==================
-# dart ../../bin/ffigen.dart --config config.yaml
+# pub run ffigen --config test/native_test/config.yaml
# ===============================================================
-output: 'native_test_bindings.dart'
+name: NativeLibrary
+description: 'Native tests.'
+output: 'test/native_test/native_test_bindings.dart'
sort: true
headers:
- - 'native_test.c'
-header-filter:
- include:
- - 'native_test.c'
+ entry-points:
+ - 'test/native_test/native_test.c'
+ include-directives:
+ - '**native_test.c'
array-workaround: true
diff --git a/test/native_test/native_test.dart b/test/native_test/native_test.dart
index 0cec0cc..63d1824 100644
--- a/test/native_test/native_test.dart
+++ b/test/native_test/native_test.dart
@@ -6,12 +6,15 @@
import 'dart:io';
import 'dart:math';
+import 'package:ffigen/ffigen.dart';
+import 'package:path/path.dart' as path;
import 'package:test/test.dart';
-
+import 'package:yaml/yaml.dart';
import '../test_utils.dart';
-import 'native_test_bindings.dart' as bindings;
+import 'native_test_bindings.dart';
void main() {
+ NativeLibrary bindings;
group('native_test', () {
setUpAll(() {
logWarnings();
@@ -21,9 +24,32 @@
} else if (Platform.isWindows) {
dylibName = r'test\native_test\native_test.dll';
}
- bindings.init(
+ bindings = NativeLibrary(
DynamicLibrary.open(File(dylibName).absolute?.path ?? dylibName));
});
+
+ test('generate_bindings', () {
+ final config = Config.fromYaml(loadYaml(
+ File(path.join('test', 'native_test', 'config.yaml'))
+ .readAsStringSync()) as YamlMap);
+ final library = parse(config);
+ final file = File(
+ path.join('test', 'debug_generated', 'native_test_bindings.dart'),
+ );
+ library.generateFile(file);
+
+ try {
+ final actual = file.readAsStringSync();
+ final expected = File(path.join(config.output)).readAsStringSync();
+ expect(actual, expected);
+ if (file.existsSync()) {
+ file.delete();
+ }
+ } catch (e) {
+ print('Failed test: Debug generated file: ${file.absolute?.path}');
+ rethrow;
+ }
+ });
test('uint8_t', () {
expect(bindings.Function1Uint8(pow(2, 8).toInt()), 42);
});
diff --git a/test/native_test/native_test_bindings.dart b/test/native_test/native_test_bindings.dart
index a49d622..fe4c945 100644
--- a/test/native_test/native_test_bindings.dart
+++ b/test/native_test/native_test_bindings.dart
@@ -3,244 +3,181 @@
/// Generated by `package:ffigen`.
import 'dart:ffi' as ffi;
-/// Holds the Dynamic library.
-ffi.DynamicLibrary _dylib;
+/// Native tests.
+class NativeLibrary {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
-/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
- _dylib = dylib;
+ /// The symbols are looked up in [dynamicLibrary].
+ NativeLibrary(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ int Function1Uint8(
+ int x,
+ ) {
+ _Function1Uint8 ??=
+ _dylib.lookupFunction<_c_Function1Uint8, _dart_Function1Uint8>(
+ 'Function1Uint8');
+ return _Function1Uint8(
+ x,
+ );
+ }
+
+ _dart_Function1Uint8 _Function1Uint8;
+
+ int Function1Uint16(
+ int x,
+ ) {
+ _Function1Uint16 ??=
+ _dylib.lookupFunction<_c_Function1Uint16, _dart_Function1Uint16>(
+ 'Function1Uint16');
+ return _Function1Uint16(
+ x,
+ );
+ }
+
+ _dart_Function1Uint16 _Function1Uint16;
+
+ int Function1Uint32(
+ int x,
+ ) {
+ _Function1Uint32 ??=
+ _dylib.lookupFunction<_c_Function1Uint32, _dart_Function1Uint32>(
+ 'Function1Uint32');
+ return _Function1Uint32(
+ x,
+ );
+ }
+
+ _dart_Function1Uint32 _Function1Uint32;
+
+ int Function1Uint64(
+ int x,
+ ) {
+ _Function1Uint64 ??=
+ _dylib.lookupFunction<_c_Function1Uint64, _dart_Function1Uint64>(
+ 'Function1Uint64');
+ return _Function1Uint64(
+ x,
+ );
+ }
+
+ _dart_Function1Uint64 _Function1Uint64;
+
+ int Function1Int8(
+ int x,
+ ) {
+ _Function1Int8 ??= _dylib
+ .lookupFunction<_c_Function1Int8, _dart_Function1Int8>('Function1Int8');
+ return _Function1Int8(
+ x,
+ );
+ }
+
+ _dart_Function1Int8 _Function1Int8;
+
+ int Function1Int16(
+ int x,
+ ) {
+ _Function1Int16 ??=
+ _dylib.lookupFunction<_c_Function1Int16, _dart_Function1Int16>(
+ 'Function1Int16');
+ return _Function1Int16(
+ x,
+ );
+ }
+
+ _dart_Function1Int16 _Function1Int16;
+
+ int Function1Int32(
+ int x,
+ ) {
+ _Function1Int32 ??=
+ _dylib.lookupFunction<_c_Function1Int32, _dart_Function1Int32>(
+ 'Function1Int32');
+ return _Function1Int32(
+ x,
+ );
+ }
+
+ _dart_Function1Int32 _Function1Int32;
+
+ int Function1Int64(
+ int x,
+ ) {
+ _Function1Int64 ??=
+ _dylib.lookupFunction<_c_Function1Int64, _dart_Function1Int64>(
+ 'Function1Int64');
+ return _Function1Int64(
+ x,
+ );
+ }
+
+ _dart_Function1Int64 _Function1Int64;
+
+ int Function1IntPtr(
+ int x,
+ ) {
+ _Function1IntPtr ??=
+ _dylib.lookupFunction<_c_Function1IntPtr, _dart_Function1IntPtr>(
+ 'Function1IntPtr');
+ return _Function1IntPtr(
+ x,
+ );
+ }
+
+ _dart_Function1IntPtr _Function1IntPtr;
+
+ double Function1Float(
+ double x,
+ ) {
+ _Function1Float ??=
+ _dylib.lookupFunction<_c_Function1Float, _dart_Function1Float>(
+ 'Function1Float');
+ return _Function1Float(
+ x,
+ );
+ }
+
+ _dart_Function1Float _Function1Float;
+
+ double Function1Double(
+ double x,
+ ) {
+ _Function1Double ??=
+ _dylib.lookupFunction<_c_Function1Double, _dart_Function1Double>(
+ 'Function1Double');
+ return _Function1Double(
+ x,
+ );
+ }
+
+ _dart_Function1Double _Function1Double;
+
+ ffi.Pointer<Struct1> getStruct1() {
+ _getStruct1 ??=
+ _dylib.lookupFunction<_c_getStruct1, _dart_getStruct1>('getStruct1');
+ return _getStruct1();
+ }
+
+ _dart_getStruct1 _getStruct1;
}
-double Function1Double(
- double x,
-) {
- return _Function1Double(
- x,
- );
-}
-
-final _dart_Function1Double _Function1Double =
- _dylib.lookupFunction<_c_Function1Double, _dart_Function1Double>(
- 'Function1Double');
-
-typedef _c_Function1Double = ffi.Double Function(
- ffi.Double x,
-);
-
-typedef _dart_Function1Double = double Function(
- double x,
-);
-
-double Function1Float(
- double x,
-) {
- return _Function1Float(
- x,
- );
-}
-
-final _dart_Function1Float _Function1Float = _dylib
- .lookupFunction<_c_Function1Float, _dart_Function1Float>('Function1Float');
-
-typedef _c_Function1Float = ffi.Float Function(
- ffi.Float x,
-);
-
-typedef _dart_Function1Float = double Function(
- double x,
-);
-
-int Function1Int16(
- int x,
-) {
- return _Function1Int16(
- x,
- );
-}
-
-final _dart_Function1Int16 _Function1Int16 = _dylib
- .lookupFunction<_c_Function1Int16, _dart_Function1Int16>('Function1Int16');
-
-typedef _c_Function1Int16 = ffi.Int16 Function(
- ffi.Int16 x,
-);
-
-typedef _dart_Function1Int16 = int Function(
- int x,
-);
-
-int Function1Int32(
- int x,
-) {
- return _Function1Int32(
- x,
- );
-}
-
-final _dart_Function1Int32 _Function1Int32 = _dylib
- .lookupFunction<_c_Function1Int32, _dart_Function1Int32>('Function1Int32');
-
-typedef _c_Function1Int32 = ffi.Int32 Function(
- ffi.Int32 x,
-);
-
-typedef _dart_Function1Int32 = int Function(
- int x,
-);
-
-int Function1Int64(
- int x,
-) {
- return _Function1Int64(
- x,
- );
-}
-
-final _dart_Function1Int64 _Function1Int64 = _dylib
- .lookupFunction<_c_Function1Int64, _dart_Function1Int64>('Function1Int64');
-
-typedef _c_Function1Int64 = ffi.Int64 Function(
- ffi.Int64 x,
-);
-
-typedef _dart_Function1Int64 = int Function(
- int x,
-);
-
-int Function1Int8(
- int x,
-) {
- return _Function1Int8(
- x,
- );
-}
-
-final _dart_Function1Int8 _Function1Int8 = _dylib
- .lookupFunction<_c_Function1Int8, _dart_Function1Int8>('Function1Int8');
-
-typedef _c_Function1Int8 = ffi.Int8 Function(
- ffi.Int8 x,
-);
-
-typedef _dart_Function1Int8 = int Function(
- int x,
-);
-
-int Function1IntPtr(
- int x,
-) {
- return _Function1IntPtr(
- x,
- );
-}
-
-final _dart_Function1IntPtr _Function1IntPtr =
- _dylib.lookupFunction<_c_Function1IntPtr, _dart_Function1IntPtr>(
- 'Function1IntPtr');
-
-typedef _c_Function1IntPtr = ffi.IntPtr Function(
- ffi.IntPtr x,
-);
-
-typedef _dart_Function1IntPtr = int Function(
- int x,
-);
-
-int Function1Uint16(
- int x,
-) {
- return _Function1Uint16(
- x,
- );
-}
-
-final _dart_Function1Uint16 _Function1Uint16 =
- _dylib.lookupFunction<_c_Function1Uint16, _dart_Function1Uint16>(
- 'Function1Uint16');
-
-typedef _c_Function1Uint16 = ffi.Uint16 Function(
- ffi.Uint16 x,
-);
-
-typedef _dart_Function1Uint16 = int Function(
- int x,
-);
-
-int Function1Uint32(
- int x,
-) {
- return _Function1Uint32(
- x,
- );
-}
-
-final _dart_Function1Uint32 _Function1Uint32 =
- _dylib.lookupFunction<_c_Function1Uint32, _dart_Function1Uint32>(
- 'Function1Uint32');
-
-typedef _c_Function1Uint32 = ffi.Uint32 Function(
- ffi.Uint32 x,
-);
-
-typedef _dart_Function1Uint32 = int Function(
- int x,
-);
-
-int Function1Uint64(
- int x,
-) {
- return _Function1Uint64(
- x,
- );
-}
-
-final _dart_Function1Uint64 _Function1Uint64 =
- _dylib.lookupFunction<_c_Function1Uint64, _dart_Function1Uint64>(
- 'Function1Uint64');
-
-typedef _c_Function1Uint64 = ffi.Uint64 Function(
- ffi.Uint64 x,
-);
-
-typedef _dart_Function1Uint64 = int Function(
- int x,
-);
-
-int Function1Uint8(
- int x,
-) {
- return _Function1Uint8(
- x,
- );
-}
-
-final _dart_Function1Uint8 _Function1Uint8 = _dylib
- .lookupFunction<_c_Function1Uint8, _dart_Function1Uint8>('Function1Uint8');
-
-typedef _c_Function1Uint8 = ffi.Uint8 Function(
- ffi.Uint8 x,
-);
-
-typedef _dart_Function1Uint8 = int Function(
- int x,
-);
-
class Struct1 extends ffi.Struct {
@ffi.Int8()
int a;
@ffi.Int32()
- int _data_item_0;
+ int _unique_data_item_0;
@ffi.Int32()
- int _data_item_1;
+ int _unique_data_item_1;
@ffi.Int32()
- int _data_item_2;
+ int _unique_data_item_2;
@ffi.Int32()
- int _data_item_3;
+ int _unique_data_item_3;
@ffi.Int32()
- int _data_item_4;
+ int _unique_data_item_4;
@ffi.Int32()
- int _data_item_5;
+ int _unique_data_item_5;
/// Helper for array `data`.
ArrayHelper_Struct1_data_level0 get data =>
@@ -321,17 +258,17 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._data_item_0;
+ return _struct._unique_data_item_0;
case 1:
- return _struct._data_item_1;
+ return _struct._unique_data_item_1;
case 2:
- return _struct._data_item_2;
+ return _struct._unique_data_item_2;
case 3:
- return _struct._data_item_3;
+ return _struct._unique_data_item_3;
case 4:
- return _struct._data_item_4;
+ return _struct._unique_data_item_4;
case 5:
- return _struct._data_item_5;
+ return _struct._unique_data_item_5;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -341,22 +278,22 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._data_item_0 = value;
+ _struct._unique_data_item_0 = value;
break;
case 1:
- _struct._data_item_1 = value;
+ _struct._unique_data_item_1 = value;
break;
case 2:
- _struct._data_item_2 = value;
+ _struct._unique_data_item_2 = value;
break;
case 3:
- _struct._data_item_3 = value;
+ _struct._unique_data_item_3 = value;
break;
case 4:
- _struct._data_item_4 = value;
+ _struct._unique_data_item_4 = value;
break;
case 5:
- _struct._data_item_5 = value;
+ _struct._unique_data_item_5 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -364,12 +301,93 @@
}
}
-ffi.Pointer<Struct1> getStruct1() {
- return _getStruct1();
-}
+typedef _c_Function1Uint8 = ffi.Uint8 Function(
+ ffi.Uint8 x,
+);
-final _dart_getStruct1 _getStruct1 =
- _dylib.lookupFunction<_c_getStruct1, _dart_getStruct1>('getStruct1');
+typedef _dart_Function1Uint8 = int Function(
+ int x,
+);
+
+typedef _c_Function1Uint16 = ffi.Uint16 Function(
+ ffi.Uint16 x,
+);
+
+typedef _dart_Function1Uint16 = int Function(
+ int x,
+);
+
+typedef _c_Function1Uint32 = ffi.Uint32 Function(
+ ffi.Uint32 x,
+);
+
+typedef _dart_Function1Uint32 = int Function(
+ int x,
+);
+
+typedef _c_Function1Uint64 = ffi.Uint64 Function(
+ ffi.Uint64 x,
+);
+
+typedef _dart_Function1Uint64 = int Function(
+ int x,
+);
+
+typedef _c_Function1Int8 = ffi.Int8 Function(
+ ffi.Int8 x,
+);
+
+typedef _dart_Function1Int8 = int Function(
+ int x,
+);
+
+typedef _c_Function1Int16 = ffi.Int16 Function(
+ ffi.Int16 x,
+);
+
+typedef _dart_Function1Int16 = int Function(
+ int x,
+);
+
+typedef _c_Function1Int32 = ffi.Int32 Function(
+ ffi.Int32 x,
+);
+
+typedef _dart_Function1Int32 = int Function(
+ int x,
+);
+
+typedef _c_Function1Int64 = ffi.Int64 Function(
+ ffi.Int64 x,
+);
+
+typedef _dart_Function1Int64 = int Function(
+ int x,
+);
+
+typedef _c_Function1IntPtr = ffi.IntPtr Function(
+ ffi.IntPtr x,
+);
+
+typedef _dart_Function1IntPtr = int Function(
+ int x,
+);
+
+typedef _c_Function1Float = ffi.Float Function(
+ ffi.Float x,
+);
+
+typedef _dart_Function1Float = double Function(
+ double x,
+);
+
+typedef _c_Function1Double = ffi.Double Function(
+ ffi.Double x,
+);
+
+typedef _dart_Function1Double = double Function(
+ double x,
+);
typedef _c_getStruct1 = ffi.Pointer<Struct1> Function();
diff --git a/test/prefix_tests/prefix_test.dart b/test/prefix_tests/prefix_test.dart
index ba1e56d..55ebc8a 100644
--- a/test/prefix_tests/prefix_test.dart
+++ b/test/prefix_tests/prefix_test.dart
@@ -33,10 +33,8 @@
${strings.output}: 'unused'
${strings.headers}:
- - 'test/prefix_tests/prefix.h'
-${strings.headerFilter}:
- ${strings.include}:
- - 'prefix.h'
+ ${strings.entryPoints}:
+ - 'test/prefix_tests/prefix.h'
functions:
${strings.prefix}: $functionPrefix
diff --git a/test/test_utils.dart b/test/test_utils.dart
index 8d49c18..0d94d29 100644
--- a/test/test_utils.dart
+++ b/test/test_utils.dart
@@ -2,8 +2,12 @@
// 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:ffigen/src/code_generator.dart';
import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
/// Extracts a binding's string from a library.
@@ -31,6 +35,29 @@
}
}
+/// Generates actual file using library and tests using [expect] with expected
+///
+/// This will not delete the actual debug file incase [expect] throws an error.
+void matchLibraryWithExpected(
+ Library library, List<String> pathForActual, List<String> pathToExpected) {
+ final file = File(
+ path.joinAll(pathForActual),
+ );
+ library.generateFile(file);
+
+ try {
+ final actual = file.readAsStringSync();
+ final expected = File(path.joinAll(pathToExpected)).readAsStringSync();
+ expect(actual, expected);
+ if (file.existsSync()) {
+ file.delete();
+ }
+ } catch (e) {
+ print('Failed test: Debug generated file: ${file.absolute?.path}');
+ rethrow;
+ }
+}
+
class NotFoundException implements Exception {
final String message;
NotFoundException(this.message);
diff --git a/tool/libclang_config.yaml b/tool/libclang_config.yaml
index bc0754c..8526317 100644
--- a/tool/libclang_config.yaml
+++ b/tool/libclang_config.yaml
@@ -15,12 +15,12 @@
sort: true
compiler-opts: '-I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -I/usr/local/opt/llvm/include/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -Wno-nullability-completeness'
headers:
- - 'lib/src/clang_library/wrapper.c'
-header-filter:
- include:
- - wrapper.c
- - Index.h
- - CXString.h
+ entry-points:
+ - 'lib/src/clang_library/wrapper.c'
+ include-directives:
+ - '**wrapper.c'
+ - '**Index.h'
+ - '**CXString.h'
array-workaround: true