Skip to content

Replace fragile per-type import bookkeeping with ffigen symbol-file dedup#76

Open
JSUYA wants to merge 8 commits into
flutter-tizen:mainfrom
JSUYA:ffi_symbol_file_dedup
Open

Replace fragile per-type import bookkeeping with ffigen symbol-file dedup#76
JSUYA wants to merge 8 commits into
flutter-tizen:mainfrom
JSUYA:ffi_symbol_file_dedup

Conversation

@JSUYA

@JSUYA JSUYA commented Jul 8, 2026

Copy link
Copy Markdown
Member

Shared types between modules were deduplicated by hand in configs//modules.yaml.
Every type shared across two modules had to be enumerated one by one:

  imports:
  - from: capi_appfw_app_control
    typedefs: [app_control_h]   # each shared type listed manually

48–50 such entries per version, kept in sync with the C headers by hand.
Miss one and the type re-duplicates, causing an ambiguous-export error.
Anonymous structs/unions collided on ffigen's coincidental UnnamedUnion1 names and were hidden from tizen.dart, making them unreachable.

So in this PR,
Replaces the manual type lists with a plain deps list, backed by ffigen's native symbol-file dedup:

  deps:
  - capi_appfw_app_control      # provider's types reused automatically
  • build_configs.py renders deps into output.symbol-file (provider) and import.symbol-files (consumer), so ffigen reuses the provider's
    declarations for all shared types — no per-type list to maintain.
  • Generation runs in topological order (ffigen_order.txt, providers first).
  • rename_unnamed.py gives anonymous types module-unique names (CapiMediaCameraUnnamedUnion1), so they stay reachable and need no hide.
  • check_consistency.py now verifies deps reference real modules and form a DAG.

It also removes now-obsolete generator scripts: the one-time migration/verification helpers (import_configs.py, verify_configs.py) and the
orphaned version-bootstrap tooling (update_modules.py, scan_rootstrap.py), trimming rootstrap_index.py to what resolve_type_dups.py still
needs.

Structure and scripts only — the generated bindings under lib/ are unchanged and will be regenerated in per-version follow-up PRs.

JSUYA added 7 commits July 6, 2026 15:41
configs/<version>/modules.yaml now describes every module (library,
headers, type-map imports, enum renames, ...) and the generation
scripts derive symgen.yaml, entrypoints.h, entrypoints_*.h, and
ffigen_*.yaml from it:

- scripts/build_configs.py: render derived configs from modules.yaml
- scripts/import_configs.py: bootstrap modules.yaml from existing
  configs (one-time migration helper)
- scripts/verify_configs.py: semantic diff between two config dirs
- scripts/generate_tizen.py: derive UnnamedUnion/UnnamedStruct hide
  clauses from the binding files instead of hardcoding the time module

Verified: build_configs.py output is semantically identical to the
committed configs for all six versions, and regenerating the 6.0
bindings (symgen + ffigen + convert_description + generate_tizen)
reproduces the committed files byte-for-byte.
configs/<version>/ now contains only the hand-maintained modules.yaml.
symgen.yaml, entrypoints*.h, and ffigen_*.yaml are rendered into
build/configs/<version>/ by scripts/build_configs.py when running
generate_bindings.sh or generate_callbacks.sh, so the ~780 derived
files no longer need to be committed and kept in sync by hand.

- generate_bindings.sh now also runs convert_description.dart and
  generate_tizen.py, covering the whole per-version generation flow.
- Add symgen_copyright_year to modules.yaml so rendered symgen.yaml
  preserves each version's original copyright year.
- Add scripts/check_consistency.py and a Verify workflow that render
  all configs, check modules.yaml against lib/, and analyze lib.
- Add .pubignore to keep build-time-only files out of the package.
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).
Follow-up cleanup to the symbol-file dedup pipeline, addressing coupling
and script sprawl without changing any generated output.

- Unify the snake_case -> UpperCamelCase convention into a single
  modules_yaml.to_upper_camel(). It was implemented three times
  (build_configs, generate_tizen, rename_unnamed) with two different
  algorithms (slice-upper vs str.title()) that silently diverge on name
  parts containing digits or capitals, so the class name and the
  anonymous-type prefix could disagree.
- Make build_configs' include groups data-driven: any group present in
  modules.yaml is now emitted, instead of being silently dropped unless
  its key was hardcoded in the renderer.
