Added new command-line option `--compiler-opts`. (#192)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index abc7d7b..319671a 100644
--- a/CHANGELOG.md
+++ b/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/README.md b/README.md
index 9f516e4..5eb0103 100644
--- a/README.md
+++ b/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/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index cf083df..434137e 100644
--- a/lib/src/config_provider/config.dart
+++ b/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/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 0351d8c..692f921 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/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/lib/src/executables/ffigen.dart b/lib/src/executables/ffigen.dart
index 14d1388..12dd868 100644
--- a/lib/src/executables/ffigen.dart
+++ b/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/pubspec.yaml b/pubspec.yaml
index e986dfd..31048c4 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: 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/test/config_tests/compiler_opts_test.dart b/test/config_tests/compiler_opts_test.dart
new file mode 100644
index 0000000..a3aa117
--- /dev/null
+++ b/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/test/test_coverage.dart b/test/test_coverage.dart
index 9f61cde..88623ba 100644
--- a/test/test_coverage.dart
+++ b/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();