diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md
index f95edb7b3..62eb1e0bd 100644
--- a/pkgs/ffigen/CHANGELOG.md
+++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,8 @@
+# 10.1.0
+
+- Add flag and config `ignore-source-errors`. This prevents bindings to be generated
+until source errors are resolved or manually ignore via this flag.
+
## 10.0.0
- Stable release targeting Dart 3.2 using new `dart:ffi` features available
diff --git a/pkgs/ffigen/README.md b/pkgs/ffigen/README.md
index b5845c341..4323f559a 100644
--- a/pkgs/ffigen/README.md
+++ b/pkgs/ffigen/README.md
@@ -452,6 +452,24 @@ use-supported-typedefs: true
```yaml
use-dart-handle: true
```
+
+
+
+
+ ignore-source-errors |
+ Where to ignore compiler warnings/errors in source header files.
+ Default: false
+ |
+
+
+```yaml
+ignore-source-errors: true
+```
+and/or via the command line -
+```bash
+dart run ffigen --ignore-source-errors
+```
+
|
diff --git a/pkgs/ffigen/lib/src/config_provider/config.dart b/pkgs/ffigen/lib/src/config_provider/config.dart
index d47e30e92..f5cd174fb 100644
--- a/pkgs/ffigen/lib/src/config_provider/config.dart
+++ b/pkgs/ffigen/lib/src/config_provider/config.dart
@@ -176,6 +176,14 @@ class Config {
FfiNativeConfig get ffiNativeConfig => _ffiNativeConfig;
late FfiNativeConfig _ffiNativeConfig;
+ /// Where to ignore compiler warnings/errors in source header files.
+ bool get ignoreSourceErrors => _ignoreSourceErrors;
+ set ignoreSourceErrors(bool n) {
+ _ignoreSourceErrors = _ignoreSourceErrors || n;
+ }
+
+ bool _ignoreSourceErrors = false;
+
Config._({required this.filename, required this.packageConfig});
/// Create config from Yaml map.
@@ -285,6 +293,12 @@ class Config {
transform: (node) => headersExtractor(node.value, filename),
result: (node) => _headers = node.value,
)),
+ HeterogeneousMapEntry(
+ key: strings.ignoreSourceErrors,
+ valueConfigSpec: BoolConfigSpec(),
+ defaultValue: (node) => false,
+ resultOrDefault: (node) => ignoreSourceErrors = node.value as bool,
+ ),
HeterogeneousMapEntry(
key: strings.compilerOpts,
valueConfigSpec: OneOfConfigSpec, List>(
diff --git a/pkgs/ffigen/lib/src/executables/ffigen.dart b/pkgs/ffigen/lib/src/executables/ffigen.dart
index c37cb4f85..1c6008592 100644
--- a/pkgs/ffigen/lib/src/executables/ffigen.dart
+++ b/pkgs/ffigen/lib/src/executables/ffigen.dart
@@ -16,6 +16,7 @@ final _logger = Logger('ffigen.ffigen');
final _ansi = Ansi(Ansi.terminalSupportsAnsi);
const compilerOpts = 'compiler-opts';
+const ignoreSourceErrors = 'ignore-source-errors';
const conf = 'config';
const help = 'help';
const verbose = 'verbose';
@@ -87,6 +88,10 @@ Config getConfig(ArgResults result, PackageConfig? packageConfig) {
highPriority: true);
}
+ if (result.wasParsed(ignoreSourceErrors)) {
+ config.ignoreSourceErrors = true;
+ }
+
return config;
}
@@ -158,6 +163,11 @@ ArgResults getArgResults(List args) {
compilerOpts,
help: 'Compiler options for clang. (E.g --$compilerOpts "-I/headers -W")',
);
+ parser.addFlag(
+ ignoreSourceErrors,
+ help: 'Ignore any compiler warnings/errors in source header files',
+ negatable: false,
+ );
ArgResults results;
try {
diff --git a/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart b/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
index d5431a958..1de29c93b 100644
--- a/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
+++ b/pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart
@@ -316,6 +316,21 @@ class Clang {
late final _clang_formatDiagnostic = _clang_formatDiagnosticPtr
.asFunction();
+ /// Determine the severity of the given diagnostic.
+ int clang_getDiagnosticSeverity(
+ CXDiagnostic arg0,
+ ) {
+ return _clang_getDiagnosticSeverity(
+ arg0,
+ );
+ }
+
+ late final _clang_getDiagnosticSeverityPtr =
+ _lookup>(
+ 'clang_getDiagnosticSeverity');
+ late final _clang_getDiagnosticSeverity =
+ _clang_getDiagnosticSeverityPtr.asFunction();
+
/// Same as \c clang_parseTranslationUnit2, but returns
/// the \c CXTranslationUnit instead of an error code. In case of an error this
/// routine returns a \c NULL \c CXTranslationUnit, without further detailed
@@ -1484,6 +1499,29 @@ abstract class CXDiagnosticDisplayOptions {
static const int CXDiagnostic_DisplayCategoryName = 32;
}
+/// Describes the severity of a particular diagnostic.
+abstract class CXDiagnosticSeverity {
+ /// A diagnostic that has been suppressed, e.g., by a command-line
+ /// option.
+ static const int CXDiagnostic_Ignored = 0;
+
+ /// This diagnostic is a note that should be attached to the
+ /// previous (non-note) diagnostic.
+ static const int CXDiagnostic_Note = 1;
+
+ /// This diagnostic indicates suspicious code that may not be
+ /// wrong.
+ static const int CXDiagnostic_Warning = 2;
+
+ /// This diagnostic indicates that the code is ill-formed.
+ static const int CXDiagnostic_Error = 3;
+
+ /// This diagnostic indicates that the code is ill-formed such
+ /// that future parser recovery is unlikely to produce useful
+ /// results.
+ static const int CXDiagnostic_Fatal = 4;
+}
+
/// Flags that control the creation of translation units.
///
/// The enumerators in this enumeration type are meant to be bitwise
@@ -2641,8 +2679,10 @@ abstract class CXChildVisitResult {
/// The visitor should return one of the \c CXChildVisitResult values
/// to direct clang_visitCursorChildren().
typedef CXCursorVisitor
- = ffi.Pointer>;
-typedef CXCursorVisitor_function = ffi.Int32 Function(
+ = ffi.Pointer>;
+typedef CXCursorVisitorFunction = ffi.Int32 Function(
+ CXCursor cursor, CXCursor parent, CXClientData client_data);
+typedef DartCXCursorVisitorFunction = int Function(
CXCursor cursor, CXCursor parent, CXClientData client_data);
/// Opaque pointer representing client data that will be passed through
diff --git a/pkgs/ffigen/lib/src/header_parser/parser.dart b/pkgs/ffigen/lib/src/header_parser/parser.dart
index 5be826fdf..3111fd23e 100644
--- a/pkgs/ffigen/lib/src/header_parser/parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/parser.dart
@@ -4,6 +4,7 @@
import 'dart:ffi';
import 'dart:io';
+import 'dart:math' show max;
import 'package:ffi/ffi.dart';
import 'package:ffigen/src/code_generator.dart';
@@ -22,7 +23,7 @@ import 'utils.dart';
Library parse(Config c) {
initParser(c);
- final bindings = parseToBindings();
+ final bindings = parseToBindings(c);
final library = Library(
bindings: bindings,
@@ -52,7 +53,7 @@ void initParser(Config c) {
}
/// Parses source files and adds generated bindings to [bindings].
-List parseToBindings() {
+List parseToBindings(Config c) {
final index = clang.clang_createIndex(0, 0);
Pointer> clangCmdArgs = nullptr;
@@ -84,6 +85,8 @@ List parseToBindings() {
final tuList = >[];
+ var highestDiagnosticLevel =
+ clang_types.CXDiagnosticSeverity.CXDiagnostic_Ignored;
// Parse all translation units from entry points.
for (final headerLocation in config.headers.entryPoints) {
_logger.fine('Creating TranslationUnit for header: $headerLocation');
@@ -109,10 +112,19 @@ List parseToBindings() {
continue;
}
- logTuDiagnostics(tu, _logger, headerLocation);
+ final diagnosticsLevel = logTuDiagnostics(tu, _logger, headerLocation);
+ highestDiagnosticLevel = max(highestDiagnosticLevel, diagnosticsLevel);
tuList.add(tu);
}
+ if (!config.ignoreSourceErrors &&
+ highestDiagnosticLevel >=
+ clang_types.CXDiagnosticSeverity.CXDiagnostic_Warning) {
+ _logger.severe(
+ "Source headers contains errors. Either resolve them or set flag --ignore-source-errors to generate the bindings.");
+ exit(1);
+ }
+
final tuCursors =
tuList.map((tu) => clang.clang_getTranslationUnitCursor(tu));
diff --git a/pkgs/ffigen/lib/src/header_parser/utils.dart b/pkgs/ffigen/lib/src/header_parser/utils.dart
index f03df3fb5..3945b9665 100644
--- a/pkgs/ffigen/lib/src/header_parser/utils.dart
+++ b/pkgs/ffigen/lib/src/header_parser/utils.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:ffi';
+import 'dart:math' show max;
import 'package:ffi/ffi.dart';
import 'package:ffigen/src/code_generator.dart';
@@ -29,16 +30,21 @@ void visitChildrenResultChecker(int resultCode) {
}
/// Logs the warnings/errors returned by clang for a translation unit.
-void logTuDiagnostics(
+///
+/// Returns the highest [clang_types.CXDiagnosticSeverity] seen, defaults to
+/// [clang_types.CXDiagnosticSeverity.CXDiagnostic_Ignored] if none.
+int logTuDiagnostics(
Pointer tu, Logger logger, String header,
{Level logLevel = Level.SEVERE}) {
+ var result = clang_types.CXDiagnosticSeverity.CXDiagnostic_Ignored;
final total = clang.clang_getNumDiagnostics(tu);
if (total == 0) {
- return;
+ return result;
}
logger.log(logLevel, 'Header $header: Total errors/warnings: $total.');
for (var i = 0; i < total; i++) {
final diag = clang.clang_getDiagnostic(tu, i);
+ result = max(result, clang.clang_getDiagnosticSeverity(diag));
final cxstring = clang.clang_formatDiagnostic(
diag,
clang_types
@@ -50,6 +56,7 @@ void logTuDiagnostics(
logger.log(logLevel, ' ${cxstring.toStringAndDispose()}');
clang.clang_disposeDiagnostic(diag);
}
+ return result;
}
extension CXSourceRangeExt on Pointer {
diff --git a/pkgs/ffigen/lib/src/strings.dart b/pkgs/ffigen/lib/src/strings.dart
index 0918f48e7..b14a51791 100644
--- a/pkgs/ffigen/lib/src/strings.dart
+++ b/pkgs/ffigen/lib/src/strings.dart
@@ -200,6 +200,7 @@ const supportedNativeType_mappings = {
const sort = 'sort';
const useSupportedTypedefs = 'use-supported-typedefs';
const useDartHandle = 'use-dart-handle';
+const ignoreSourceErrors = 'ignore-source-errors';
const comments = 'comments';
// Sub-fields of comments.
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml
index 5504c2afa..e6331b66b 100644
--- a/pkgs/ffigen/pubspec.yaml
+++ b/pkgs/ffigen/pubspec.yaml
@@ -3,7 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
name: ffigen
-version: 10.0.0
+version: 10.1.0
description: >
Generator for FFI bindings, using LibClang to parse C, Objective-C, and Swift
files.
diff --git a/pkgs/ffigen/tool/libclang_config.yaml b/pkgs/ffigen/tool/libclang_config.yaml
index f569afd1c..90a3206b6 100644
--- a/pkgs/ffigen/tool/libclang_config.yaml
+++ b/pkgs/ffigen/tool/libclang_config.yaml
@@ -61,6 +61,7 @@ functions:
- clang_disposeIndex
- clang_getNumDiagnostics
- clang_getDiagnostic
+ - clang_getDiagnosticSeverity
- clang_disposeDiagnostic
- clang_parseTranslationUnit
- clang_disposeTranslationUnit