Skip to content

Commit 2cd8daa

Browse files
committed
Replace per-type import bookkeeping with ffigen symbol-file dedup
Cross-module shared types were deduplicated by hand-enumerating every typedef/struct/union in per-module `imports` lists in modules.yaml, which build_configs.py rendered into library-imports + type-map blocks. Each new duplicate required finding the owning module and appending the exact type name, and the lists (48-50 edges per version) had to be kept in sync with the C headers. Replace the enumerated lists with a plain `deps` list of module names and use ffigen's native symbol-file mechanism instead: a module named in another module's deps exports a symbol file (output.symbol-file), and the depending module imports it (import.symbol-files), so ffigen references the provider's declarations for every shared type automatically. The dependency edges are unchanged; only the per-type bookkeeping is gone (-1,288 lines across the six manifests). - build_configs.py renders provider/consumer blocks from deps, keeps type-map only for dart:ffi primitive_typedefs, and emits ffigen_order.txt (topological order, providers first) since a consumer needs its providers' symbol files to exist. - generate_bindings.sh runs ffigen in that order and then runs the new rename_unnamed.py, which prefixes ffigen's per-file UnnamedStructN/ UnnamedUnionN names with the module stem so they are globally unique and no longer need hide clauses. - generate_tizen.py now hides any duplicated top-level export (classes, enums, typedefs, and const macros), recognizing symbol-file aliases (typedef X = impN.X;) so the real declaration keeps ownership. - resolve_type_dups.py derives a single deps edge per duplicate pair instead of growing enumerated type lists, and regenerates changed modules in dependency order. - check_consistency.py additionally validates that deps name existing modules and form a DAG. The 6.0 dependency edges and rendered configs are identical to the ones validated on jsuya/ffigen-6.0-pushable (dart analyze clean, integration test 56/57 on RPI4, the one failure being an unrelated NOT_SUPPORTED).
1 parent 259ea64 commit 2cd8daa

17 files changed

Lines changed: 958 additions & 2511 deletions

configs/10.0/modules.yaml

Lines changed: 112 additions & 343 deletions
Large diffs are not rendered by default.

configs/6.0/modules.yaml

Lines changed: 87 additions & 258 deletions
Large diffs are not rendered by default.

configs/6.5/modules.yaml

Lines changed: 98 additions & 288 deletions
Large diffs are not rendered by default.

configs/7.0/modules.yaml

Lines changed: 111 additions & 342 deletions
Large diffs are not rendered by default.

configs/8.0/modules.yaml

Lines changed: 111 additions & 345 deletions
Large diffs are not rendered by default.

configs/9.0/modules.yaml

Lines changed: 112 additions & 343 deletions
Large diffs are not rendered by default.

doc/IMPROVEMENT_PLAN.md

Lines changed: 0 additions & 214 deletions
This file was deleted.

doc/MODULES_SCHEMA.md

Lines changed: 0 additions & 170 deletions
This file was deleted.

scripts/README.md

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@
1515
The only hand-maintained config file per version is `configs/<version>/modules.yaml`.
1616
Everything else (`symgen.yaml`, `entrypoints.h`, `entrypoints_*.h`, `ffigen_*.yaml`)
1717
is rendered from it into `build/configs/<version>/` at generation time and is not
18-
committed. See `doc/MODULES_SCHEMA.md` for the schema.
18+
committed.
1919

