[jnigen] Move output related configuration to single place (https://github.com/dart-lang/jnigen/issues/93)
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index 104a802..a578787 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml
@@ -331,7 +331,7 @@ - run: flutter build apk working-directory: ./pkgs/jnigen/example/notification_plugin/example - name: re-generate bindings - run: flutter pub run jnigen -Ddart_root=_dart -Dc_root=_c --config jnigen.yaml + run: flutter pub run jnigen -Doutput.dart.path=_dart -Doutput.c.path=_c --config jnigen.yaml - name: compare generated dart bindings run: diff -qr lib/ _dart - name: compare generated C bindings @@ -361,7 +361,7 @@ - run: flutter analyze - run: flutter build apk - name: re-generate bindings - run: flutter pub run jnigen -Ddart_root=_dart -Dc_root=_c --config jnigen.yaml + run: flutter pub run jnigen -Doutput.dart.path=_dart -Doutput.c.path=_c --config jnigen.yaml - name: compare generated dart bindings run: diff -qr lib/android_utils _dart - name: compare generated C bindings @@ -390,7 +390,7 @@ - run: dart pub get - name: Generate bindings run: | - dart run jnigen -Dc_root=_c -Ddart_root=_dart --config jnigen.yaml + dart run jnigen -Doutput.c.path=_c -Doutput.dart.path=_dart --config jnigen.yaml - name: Compare generated bindings run: | diff -qr _c src/
diff --git a/pkgs/jnigen/example/in_app_java/jnigen.yaml b/pkgs/jnigen/example/in_app_java/jnigen.yaml index 4d4280a..3c700ab 100644 --- a/pkgs/jnigen/example/in_app_java/jnigen.yaml +++ b/pkgs/jnigen/example/in_app_java/jnigen.yaml
@@ -1,11 +1,14 @@ android_sdk_config: add_gradle_deps: true -library_name: android_utils +output: + c: + library_name: android_utils + path: src/android_utils + dart: + path: lib/android_utils + source_path: - 'android/app/src/main/java' classes: - 'com.example.in_app_java.AndroidUtils' -c_root: src/android_utils -dart_root: lib/android_utils -root_package: com.example
diff --git a/pkgs/jnigen/example/in_app_java/tool/generate_bindings.dart b/pkgs/jnigen/example/in_app_java/tool/generate_bindings.dart deleted file mode 100644 index ce3b03f..0000000 --- a/pkgs/jnigen/example/in_app_java/tool/generate_bindings.dart +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright (c) 2022, 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:jnigen/jnigen.dart'; - -void main(List<String> args) async { - final config = Config( - sourcePath: [Uri.directory('android/app/src/main/java')], - classes: ['com.example.in_app_java.AndroidUtils'], - cRoot: Uri.directory('src/android_utils'), - dartRoot: Uri.directory('lib/android_utils'), - libraryName: 'android_utils', - androidSdkConfig: AndroidSdkConfig( - addGradleDeps: true, - ), - ); - await generateJniBindings(config); -}
diff --git a/pkgs/jnigen/example/notification_plugin/jnigen.yaml b/pkgs/jnigen/example/notification_plugin/jnigen.yaml index a2249ef..cd38a3a 100644 --- a/pkgs/jnigen/example/notification_plugin/jnigen.yaml +++ b/pkgs/jnigen/example/notification_plugin/jnigen.yaml
@@ -7,10 +7,14 @@ // 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. -library_name: notification_plugin source_path: - 'android/src/main/java' classes: - 'com.example.notification_plugin.Notifications' -c_root: src/ -dart_root: lib/ + +output: + c: + path: 'src/' + library_name: notification_plugin + dart: + path: 'lib/'
diff --git a/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml b/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml index f586d6d..eb4b674 100644 --- a/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml +++ b/pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml
@@ -1,7 +1,3 @@ -## Name of the generated library, this is required and used as the name of -## shared library which contains C bindings -library_name: pdfbox_plugin - ## String to be pasted verbatim into generated bindings preamble: | // Generated from Apache PDFBox library which is licensed under the Apache License 2.0. @@ -22,18 +18,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -## Root for generated C bindings. -c_root: 'src/' - -## C files can be stored in a different sub-directory inside c_root. -## -## We have a guideline to keep all generated code in third_party/ since original -## project's license applies to generated code. So we specify third_party/ as -## c_subdir while keeping generated CMakeLists.txt in src/. -c_subdir: 'third_party/' - -## Root for generated Dart bindings. -dart_root: 'lib/src/third_party/' +## Output configuration +output: + c: + ## Path to write generated C bindings + path: 'src/' + ## C files can be stored in a different sub-directory inside root. + ## + ## We have a guideline to keep all generated code in third_party/ since original + ## project's license applies to generated code. So we specify third_party/ as + ## c_subdir while keeping generated CMakeLists.txt in src/. + subdir: 'third_party/' + ## Name of the generated library. This is a required parameter, and used for the name of the + ## shared library and CMake configuration. + library_name: 'pdfbox_plugin' + dart: + ## Generated dart bindings will be written to this path. They will follow the same folder hierarchy + ## as the original Java code. + path: 'lib/src/third_party/' ## Classes / packages for which bindings need to be generated. classes:
diff --git a/pkgs/jnigen/lib/src/bindings/preprocessor.dart b/pkgs/jnigen/lib/src/bindings/preprocessor.dart index 1d57471..9635828 100644 --- a/pkgs/jnigen/lib/src/bindings/preprocessor.dart +++ b/pkgs/jnigen/lib/src/bindings/preprocessor.dart
@@ -14,13 +14,7 @@ static void preprocessAll(Map<String, ClassDecl> classes, Config config, {bool renameClasses = false}) { final Map<String, int> classNameCounts = {}; - final rootPackage = config.rootPackage; for (var c in classes.values) { - final packageName = c.packageName; - if (rootPackage != null && !packageName.startsWith('$rootPackage.')) { - throw ArgumentError("class ${c.binaryName} not in " - "root package $rootPackage"); - } final className = getSimplifiedClassName(c.binaryName); c.uniqueName = renameConflict(classNameCounts, className); if (renameClasses) {
diff --git a/pkgs/jnigen/lib/src/config/config.dart b/pkgs/jnigen/lib/src/config/config.dart index 78952e2..0fad9ad 100644 --- a/pkgs/jnigen/lib/src/config/config.dart +++ b/pkgs/jnigen/lib/src/config/config.dart
@@ -125,6 +125,47 @@ doclet, } +class CCodeOutputConfig { + CCodeOutputConfig({ + required this.path, + required this.libraryName, + this.subdir, + }); + + /// Directory to write JNI C Bindings, in C+Dart mode. + /// + /// Strictly speaking, this is the root to place the `CMakeLists.txt` file + /// for the generated C bindings. It may be desirable to use the [subdir] + /// options to write C files to a subdirectory of [path]. For instance, + /// when generated code is required to be in `third_party` directory. + Uri path; + + /// Name of generated library in CMakeLists.txt configuration. + /// + /// This will also determine the name of shared object file. + String libraryName; + + /// Subfolder relative to [path] to write generated C code. + String? subdir; +} + +class DartCodeOutputConfig { + // TODO(#90): Support output_structure = single_file | package_structure. + + DartCodeOutputConfig({required this.path}); + + /// Path to write generated Dart bindings. + Uri path; +} + +class OutputConfig { + // TODO(#60): Add bindings_type = dart_only | c_based. + + OutputConfig({required this.cConfig, required this.dartConfig}); + DartCodeOutputConfig dartConfig; + CCodeOutputConfig cConfig; +} + class BindingExclusions { BindingExclusions({this.methods, this.fields, this.classes}); MethodFilter? methods; @@ -132,32 +173,11 @@ ClassFilter? classes; } -enum BindingsType { - cBased, // C+Dart bindings - singleFile, - packageStructured, -} - -BindingsType getBindingsType(String? type, BindingsType defaultType) { - const names = { - 'c_based': BindingsType.cBased, - 'single_file': BindingsType.singleFile, - 'package_structured': BindingsType.packageStructured, - }; - return names[type] ?? defaultType; -} - /// Configuration for jnigen binding generation. class Config { Config({ + required this.outputConfig, required this.classes, - this.bindingsType = BindingsType.cBased, - this.outputPath, - this.libraryName, - this.cRoot, - this.dartRoot, - this.cSubdir, - this.rootPackage, this.exclude, this.sourcePath, this.classPath, @@ -168,16 +188,10 @@ this.summarizerOptions, this.logLevel = Level.INFO, this.dumpJsonTo, - }) { - if (bindingsType == BindingsType.cBased) { - if (cRoot == null || dartRoot == null || libraryName == null) { - throw ArgumentError("In c_based mode these values must be specified: " - "c_root, dart_root, library_name"); - } - } else { - throw UnimplementedError("BindingsType not yet supported: $bindingsType"); - } - } + }); + + /// Output configuration for generated bindings + OutputConfig outputConfig; /// List of classes or packages for which bindings have to be generated. /// @@ -188,41 +202,6 @@ /// name suffix is `.class`. List<String> classes; - /// Type of bindings to generate. - final BindingsType bindingsType; - - /// Name of generated library in CMakeLists.txt configuration. - /// - /// This will also determine the name of shared object file. - final String? libraryName; - - /// Directory to write JNI C Bindings, in C+Dart mode. - /// - /// Strictly speaking, this is the root to place the `CMakeLists.txt` file - /// for the generated C bindings. It may be desirable to use the [cSubdir] - /// options to write C files to a subdirectory of [cRoot]. For instance, - /// when generated code is required to be in `third_party` directory. - Uri? cRoot; - - /// Directory to write Dart bindings, in C + Dart mode. - Uri? dartRoot; - - /// Subfolder relative to [cRoot] to write generated C code. - String? cSubdir; - - /// Java package corresponding to the dart_root directory. - /// - /// By default, the complete java hierarchy is mirrored. For instance, - /// `org.apache.pdfbox.text` becomes `org/apache/pdfbox/text.dart`. - /// This is often undesirable, when all packages have a common package. In - /// such cases, a super-package name can be provided. This will be assumed as - /// the prefix of all packages and hierarchy will be created relative to this - /// package. - String? rootPackage; - - /// Output file or folder in non-legacy modes - Uri? outputPath; - /// Methods and fields to be excluded from generated bindings. final BindingExclusions? exclude; @@ -288,7 +267,6 @@ return res; } - Uri? fileUri(String? path) => path != null ? Uri.file(path) : null; Uri? directoryUri(String? path) => path != null ? Uri.directory(path) : null; @@ -339,15 +317,17 @@ methods: regexFilter<Method>(_Props.excludeMethods), fields: regexFilter<Field>(_Props.excludeFields), ), - bindingsType: getBindingsType( - prov.getString(_Props.bindingsType), BindingsType.cBased), - cRoot: directoryUri(prov.getString(_Props.cRoot)), - dartRoot: directoryUri(prov.getString(_Props.dartRoot)), - outputPath: fileUri(prov.getString(_Props.outputPath)), - cSubdir: prov.getString(_Props.cSubdir), - rootPackage: prov.getString(_Props.rootPackage), + outputConfig: OutputConfig( + cConfig: CCodeOutputConfig( + libraryName: must(prov.getString, '', _Props.libraryName), + path: Uri.directory(must(prov.getString, '.', _Props.cRoot)), + subdir: prov.getString(_Props.cSubdir), + ), + dartConfig: DartCodeOutputConfig( + path: Uri.directory(must(prov.getString, '.', _Props.dartRoot)), + ), + ), preamble: prov.getString(_Props.preamble), - libraryName: must(prov.getString, '', _Props.libraryName), importMap: prov.getStringMap(_Props.importMap), mavenDownloads: prov.hasValue(_Props.mavenDownloads) ? MavenDownloads( @@ -411,14 +391,14 @@ static const excludeFields = '$exclude.fields'; static const importMap = 'import_map'; - static const outputPath = 'output_path'; - static const bindingsType = 'bindings_type'; - static const dartRoot = 'dart_root'; - static const cRoot = 'c_root'; - static const cSubdir = 'c_subdir'; - static const rootPackage = 'root_package'; + static const outputConfig = 'output'; + static const cCodeOutputConfig = '$outputConfig.c'; + static const dartCodeOutputConfig = '$outputConfig.dart'; + static const cRoot = '$cCodeOutputConfig.path'; + static const cSubdir = '$cCodeOutputConfig.subdir'; + static const dartRoot = '$dartCodeOutputConfig.path'; + static const libraryName = '$cCodeOutputConfig.library_name'; static const preamble = 'preamble'; - static const libraryName = 'library_name'; static const logLevel = 'log_level'; static const mavenDownloads = 'maven_downloads';
diff --git a/pkgs/jnigen/lib/src/writers/files_writer.dart b/pkgs/jnigen/lib/src/writers/files_writer.dart index 252fac1..d26d9c4 100644 --- a/pkgs/jnigen/lib/src/writers/files_writer.dart +++ b/pkgs/jnigen/lib/src/writers/files_writer.dart
@@ -178,11 +178,11 @@ } final classNames = classesByName.keys.toSet(); - final cRoot = config.cRoot!; + final cRoot = config.outputConfig.cConfig.path; log.info("Using c root = $cRoot"); - final dartRoot = config.dartRoot!; + final dartRoot = config.outputConfig.dartConfig.path; log.info("Using dart root = $dartRoot"); - final libraryName = config.libraryName!; + final libraryName = config.outputConfig.cConfig.libraryName; log.info('Creating dart init file ...'); final initFileUri = dartRoot.resolve(_initFileName); @@ -192,7 +192,7 @@ initCode = '$preamble\n$initCode'; } await initFile.writeAsString(initCode, flush: true); - final subdir = config.cSubdir ?? '.'; + final subdir = config.outputConfig.cConfig.subdir ?? '.'; final cFileRelativePath = '$subdir/$libraryName.c'; final cFile = await File.fromUri(cRoot.resolve(cFileRelativePath)) .create(recursive: true);
diff --git a/pkgs/jnigen/test/config_test.dart b/pkgs/jnigen/test/config_test.dart index 352c378..c0589d2 100644 --- a/pkgs/jnigen/test/config_test.dart +++ b/pkgs/jnigen/test/config_test.dart
@@ -21,9 +21,13 @@ /// two fields are not equal. void expectConfigsAreEqual(Config a, Config b) { expect(a.classes, equals(b.classes), reason: "classes"); - expect(a.libraryName, equals(b.libraryName), reason: "libraryName"); - expect(a.cRoot, equals(b.cRoot), reason: "cRoot"); - expect(a.dartRoot, equals(b.dartRoot), reason: "dartRoot"); + expect(a.outputConfig.cConfig.libraryName, + equals(b.outputConfig.cConfig.libraryName), + reason: "libraryName"); + expect(a.outputConfig.cConfig.path, equals(b.outputConfig.cConfig.path), + reason: "cRoot"); + expect(a.outputConfig.dartConfig.path, equals(b.outputConfig.dartConfig.path), + reason: "dartRoot"); expect(a.sourcePath, equals(b.sourcePath), reason: "sourcePath"); expect(a.classPath, equals(b.classPath), reason: "classPath"); expect(a.preamble, equals(b.preamble), reason: "preamble"); @@ -71,8 +75,8 @@ final config = Config.parseArgs([ '--config', join(jacksonCoreTests, 'jnigen.yaml'), - '-Dc_root=$testSrc', - '-Ddart_root=$testLib', + '-Doutput.c.path=$testSrc', + '-Doutput.dart.path=$testLib', ]); test('compare configuration values', () {
diff --git a/pkgs/jnigen/test/jackson_core_test/generate.dart b/pkgs/jnigen/test/jackson_core_test/generate.dart index 7b708c4..c97d72d 100644 --- a/pkgs/jnigen/test/jackson_core_test/generate.dart +++ b/pkgs/jnigen/test/jackson_core_test/generate.dart
@@ -41,9 +41,15 @@ backend: useAsm ? 'asm' : null, ), preamble: jacksonPreamble, - libraryName: testName, - cRoot: Uri.directory(join(rootDir, 'src')), - dartRoot: Uri.directory(join(rootDir, 'lib')), + outputConfig: OutputConfig( + cConfig: CCodeOutputConfig( + libraryName: testName, + path: Uri.directory(join(rootDir, 'src')), + ), + dartConfig: DartCodeOutputConfig( + path: Uri.directory(join(rootDir, 'lib')), + ), + ), classes: (generateFullVersion) ? ['com.fasterxml.jackson.core'] : [
diff --git a/pkgs/jnigen/test/jackson_core_test/jnigen.yaml b/pkgs/jnigen/test/jackson_core_test/jnigen.yaml index 5a4f69c..d432067 100644 --- a/pkgs/jnigen/test/jackson_core_test/jnigen.yaml +++ b/pkgs/jnigen/test/jackson_core_test/jnigen.yaml
@@ -3,10 +3,14 @@ - 'com.fasterxml.jackson.core:jackson-core:2.13.4' source_dir: test/jackson_core_test/third_party/java jar_dir: test/jackson_core_test/third_party/jar -dart_root: test/jackson_core_test/third_party/lib -c_root: test/jackson_core_test/third_party/src -library_name: jackson_core_test -log_level: info + +output: + dart: + path: test/jackson_core_test/third_party/lib + c: + path: test/jackson_core_test/third_party/src + library_name: jackson_core_test + classes: - 'com.fasterxml.jackson.core.JsonFactory' - 'com.fasterxml.jackson.core.JsonParser'
diff --git a/pkgs/jnigen/test/simple_package_test/generate.dart b/pkgs/jnigen/test/simple_package_test/generate.dart index 33fd4e9..e87d9f6 100644 --- a/pkgs/jnigen/test/simple_package_test/generate.dart +++ b/pkgs/jnigen/test/simple_package_test/generate.dart
@@ -4,7 +4,6 @@ import 'dart:io'; -import 'package:logging/logging.dart'; import 'package:path/path.dart'; import 'package:jnigen/jnigen.dart'; @@ -46,11 +45,14 @@ 'com.github.dart_lang.jnigen.simple_package', 'com.github.dart_lang.jnigen.pkg2', ], + outputConfig: OutputConfig( + cConfig: CCodeOutputConfig( + path: cWrapperDir, + libraryName: 'simple_package', + ), + dartConfig: DartCodeOutputConfig(path: dartWrappersRoot), + ), preamble: preamble, - cRoot: cWrapperDir, - dartRoot: dartWrappersRoot, - logLevel: Level.INFO, - libraryName: 'simple_package', ); return config; }
diff --git a/pkgs/jnigen/test/test_util/test_util.dart b/pkgs/jnigen/test/test_util/test_util.dart index 1a38b16..c35f7a9 100644 --- a/pkgs/jnigen/test/test_util/test_util.dart +++ b/pkgs/jnigen/test/test_util/test_util.dart
@@ -60,8 +60,8 @@ Future<void> _generateTempBindings(Config config, Directory tempDir) async { final tempSrc = tempDir.uri.resolve("src/"); final tempLib = tempDir.uri.resolve("lib/"); - config.cRoot = tempSrc; - config.dartRoot = tempLib; + config.outputConfig.cConfig.path = tempSrc; + config.outputConfig.dartConfig.path = tempLib; await generateJniBindings(config); }
diff --git a/pkgs/jnigen/test/yaml_config_test.dart b/pkgs/jnigen/test/yaml_config_test.dart index 30083d1..7557e2f 100644 --- a/pkgs/jnigen/test/yaml_config_test.dart +++ b/pkgs/jnigen/test/yaml_config_test.dart
@@ -21,8 +21,8 @@ final args = [ '--config', configFile, - '-Dc_root=$testSrc', - '-Ddart_root=$testLib', + '-Doutput.c.path=$testSrc', + '-Doutput.dart.path=$testLib', ]; final config = Config.parseArgs(args); await generateAndCompareBindings(config, lib, src);
diff --git a/pkgs/jnigen/tool/pre_commit_checks.dart b/pkgs/jnigen/tool/pre_commit_checks.dart index 68d2974..e269fc5 100644 --- a/pkgs/jnigen/tool/pre_commit_checks.dart +++ b/pkgs/jnigen/tool/pre_commit_checks.dart
@@ -173,8 +173,8 @@ "jnigen", "--config", "jnigen.yaml", - "-Dc_root=src_temp", - "-Ddart_root=lib_temp", + "-Doutput.c.path=src_temp", + "-Doutput.dart.path=lib_temp", ]) ..chainCommand("diff", ["-qr", "lib/android_utils/", "lib_temp/"]) ..chainCommand("diff", ["-qr", "src/android_utils/", "src_temp/"]) @@ -186,8 +186,8 @@ "jnigen", "--config", "jnigen.yaml", - "-Dc_root=src_temp", - "-Ddart_root=lib_temp", + "-Doutput.c.path=src_temp", + "-Doutput.dart.path=lib_temp", ]) ..chainCommand("diff", ["-qr", "lib/src/third_party/", "lib_temp/"]) ..chainCommand("diff", ["-qr", "src/", "src_temp/"]) @@ -200,8 +200,8 @@ "jnigen", "--config", "jnigen.yaml", - "-Dc_root=src_temp", - "-Ddart_root=lib_temp", + "-Doutput.c.path=src_temp", + "-Doutput.dart.path=lib_temp", ]) ..chainCommand("diff", ["-qr", "lib/", "lib_temp/"]) ..chainCommand("diff", ["-qr", "src/", "src_temp/"])