[ffigen] Added new command-line option `--compiler-opts`. (#192)
diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md index abc7d7b..319671a 100644 --- a/pkgs/ffigen/CHANGELOG.md +++ b/pkgs/ffigen/CHANGELOG.md
@@ -1,3 +1,6 @@ +# 2.2.5 +- Added new command line flag `--compiler-opts` to the command line tool. + # 2.2.4 - Fix `sort: true` not working. - Fix extra `//` or `///` in comments when using `comments -> style`: `full`.
diff --git a/pkgs/ffigen/README.md b/pkgs/ffigen/README.md index 9f516e4..5eb0103 100644 --- a/pkgs/ffigen/README.md +++ b/pkgs/ffigen/README.md
@@ -135,12 +135,18 @@ </tr> <tr> <td>compiler-opts</td> - <td>Pass compiler options to clang.</td> + <td>Pass compiler options to clang. You can also pass + these via the command line tool.</td> <td> ```yaml compiler-opts: '-I/usr/lib/llvm-9/include/' ``` +and/or via the command line - +```bash +dart run ffigen --compiler-opts "-I/headers +-L 'path/to/folder name/file'" +``` </td> </tr> <tr>
diff --git a/pkgs/ffigen/lib/src/config_provider/config.dart b/pkgs/ffigen/lib/src/config_provider/config.dart index cf083df..434137e 100644 --- a/pkgs/ffigen/lib/src/config_provider/config.dart +++ b/pkgs/ffigen/lib/src/config_provider/config.dart
@@ -125,6 +125,17 @@ return configspecs; } + /// Add compiler options for clang. If [highPriority] is true these are added + /// to the front of the list. + void addCompilerOpts(String compilerOpts, {bool highPriority = false}) { + if (highPriority) { + _compilerOpts.insertAll( + 0, compilerOptsToList(compilerOpts)); // Inserts at the front. + } else { + _compilerOpts.addAll(compilerOptsToList(compilerOpts)); + } + } + /// Checks if there are nested [key] in [map]. bool _checkKeyInYaml(List<String> key, YamlMap map) { dynamic last = map;
diff --git a/pkgs/ffigen/lib/src/config_provider/spec_utils.dart b/pkgs/ffigen/lib/src/config_provider/spec_utils.dart index 0351d8c..692f921 100644 --- a/pkgs/ffigen/lib/src/config_provider/spec_utils.dart +++ b/pkgs/ffigen/lib/src/config_provider/spec_utils.dart
@@ -103,8 +103,25 @@ return true; } +final _quoteMatcher = RegExp(r'''^["'](.*)["']$''', dotAll: true); +final _cmdlineArgMatcher = RegExp(r'''['"](\\"|[^"])*?['"]|[^ ]+'''); +List<String> compilerOptsToList(String compilerOpts) { + final list = <String>[]; + _cmdlineArgMatcher.allMatches(compilerOpts).forEach((element) { + var match = element.group(0); + if (match != null) { + if (quiver.matchesFull(_quoteMatcher, match)) { + match = _quoteMatcher.allMatches(match).first.group(1)!; + } + list.add(match); + } + }); + + return list; +} + List<String> compilerOptsExtractor(dynamic value) => - (value as String).split(' '); + compilerOptsToList(value as String); bool compilerOptsValidator(List<String> name, dynamic value) => checkType<String>(name, value);
diff --git a/pkgs/ffigen/lib/src/executables/ffigen.dart b/pkgs/ffigen/lib/src/executables/ffigen.dart index 14d1388..12dd868 100644 --- a/pkgs/ffigen/lib/src/executables/ffigen.dart +++ b/pkgs/ffigen/lib/src/executables/ffigen.dart
@@ -14,6 +14,18 @@ final _logger = Logger('ffigen.ffigen'); final _ansi = Ansi(Ansi.terminalSupportsAnsi); +const compilerOpts = 'compiler-opts'; +const conf = 'config'; +const help = 'help'; +const verbose = 'verbose'; +const pubspecName = 'pubspec.yaml'; +const configKey = 'ffigen'; +const logAll = 'all'; +const logFine = 'fine'; +const logInfo = 'info'; +const logWarning = 'warning'; +const logSevere = 'severe'; + String successPen(String str) { return '${_ansi.green}$str${_ansi.none}'; } @@ -50,19 +62,27 @@ Config getConfig(ArgResults result) { _logger.info('Running in ${Directory.current}'); + Config config; - if (result.wasParsed('config')) { - return getConfigFromCustomYaml(result['config'] as String); + // Parse config from yaml. + if (result.wasParsed(conf)) { + config = getConfigFromCustomYaml(result[conf] as String); } else { - return getConfigFromPubspec(); + config = getConfigFromPubspec(); } + + // Add compiler options from command line. + if (result.wasParsed(compilerOpts)) { + _logger.fine('Passed compiler opts - "${result[compilerOpts]}"'); + config.addCompilerOpts((result[compilerOpts] as String), + highPriority: true); + } + + return config; } /// Extracts configuration from pubspec file. Config getConfigFromPubspec() { - final pubspecName = 'pubspec.yaml'; - final configKey = 'ffigen'; - final pubspecFile = File(pubspecName); if (!pubspecFile.existsSync()) { @@ -107,33 +127,37 @@ parser.addSeparator( 'FFIGEN: Generate dart bindings from C header files\nUsage:'); parser.addOption( - 'config', - help: 'path to Yaml file containing configurations if not in pubspec.yaml', + conf, + help: 'Path to Yaml file containing configurations if not in pubspec.yaml', ); parser.addOption( - 'verbose', + verbose, abbr: 'v', - defaultsTo: 'info', + defaultsTo: logInfo, allowed: [ - 'all', - 'fine', - 'info', - 'warning', - 'severe', + logAll, + logFine, + logInfo, + logWarning, + logSevere, ], ); parser.addFlag( - 'help', + help, abbr: 'h', - help: 'prints this usage', + help: 'Prints this usage', negatable: false, ); + parser.addOption( + compilerOpts, + help: 'Compiler options for clang. (E.g --$compilerOpts "-I/headers -W")', + ); ArgResults results; try { results = parser.parse(args); - if (results.wasParsed('help')) { + if (results.wasParsed(help)) { print(parser.usage); exit(0); } @@ -148,25 +172,25 @@ /// Sets up the logging level and printing. void setupLogger(ArgResults result) { - if (result.wasParsed('verbose')) { - switch (result['verbose'] as String?) { - case 'all': + if (result.wasParsed(verbose)) { + switch (result[verbose] as String?) { + case logAll: // Logs everything, the entire AST touched by our parser. Logger.root.level = Level.ALL; break; - case 'fine': + case logFine: // Logs AST parts relevant to user (i.e those included in filters). Logger.root.level = Level.FINE; break; - case 'info': + case logInfo: // Logs relevant info for general user (default). Logger.root.level = Level.INFO; break; - case 'warning': + case logWarning: // Logs warnings for relevant stuff. Logger.root.level = Level.WARNING; break; - case 'severe': + case logSevere: // Logs severe warnings and errors. Logger.root.level = Level.SEVERE; break;
diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml index e986dfd..31048c4 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: 2.2.4 +version: 2.2.5 homepage: https://github.com/dart-lang/ffigen description: Generator for FFI bindings, using LibClang to parse C header files.
diff --git a/pkgs/ffigen/test/config_tests/compiler_opts_test.dart b/pkgs/ffigen/test/config_tests/compiler_opts_test.dart new file mode 100644 index 0000000..a3aa117 --- /dev/null +++ b/pkgs/ffigen/test/config_tests/compiler_opts_test.dart
@@ -0,0 +1,29 @@ +// Copyright (c) 2021, 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/code_generator.dart'; +import 'package:ffigen/src/config_provider/spec_utils.dart'; +import 'package:test/test.dart'; + +late Library actual, expected; + +void main() { + group('compiler_opts_test', () { + test('Compiler Opts', () { + final opts = + '''--option value "in double quotes" 'in single quotes' -tab=separated'''; + final list = compilerOptsToList(opts); + expect( + list, + <String>[ + '--option', + 'value', + 'in double quotes', + 'in single quotes', + '-tab=separated', + ], + ); + }); + }); +}
diff --git a/pkgs/ffigen/test/test_coverage.dart b/pkgs/ffigen/test/test_coverage.dart index 9f61cde..88623ba 100644 --- a/pkgs/ffigen/test/test_coverage.dart +++ b/pkgs/ffigen/test/test_coverage.dart
@@ -7,14 +7,20 @@ as collision_tests_decl_decl_collision_test; import 'collision_tests/reserved_keyword_collision_test.dart' as collision_tests_reserved_keyword_collision_test; +import 'config_tests/compiler_opts_test.dart' + as config_tests_compiler_opts_test; import 'example_tests/cjson_example_test.dart' as example_tests_cjson_example_test; import 'example_tests/libclang_example_test.dart' as example_tests_libclang_example_test; import 'example_tests/simple_example_test.dart' as example_tests_simple_example_test; +import 'header_parser_tests/comment_markup_test.dart' + as header_parser_tests_comment_markup_test; import 'header_parser_tests/dart_handle_test.dart' as header_parser_tests_dart_handle_test; +import 'header_parser_tests/forward_decl_test.dart' + as header_parser_tests_forward_decl_test; import 'header_parser_tests/function_n_struct_test.dart' as header_parser_tests_function_n_struct_test; import 'header_parser_tests/functions_test.dart' @@ -27,6 +33,8 @@ as header_parser_tests_native_func_typedef_test; import 'header_parser_tests/nested_parsing_test.dart' as header_parser_tests_nested_parsing_test; +import 'header_parser_tests/opaque_dependencies_test.dart' + as header_parser_tests_opaque_dependencies_test; import 'header_parser_tests/typedef_test.dart' as header_parser_tests_typedef_test; import 'header_parser_tests/unnamed_enums_test.dart' @@ -43,13 +51,17 @@ example_tests_libclang_example_test.main(); collision_tests_decl_decl_collision_test.main(); collision_tests_reserved_keyword_collision_test.main(); + config_tests_compiler_opts_test.main(); + header_parser_tests_comment_markup_test.main(); header_parser_tests_dart_handle_test.main(); + header_parser_tests_forward_decl_test.main(); header_parser_tests_functions_test.main(); header_parser_tests_globals_test.main(); header_parser_tests_macros_test.main(); header_parser_tests_function_n_struct_test.main(); header_parser_tests_native_func_typedef_test.main(); header_parser_tests_nested_parsing_test.main(); + header_parser_tests_opaque_dependencies_test.main(); header_parser_tests_typedef_test.main(); header_parser_tests_unnamed_enums_test.main(); native_test_native_test.main();