- generate_bindings.sh wipes build/configs/<version> before rendering, so
  a removed or renamed module leaves no stale ffigen_*.yaml or
  .symbols/*.yaml behind.
- Remove dead code: the unused to_camel_case(), and the unreachable
  entrypoint-insertion block in update_modules (an early return made it
  and its `inserted` bookkeeping unreachable).
- Delete migration-only scripts now that all six modules.yaml are
  committed: import_configs.py (bootstrap done), verify_configs.py
  (round-trip proof done), scan_rootstrap.py (its rootstrap_manifest.yaml
  baseline was never committed or used).

Verified: Tizen 6.0 regeneration is byte-identical to the pre-refactor
output (118 files), dart analyze is clean, and check_consistency passes
for all six versions.
Continues the script-sprawl cleanup by dropping the "rootstrap module
update" cluster that only the per-module ffi/dart split ever needed.

- Delete update_modules.py: an undocumented, over-engineered bootstrapper
  for a new version's modules.yaml (token-vote category prediction plus
  multi-tier header synthesis). The documented workflow copies the
  previous version's modules.yaml by hand; this parallel path was never
  referenced by the guide and produced entries that had to be reviewed
  anyway.
- Slim rootstrap_index.py (258 -> 186 lines) down to what
  resolve_type_dups actually uses -- pkg-config Requires direction and
  include-graph reachability. Drop the manifest persistence
  (to_manifest / from_manifest / open) and the update-only queries
  (header_exists / expand_glob / includedir_owners); the
  rootstrap_manifest.yaml baseline they served was never committed.
- resolve_type_dups.py now builds the ownership index only from a live
  rootstrap (the manifest fallback had no producer left); it still
  degrades cleanly to dependency in-degree / file order when no rootstrap
  is present.
- Remove modules_yaml naming helpers (lib_to_module_name, soname_of) that
  only update_modules / import_configs used.

Verified: rootstrap_index's kept queries and resolve_type_dups'
Ownership.decide run correctly against the Tizen 6.0 rootstrap; the
generate path is unaffected -- 6.0 regeneration is byte-identical, dart
analyze is clean, and check_consistency passes for all six versions.
@JSUYA JSUYA self-assigned this Jul 8, 2026
@JSUYA JSUYA added the enhancement New feature or request label Jul 8, 2026
@JSUYA
JSUYA requested a review from seungsoo47 July 8, 2026 09:23

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a .pubignore file to exclude development, configuration, and build-time-only files (such as .github/, .gemini/, configs/, and scripts/) from being published to the pub package registry, while also replicating relevant .gitignore rules. There are no review comments, and I have no additional feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

The Verify workflow regenerates lib/<version>/tizen.dart with
generate_tizen.py and fails if the result differs from what is committed.
The symbol-file dedup change reworked hide computation (compute_hide_map)
to sort the hidden names alphabetically, whereas the previous code
emitted union names before struct names. The committed files still had
the old ordering (`hide UnnamedUnion1, UnnamedStruct1`), so the check
failed.

Regenerate the six tizen.dart files so they match the current generator
(`hide UnnamedStruct1, UnnamedUnion1`). The hidden sets are unchanged, so
this is ordering-only; dart analyze stays clean.
@JSUYA
JSUYA force-pushed the ffi_symbol_file_dedup branch 2 times, most recently from 6d039fd to 04eb550 Compare July 9, 2026 11:12
@seungsoo47

Copy link
Copy Markdown
Contributor

Have you tested this plugin in tizen-fs?

@JSUYA

JSUYA commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

Have you tested this plugin in tizen-fs?

This PR removes the intermediate output, the ffi file. I have checked that the APIs in integration_test are working correctly.

I have not yet tested tizen home, as there are parts that require additional editing starting from the rootstrap level.

Are there any anticipated issues?

@seungsoo47

Copy link
Copy Markdown
Contributor

Have you tested this plugin in tizen-fs?

This PR removes the intermediate output, the ffi file. I have checked that the APIs in integration_test are working correctly.

I have not yet tested tizen home, as there are parts that require additional editing starting from the rootstrap level.

Are there any anticipated issues?

If this plugin works correctly with tizen-fs, there shouldn't be any issues.

@JSUYA

JSUYA commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

Have you tested this plugin in tizen-fs?

This PR removes the intermediate output, the ffi file. I have checked that the APIs in integration_test are working correctly.
I have not yet tested tizen home, as there are parts that require additional editing starting from the rootstrap level.
Are there any anticipated issues?

If this plugin works correctly with tizen-fs, there shouldn't be any issues.

I am currently merging this PR with the internal tizenfs branch. I will share the results after testing.

@JSUYA

JSUYA commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

Have you tested this plugin in tizen-fs?

This PR removes the intermediate output, the ffi file. I have checked that the APIs in integration_test are working correctly.
I have not yet tested tizen home, as there are parts that require additional editing starting from the rootstrap level.
Are there any anticipated issues?

If this plugin works correctly with tizen-fs, there shouldn't be any issues.

I am currently merging this PR with the internal tizenfs branch. I will share the results after testing.

Since tizen-fs uses the 9.0 API, I have create 9.0 bindings and rebased the commits for tizen-fs to conduct tests.
I have checked that each system operation of tizen-fs works without any issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants