Skip to content

Commit e9c26a6

Browse files
authored
[jnigen] Move output related configuration to single place (#93)
1 parent 6648a8a commit e9c26a6

File tree

15 files changed

+145
-165
lines changed

15 files changed

+145
-165
lines changed

.github/workflows/test-package.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ jobs:
331331
- run: flutter build apk
332332
working-directory: pkgs/jnigen/example/notification_plugin/example
333333
- name: re-generate bindings
334-
run: flutter pub run jnigen -Ddart_root=_dart -Dc_root=_c --config jnigen.yaml
334+
run: flutter pub run jnigen -Doutput.dart.path=_dart -Doutput.c.path=_c --config jnigen.yaml
335335
- name: compare generated dart bindings
336336
run: diff -qr lib/ _dart
337337
- name: compare generated C bindings
@@ -361,7 +361,7 @@ jobs:
361361
- run: flutter analyze
362362
- run: flutter build apk
363363
- name: re-generate bindings
364-
run: flutter pub run jnigen -Ddart_root=_dart -Dc_root=_c --config jnigen.yaml
364+
run: flutter pub run jnigen -Doutput.dart.path=_dart -Doutput.c.path=_c --config jnigen.yaml
365365
- name: compare generated dart bindings
366366
run: diff -qr lib/android_utils _dart
367367
- name: compare generated C bindings
@@ -390,7 +390,7 @@ jobs:
390390
- run: dart pub get
391391
- name: Generate bindings
392392
run: |
393-
dart run jnigen -Dc_root=_c -Ddart_root=_dart --config jnigen.yaml
393+
dart run jnigen -Doutput.c.path=_c -Doutput.dart.path=_dart --config jnigen.yaml
394394
- name: Compare generated bindings
395395
run: |
396396
diff -qr _c src/

pkgs/jnigen/example/in_app_java/jnigen.yaml

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
android_sdk_config:
22
add_gradle_deps: true
33

4-
library_name: android_utils
4+
output:
5+
c:
6+
library_name: android_utils
7+
path: src/android_utils
8+
dart:
9+
path: lib/android_utils
10+
511
source_path:
612
- 'android/app/src/main/java'
713
classes:
814
- 'com.example.in_app_java.AndroidUtils'
9-
c_root: src/android_utils
10-
dart_root: lib/android_utils
11-
root_package: com.example

pkgs/jnigen/example/in_app_java/tool/generate_bindings.dart

-19
This file was deleted.

pkgs/jnigen/example/notification_plugin/jnigen.yaml

+7-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ preamble: |
77
// for details. All rights reserved. Use of this source code is governed by a
88
// BSD-style license that can be found in the LICENSE file.
99
10-
library_name: notification_plugin
1110
source_path:
1211
- 'android/src/main/java'
1312
classes:
1413
- 'com.example.notification_plugin.Notifications'
15-
c_root: src/
16-
dart_root: lib/
14+
15+
output:
16+
c:
17+
path: 'src/'
18+
library_name: notification_plugin
19+
dart:
20+
path: 'lib/'

pkgs/jnigen/example/pdfbox_plugin/jnigen.yaml

+18-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
## Name of the generated library, this is required and used as the name of
2-
## shared library which contains C bindings
3-
library_name: pdfbox_plugin
4-
51
## String to be pasted verbatim into generated bindings
62
preamble: |
73
// Generated from Apache PDFBox library which is licensed under the Apache License 2.0.
@@ -22,18 +18,24 @@ preamble: |
2218
// See the License for the specific language governing permissions and
2319
// limitations under the License.
2420
25-
## Root for generated C bindings.
26-
c_root: 'src/'
27-
28-
## C files can be stored in a different sub-directory inside c_root.
29-
##
30-
## We have a guideline to keep all generated code in third_party/ since original
31-
## project's license applies to generated code. So we specify third_party/ as
32-
## c_subdir while keeping generated CMakeLists.txt in src/.
33-
c_subdir: 'third_party/'
34-
35-
## Root for generated Dart bindings.
36-
dart_root: 'lib/src/third_party/'
21+
## Output configuration
22+
output:
23+
c:
24+
## Path to write generated C bindings
25+
path: 'src/'
26+
## C files can be stored in a different sub-directory inside root.
27+
##
28+
## We have a guideline to keep all generated code in third_party/ since original
29+
## project's license applies to generated code. So we specify third_party/ as
30+
## c_subdir while keeping generated CMakeLists.txt in src/.
31+
subdir: 'third_party/'
32+
## Name of the generated library. This is a required parameter, and used for the name of the
33+
## shared library and CMake configuration.
34+
library_name: 'pdfbox_plugin'
35+
dart:
36+
## Generated dart bindings will be written to this path. They will follow the same folder hierarchy
37+
## as the original Java code.
38+
path: 'lib/src/third_party/'
3739

3840
## Classes / packages for which bindings need to be generated.
3941
classes:

pkgs/jnigen/lib/src/bindings/preprocessor.dart

-6
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,7 @@ abstract class ApiPreprocessor {
1414
static void preprocessAll(Map<String, ClassDecl> classes, Config config,
1515
{bool renameClasses = false}) {
1616
final Map<String, int> classNameCounts = {};
17-
final rootPackage = config.rootPackage;
1817
for (var c in classes.values) {
19-
final packageName = c.packageName;
20-
if (rootPackage != null && !packageName.startsWith('$rootPackage.')) {
21-
throw ArgumentError("class ${c.binaryName} not in "
22-
"root package $rootPackage");
23-
}
2418
final className = getSimplifiedClassName(c.binaryName);
2519
c.uniqueName = renameConflict(classNameCounts, className);
2620
if (renameClasses) {

pkgs/jnigen/lib/src/config/config.dart

+63-83
Original file line numberDiff line numberDiff line change
@@ -125,39 +125,59 @@ enum SummarizerBackend {
125125
doclet,
126126
}
127127

128+
class CCodeOutputConfig {
129+
CCodeOutputConfig({
130+
required this.path,
131+
required this.libraryName,
132+
this.subdir,
133+
});
134+
135+
/// Directory to write JNI C Bindings, in C+Dart mode.
136+
///
137+
/// Strictly speaking, this is the root to place the `CMakeLists.txt` file
138+
/// for the generated C bindings. It may be desirable to use the [subdir]
139+
/// options to write C files to a subdirectory of [path]. For instance,
140+
/// when generated code is required to be in `third_party` directory.
141+
Uri path;
142+
143+
/// Name of generated library in CMakeLists.txt configuration.
144+
///
145+
/// This will also determine the name of shared object file.
146+
String libraryName;
147+
148+
/// Subfolder relative to [path] to write generated C code.
149+
String? subdir;
150+
}
151+
152+
class DartCodeOutputConfig {
153+
// TODO(#90): Support output_structure = single_file | package_structure.
154+
155+
DartCodeOutputConfig({required this.path});
156+
157+
/// Path to write generated Dart bindings.
158+
Uri path;
159+
}
160+
161+
class OutputConfig {
162+
// TODO(#60): Add bindings_type = dart_only | c_based.
163+
164+
OutputConfig({required this.cConfig, required this.dartConfig});
165+
DartCodeOutputConfig dartConfig;
166+
CCodeOutputConfig cConfig;
167+
}
168+
128169
class BindingExclusions {
129170
BindingExclusions({this.methods, this.fields, this.classes});
130171
MethodFilter? methods;
131172
FieldFilter? fields;
132173
ClassFilter? classes;
133174
}
134175

135-
enum BindingsType {
136-
cBased, // C+Dart bindings
137-
singleFile,
138-
packageStructured,
139-
}
140-
141-
BindingsType getBindingsType(String? type, BindingsType defaultType) {
142-
const names = {
143-
'c_based': BindingsType.cBased,
144-
'single_file': BindingsType.singleFile,
145-
'package_structured': BindingsType.packageStructured,
146-
};
147-
return names[type] ?? defaultType;
148-
}
149-
150176
/// Configuration for jnigen binding generation.
151177
class Config {
152178
Config({
179+
required this.outputConfig,
153180
required this.classes,
154-
this.bindingsType = BindingsType.cBased,
155-
this.outputPath,
156-
this.libraryName,
157-
this.cRoot,
158-
this.dartRoot,
159-
this.cSubdir,
160-
this.rootPackage,
161181
this.exclude,
162182
this.sourcePath,
163183
this.classPath,
@@ -168,16 +188,10 @@ class Config {
168188
this.summarizerOptions,
169189
this.logLevel = Level.INFO,
170190
this.dumpJsonTo,
171-
}) {
172-
if (bindingsType == BindingsType.cBased) {
173-
if (cRoot == null || dartRoot == null || libraryName == null) {
174-
throw ArgumentError("In c_based mode these values must be specified: "
175-
"c_root, dart_root, library_name");
176-
}
177-
} else {
178-
throw UnimplementedError("BindingsType not yet supported: $bindingsType");
179-
}
180-
}
191+
});
192+
193+
/// Output configuration for generated bindings
194+
OutputConfig outputConfig;
181195

182196
/// List of classes or packages for which bindings have to be generated.
183197
///
@@ -188,41 +202,6 @@ class Config {
188202
/// name suffix is `.class`.
189203
List<String> classes;
190204

191-
/// Type of bindings to generate.
192-
final BindingsType bindingsType;
193-
194-
/// Name of generated library in CMakeLists.txt configuration.
195-
///
196-
/// This will also determine the name of shared object file.
197-
final String? libraryName;
198-
199-
/// Directory to write JNI C Bindings, in C+Dart mode.
200-
///
201-
/// Strictly speaking, this is the root to place the `CMakeLists.txt` file
202-
/// for the generated C bindings. It may be desirable to use the [cSubdir]
203-
/// options to write C files to a subdirectory of [cRoot]. For instance,
204-
/// when generated code is required to be in `third_party` directory.
205-
Uri? cRoot;
206-
207-
/// Directory to write Dart bindings, in C + Dart mode.
208-
Uri? dartRoot;
209-
210-
/// Subfolder relative to [cRoot] to write generated C code.
211-
String? cSubdir;
212-
213-
/// Java package corresponding to the dart_root directory.
214-
///
215-
/// By default, the complete java hierarchy is mirrored. For instance,
216-
/// `org.apache.pdfbox.text` becomes `org/apache/pdfbox/text.dart`.
217-
/// This is often undesirable, when all packages have a common package. In
218-
/// such cases, a super-package name can be provided. This will be assumed as
219-
/// the prefix of all packages and hierarchy will be created relative to this
220-
/// package.
221-
String? rootPackage;
222-
223-
/// Output file or folder in non-legacy modes
224-
Uri? outputPath;
225-
226205
/// Methods and fields to be excluded from generated bindings.
227206
final BindingExclusions? exclude;
228207

@@ -288,7 +267,6 @@ class Config {
288267
return res;
289268
}
290269

291-
Uri? fileUri(String? path) => path != null ? Uri.file(path) : null;
292270
Uri? directoryUri(String? path) =>
293271
path != null ? Uri.directory(path) : null;
294272

@@ -339,15 +317,17 @@ class Config {
339317
methods: regexFilter<Method>(_Props.excludeMethods),
340318
fields: regexFilter<Field>(_Props.excludeFields),
341319
),
342-
bindingsType: getBindingsType(
343-
prov.getString(_Props.bindingsType), BindingsType.cBased),
344-
cRoot: directoryUri(prov.getString(_Props.cRoot)),
345-
dartRoot: directoryUri(prov.getString(_Props.dartRoot)),
346-
outputPath: fileUri(prov.getString(_Props.outputPath)),
347-
cSubdir: prov.getString(_Props.cSubdir),
348-
rootPackage: prov.getString(_Props.rootPackage),
320+
outputConfig: OutputConfig(
321+
cConfig: CCodeOutputConfig(
322+
libraryName: must(prov.getString, '', _Props.libraryName),
323+
path: Uri.directory(must(prov.getString, '.', _Props.cRoot)),
324+
subdir: prov.getString(_Props.cSubdir),
325+
),
326+
dartConfig: DartCodeOutputConfig(
327+
path: Uri.directory(must(prov.getString, '.', _Props.dartRoot)),
328+
),
329+
),
349330
preamble: prov.getString(_Props.preamble),
350-
libraryName: must(prov.getString, '', _Props.libraryName),
351331
importMap: prov.getStringMap(_Props.importMap),
352332
mavenDownloads: prov.hasValue(_Props.mavenDownloads)
353333
? MavenDownloads(
@@ -411,14 +391,14 @@ class _Props {
411391
static const excludeFields = '$exclude.fields';
412392

413393
static const importMap = 'import_map';
414-
static const outputPath = 'output_path';
415-
static const bindingsType = 'bindings_type';
416-
static const dartRoot = 'dart_root';
417-
static const cRoot = 'c_root';
418-
static const cSubdir = 'c_subdir';
419-
static const rootPackage = 'root_package';
394+
static const outputConfig = 'output';
395+
static const cCodeOutputConfig = '$outputConfig.c';
396+
static const dartCodeOutputConfig = '$outputConfig.dart';
397+
static const cRoot = '$cCodeOutputConfig.path';
398+
static const cSubdir = '$cCodeOutputConfig.subdir';
399+
static const dartRoot = '$dartCodeOutputConfig.path';
400+
static const libraryName = '$cCodeOutputConfig.library_name';
420401
static const preamble = 'preamble';
421-
static const libraryName = 'library_name';
422402
static const logLevel = 'log_level';
423403

424404
static const mavenDownloads = 'maven_downloads';

pkgs/jnigen/lib/src/writers/files_writer.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,11 @@ class FilesWriter extends BindingsWriter {
178178
}
179179
final classNames = classesByName.keys.toSet();
180180

181-
final cRoot = config.cRoot!;
181+
final cRoot = config.outputConfig.cConfig.path;
182182
log.info("Using c root = $cRoot");
183-
final dartRoot = config.dartRoot!;
183+
final dartRoot = config.outputConfig.dartConfig.path;
184184
log.info("Using dart root = $dartRoot");
185-
final libraryName = config.libraryName!;
185+
final libraryName = config.outputConfig.cConfig.libraryName;
186186

187187
log.info('Creating dart init file ...');
188188
final initFileUri = dartRoot.resolve(_initFileName);
@@ -192,7 +192,7 @@ class FilesWriter extends BindingsWriter {
192192
initCode = '$preamble\n$initCode';
193193
}
194194
await initFile.writeAsString(initCode, flush: true);
195-
final subdir = config.cSubdir ?? '.';
195+
final subdir = config.outputConfig.cConfig.subdir ?? '.';
196196
final cFileRelativePath = '$subdir/$libraryName.c';
197197
final cFile = await File.fromUri(cRoot.resolve(cFileRelativePath))
198198
.create(recursive: true);

pkgs/jnigen/test/config_test.dart

+9-5
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ final testSrc = join(thirdParty, 'test_', 'src');
2121
/// two fields are not equal.
2222
void expectConfigsAreEqual(Config a, Config b) {
2323
expect(a.classes, equals(b.classes), reason: "classes");
24-
expect(a.libraryName, equals(b.libraryName), reason: "libraryName");
25-
expect(a.cRoot, equals(b.cRoot), reason: "cRoot");
26-
expect(a.dartRoot, equals(b.dartRoot), reason: "dartRoot");
24+
expect(a.outputConfig.cConfig.libraryName,
25+
equals(b.outputConfig.cConfig.libraryName),
26+
reason: "libraryName");
27+
expect(a.outputConfig.cConfig.path, equals(b.outputConfig.cConfig.path),
28+
reason: "cRoot");
29+
expect(a.outputConfig.dartConfig.path, equals(b.outputConfig.dartConfig.path),
30+
reason: "dartRoot");
2731
expect(a.sourcePath, equals(b.sourcePath), reason: "sourcePath");
2832
expect(a.classPath, equals(b.classPath), reason: "classPath");
2933
expect(a.preamble, equals(b.preamble), reason: "preamble");
@@ -71,8 +75,8 @@ void main() {
7175
final config = Config.parseArgs([
7276
'--config',
7377
join(jacksonCoreTests, 'jnigen.yaml'),
74-
'-Dc_root=$testSrc',
75-
'-Ddart_root=$testLib',
78+
'-Doutput.c.path=$testSrc',
79+
'-Doutput.dart.path=$testLib',
7680
]);
7781

7882
test('compare configuration values', () {

0 commit comments

Comments
 (0)