2020
1. Create `configs/<version>/modules.yaml` by copying the previous version's file
2121
and updating `version`, `rootstrap_prefix`, and the module list by referring to
2222
the official [API docs](https://docs.tizen.org/application/native/api/iot-headed/latest)
2323
and the rootstrap (added/removed libraries and headers).
2424

2525
2. Generate the bindings. This renders the derived configs, runs symgen and
26-
ffigen for every module, converts Doxygen comments into Dartdoc format, and
26+
ffigen for every module (in dependency order, so that symbol files exist
27+
before the modules that import them), renames anonymous structs/unions to
28+
module-unique names, converts Doxygen comments into Dartdoc format, and
2729
regenerates `lib/<version>/tizen.dart`:
2830

2931
```sh
@@ -82,53 +84,30 @@ python3 scripts/generate_doc_script.py
8284

8385
When splitting single binding code into library-specific binding codes from version 0.5.2 onwards, type duplication issues may occur between binding codes. Here are common issues and their solutions. All solutions are expressed in `configs/<version>/modules.yaml`; the ffigen YAML shown below is what gets rendered from it.
8486

85-
### 1. Struct Type Duplication
87+
### 1. Struct / Typedef / Union Type Duplication
8688

87-
**Issue**: When both `generated_bindings_A.dart` and `generated_bindings_B.dart` define `struct AA {...}` and are exported through `tizen.dart`, a duplication error occurs.
89+
**Issue**: When both `generated_bindings_A.dart` and `generated_bindings_B.dart` define `struct AA {...}` (or a typedef/union) and are exported through `tizen.dart`, a duplication error occurs.
8890

89-
**Solution**: Add an `imports` entry to module B in `modules.yaml`:
91+
**Solution**: Add a `deps` entry to module B in `modules.yaml`:
9092

9193
```yaml
9294
- name: B
9395
...
94-
imports:
95-
- from: A
96-
as: A_Header
97-
structs:
98-
- AA
96+
deps:
97+
- A
9998
```
10099
101-
which renders into `ffigen_B.yaml` as:
100+
This uses ffigen's symbol-file mechanism: module A's rendered config exports a
101+
symbol file (`output.symbol-file` → `.symbols/A.yaml`) and module B's config
102+
imports it (`import.symbol-files`). ffigen then references A's declarations
103+
(`typedef AA = imp1.AA;`) instead of re-emitting them — for **every** type the
104+
two modules share, so no per-type bookkeeping is needed. `generate_bindings.sh`
105+
runs the modules in dependency order (`ffigen_order.txt`, providers first).
102106

103-
```yaml
104-
library-imports:
105-
A_Header: 'generated_bindings_A.dart'
106-
107-
type-map:
108-
structs:
109-
'AA':
110-
lib: 'A_Header'
111-
c-type: 'AA'
112-
dart-type: 'AA'
113-
```
114-
115-
### 2. Typedef Type Duplication
116-
117-
**Issue**: When both `generated_bindings_A.dart` and `generated_bindings_B.dart` define `typedef AA BB` and are exported through `tizen.dart`, a duplication error occurs.
107+
`scripts/resolve_type_dups.py <version>` derives these `deps` edges (plus the
108+
enum/macro fixes below) automatically from `dart analyze` errors.
118109

119-
**Solution**: Same as above, using the `typedefs` list of the `imports` entry:
120-
121-
```yaml
122-
- name: B
123-
...
124-
imports:
125-
- from: A
126-
as: A_Header
127-
typedefs:
128-
- AA
129-
```
130-
131-
### 3. Enum Type Duplication
110+
### 2. Enum Type Duplication
132111

133112
**Issue**: When both `generated_bindings_A.dart` and `generated_bindings_B.dart` define `enum {...} DD;` and are exported through `tizen.dart`, a duplication error occurs.
134113

@@ -141,7 +120,7 @@ type-map:
141120
'DD': '_DD'
142121
```
143122

144-
### 4. Unused Callback Definitions
123+
### 3. Unused Callback Definitions
145124

146125
**Issue**: When a callback is only defined in a header but not actually used, ffigen does not generate it (ffigen does not generate unused functions or types).
147126

@@ -158,7 +137,7 @@ it to the module's entry points:
158137
arg: callback
159138
```
160139

161-
### 5. Generic Type Issues with typedef
140+
### 4. Generic Type Issues with typedef
162141

163142
**Issue**: When there is code like `typedef __time_t time_t;` in a header file, generic type issues occur (generic types can only use basic types like int, double, or Pointer).
164143

@@ -172,11 +151,23 @@ it to the module's entry points:
172151
__time_t: { c: Long, d: int }
173152
```
174153

175-
### 6. Unnamed Union Duplication
154+
### 5. Unnamed Union Duplication
176155

177156
**Issue**: When unnamed unions are defined in C code, binding code generation automatically assigns names like `UnnamedUnion1`, causing duplication issues.
178157

179-
**Solution**: Handled automatically. `generate_tizen.py` scans the binding files
180-
for top-level `UnnamedUnionN`/`UnnamedStructN` declarations and, for every name
181-
declared by more than one module, keeps it exported from the first module and
182-
adds `hide` clauses to the others.
158+
**Solution**: Handled automatically. `scripts/rename_unnamed.py` (run by
159+
`generate_bindings.sh` after ffigen) prefixes every `UnnamedStructN` /
160+
`UnnamedUnionN` with the module's class-name stem (e.g.
161+
`CapiMediaCameraUnnamedUnion1`), making each one globally unique and nameable —
162+
no `hide` needed.
163+
164+
### 6. Remaining Duplicate Exports
165+
166+
**Issue**: A top-level name (e.g. a macro constant emitted as `const int X = ...;`)
167+
is declared by two modules that share no dependency edge.
168+
169+
**Solution**: Handled automatically. `generate_tizen.py` scans all binding files
170+
for top-level declarations (classes, enums, typedefs, constants), keeps each
171+
duplicated name on its owning module, and adds `hide` clauses to the other
172+
modules' `export` lines in `tizen.dart`. Symbol-file typedef aliases
173+
(`typedef X = impN.X;`) are recognized so the real declaration wins ownership.

0 commit comments

Comments
 (0)