Skip to content

Commit ab8fb37

Browse files
committed
Add bindgen Swift templates & update submodule
Add a new bindgen toolset to generate Swift wrappers from the C++ API: includes bindgen/config.yaml (clang flags, entry headers, type mappings, naming rules and symbol overrides), bindgen/template/ (swift.j2 and partials for types, enums, functions, classes, constants, aliases), bindgen/README.md with usage, and bindgen/.gitignore to ignore /out. Also update Sources/CNativeAPI submodule to commit ef88f36. Generated wrappers call existing C API symbols from CNativeAPI.
1 parent 2c8513c commit ab8fb37

14 files changed

Lines changed: 792 additions & 1 deletion

File tree

Sources/CNativeAPI

Submodule CNativeAPI updated 148 files

bindgen/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/out

bindgen/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Bindgen Swift Wrapper
2+
3+
Swift wrapper generation from C++ API headers.
4+
5+
- Input: `Sources/CNativeAPI/src/**/*.h` (excluding `capi` and `platform`)
6+
- Output: `bindgen/out/**/*.swift`
7+
- FFI policy: generated wrappers call existing C API symbols from `CNativeAPI`
8+
9+
## Run
10+
11+
```bash
12+
cd nativeapi-swift
13+
PYTHONPATH=Sources/CNativeAPI/tools python3 -m bindgen \
14+
--config bindgen/config.yaml \
15+
--dump-ir bindgen/out/ir.json \
16+
--out bindgen/out
17+
```
18+
19+
## Symbol Mapping
20+
21+
Default mapping:
22+
- Free function: `FooBar` -> `native_foo_bar`
23+
- Method: `Class::Method` -> `native_class_method`
24+
25+
Override mapping in `mapping.options.symbol_overrides` when needed.

bindgen/config.yaml

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
clang_flags:
2+
- -x
3+
- c++
4+
- -std=c++17
5+
6+
entry_headers:
7+
- Sources/CNativeAPI/src/accessibility_manager.h
8+
- Sources/CNativeAPI/src/application.h
9+
- Sources/CNativeAPI/src/application_event.h
10+
- Sources/CNativeAPI/src/autostart.h
11+
- Sources/CNativeAPI/src/dialog.h
12+
- Sources/CNativeAPI/src/display.h
13+
- Sources/CNativeAPI/src/display_event.h
14+
- Sources/CNativeAPI/src/display_manager.h
15+
- Sources/CNativeAPI/src/foundation/color.h
16+
- Sources/CNativeAPI/src/foundation/event.h
17+
- Sources/CNativeAPI/src/foundation/event_emitter.h
18+
- Sources/CNativeAPI/src/foundation/geometry.h
19+
- Sources/CNativeAPI/src/foundation/id_allocator.h
20+
- Sources/CNativeAPI/src/foundation/keyboard.h
21+
- Sources/CNativeAPI/src/foundation/native_object_provider.h
22+
- Sources/CNativeAPI/src/foundation/object_registry.h
23+
- Sources/CNativeAPI/src/image.h
24+
- Sources/CNativeAPI/src/keyboard_event.h
25+
- Sources/CNativeAPI/src/keyboard_monitor.h
26+
- Sources/CNativeAPI/src/menu.h
27+
- Sources/CNativeAPI/src/menu_event.h
28+
- Sources/CNativeAPI/src/message_dialog.h
29+
- Sources/CNativeAPI/src/placement.h
30+
- Sources/CNativeAPI/src/positioning_strategy.h
31+
- Sources/CNativeAPI/src/preferences.h
32+
- Sources/CNativeAPI/src/secure_storage.h
33+
- Sources/CNativeAPI/src/shortcut.h
34+
- Sources/CNativeAPI/src/shortcut_event.h
35+
- Sources/CNativeAPI/src/shortcut_manager.h
36+
- Sources/CNativeAPI/src/storage.h
37+
- Sources/CNativeAPI/src/tray_icon.h
38+
- Sources/CNativeAPI/src/tray_icon_event.h
39+
- Sources/CNativeAPI/src/tray_manager.h
40+
- Sources/CNativeAPI/src/url_opener.h
41+
- Sources/CNativeAPI/src/window.h
42+
- Sources/CNativeAPI/src/window_event.h
43+
- Sources/CNativeAPI/src/window_manager.h
44+
- Sources/CNativeAPI/src/window_registry.h
45+
46+
include_paths:
47+
- Sources/CNativeAPI/src
48+
- Sources/CNativeAPI/include
49+
50+
mapping:
51+
language: swift
52+
output_note: Generated wrapper from C++ API. Calls existing C API bindings from CNativeAPI.
53+
54+
naming:
55+
file_name: pascal_case
56+
type_name: pascal_case
57+
enum_name: pascal_case
58+
enum_value_name: camel_case
59+
function_name: camel_case
60+
method_name: camel_case
61+
class_name: pascal_case
62+
field_name: camel_case
63+
param_name: camel_case
64+
constant_name: camel_case
65+
alias_name: pascal_case
66+
strip_prefixes:
67+
- na_
68+
- NA_
69+
- nativeapi_
70+
- NATIVEAPI_
71+
strip_suffixes:
72+
- _t
73+
- _T
74+
add_prefix: ""
75+
add_suffix: ""
76+
77+
types:
78+
void: Void
79+
bool: Bool
80+
_Bool: Bool
81+
char: Int8
82+
short: Int16
83+
int: Int32
84+
long: Int64
85+
"long long": Int64
86+
int8_t: Int8
87+
int16_t: Int16
88+
int32_t: Int32
89+
int64_t: Int64
90+
int8: Int8
91+
int16: Int16
92+
int32: Int32
93+
int64: Int64
94+
ssize_t: Int
95+
intptr_t: Int
96+
ptrdiff_t: Int
97+
"unsigned char": UInt8
98+
"unsigned short": UInt16
99+
"unsigned int": UInt32
100+
"unsigned long": UInt64
101+
"unsigned long long": UInt64
102+
uint8_t: UInt8
103+
uint16_t: UInt16
104+
uint32_t: UInt32
105+
uint64_t: UInt64
106+
uint8: UInt8
107+
uint16: UInt16
108+
uint32: UInt32
109+
uint64: UInt64
110+
size_t: UInt
111+
uintptr_t: UInt
112+
float: Float
113+
double: Double
114+
float32: Float
115+
float64: Double
116+
"long double": Double
117+
"char*": UnsafeMutablePointer<CChar>
118+
"const char*": UnsafePointer<CChar>
119+
"void*": UnsafeMutableRawPointer
120+
"const void*": UnsafeRawPointer
121+
cstring: UnsafePointer<CChar>
122+
nativeapi::Point: Point
123+
nativeapi::Size: Size
124+
nativeapi::Rectangle: Rect
125+
"const nativeapi::Point": Point
126+
"const nativeapi::Size": Size
127+
"const nativeapi::Rectangle": Rect
128+
nativeapi::Window: Window
129+
nativeapi::Display: Display
130+
nativeapi::Menu: Menu
131+
nativeapi::TrayIcon: TrayIcon
132+
function_pointer: "@convention(c) () -> Void"
133+
134+
default_type: Any
135+
passthrough_unknown: false
136+
137+
options:
138+
singleton_classes:
139+
- AccessibilityManager
140+
- Application
141+
- DisplayManager
142+
- TrayManager
143+
- WindowManager
144+
api_type_rules:
145+
exact:
146+
dynamic: Any
147+
contains:
148+
- match: Pointer<CChar>
149+
type: String
150+
- match: "&"
151+
type: UnsafeMutableRawPointer
152+
- match: "::"
153+
type: Any
154+
return_bridge_map:
155+
String: string
156+
Point: point
157+
Size: size
158+
Rect: rect
159+
cstring_free_symbols:
160+
default: free_c_str
161+
window: native_window_free_string
162+
bridge_types:
163+
point: Point
164+
size: Size
165+
rect: Rect
166+
param_bridges:
167+
- type_key: point
168+
symbol_suffixes:
169+
- _set_position
170+
args:
171+
- "{name}.x"
172+
- "{name}.y"
173+
- type_key: size
174+
symbol_suffixes:
175+
- _set_size
176+
- _set_content_size
177+
- _set_minimum_size
178+
- _set_maximum_size
179+
args:
180+
- "{name}.width"
181+
- "{name}.height"
182+
- type_key: rect
183+
symbol_suffixes:
184+
- _set_bounds
185+
- _set_content_bounds
186+
args:
187+
- "{name}.cStruct"
188+
symbol_overrides:
189+
nativeapi::RunApp: native_run_app
190+
nativeapi::Application::GetInstance: native_application_get_instance
191+
nativeapi::Window::Window: native_window_create
192+
formatters:
193+
- name: swiftformat-generated
194+
cmd:
195+
- swiftformat
196+
- "{out_dir}/src"
197+
continue_on_error: true
198+
199+
filters:
200+
allowlist_regex: []
201+
denylist_regex: []
202+
exclude_dirs:
203+
- capi
204+
- platform

bindgen/scripts/compare_bindgen.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
from __future__ import annotations
3+
4+
import argparse
5+
import difflib
6+
import json
7+
from pathlib import Path
8+
9+
10+
def collect(dir_path: Path, ext: str) -> dict[str, Path]:
11+
return {p.name: p for p in dir_path.rglob(f"*{ext}")}
12+
13+
14+
def analyze(existing: Path, generated: Path) -> dict:
15+
e_map = collect(existing, ".swift")
16+
g_map = collect(generated, ".swift")
17+
common = sorted(set(e_map) & set(g_map))
18+
report = {
19+
"existing_count": len(e_map),
20+
"generated_count": len(g_map),
21+
"common_count": len(common),
22+
"common": [],
23+
}
24+
for name in common:
25+
e_text = e_map[name].read_text(encoding="utf-8", errors="ignore").splitlines()
26+
g_text = g_map[name].read_text(encoding="utf-8", errors="ignore").splitlines()
27+
diff = list(difflib.unified_diff(e_text, g_text, n=0))
28+
g_raw = "\n".join(g_text)
29+
report["common"].append(
30+
{
31+
"file": name,
32+
"diff_lines": len(diff),
33+
"contains_any": "Any" in g_raw,
34+
"contains_native_call": "native_" in g_raw,
35+
"contains_singleton": "static let shared" in g_raw,
36+
}
37+
)
38+
return report
39+
40+
41+
def main() -> int:
42+
parser = argparse.ArgumentParser()
43+
parser.add_argument("--existing", required=True)
44+
parser.add_argument("--generated", required=True)
45+
parser.add_argument("--out", required=True)
46+
args = parser.parse_args()
47+
48+
result = analyze(Path(args.existing), Path(args.generated))
49+
out = Path(args.out)
50+
out.parent.mkdir(parents=True, exist_ok=True)
51+
out.write_text(json.dumps(result, indent=2), encoding="utf-8")
52+
return 0
53+
54+
55+
if __name__ == "__main__":
56+
raise SystemExit(main())
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: 1
2+
language: swift
3+
module_profiles:
4+
singleton_manager:
5+
classes:
6+
- AccessibilityManager
7+
- Application
8+
- DisplayManager
9+
- TrayManager
10+
- WindowManager
11+
native_handle_wrapper:
12+
base_class: BaseNativeHandleWrapper
13+
value_bridges:
14+
point: Point
15+
size: Size
16+
rect: Rect
17+
event_model:
18+
base: BaseEventEmitter
19+
protocol: Event
20+
conventions:
21+
getter_to_property: true
22+
bool_getter_to_property: true
23+
skip_ctor_dtor_methods: true
24+
string_free_default: free_c_str
25+
string_free_overrides:
26+
native_window_get_title: native_window_free_string

bindgen/spec/symbol_map.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 1
2+
language: swift
3+
explicit:
4+
nativeapi::RunApp: native_run_app
5+
nativeapi::Application::GetInstance: native_application_get_instance
6+
nativeapi::DisplayManager::GetInstance: native_display_manager_get_instance
7+
nativeapi::WindowManager::GetInstance: native_window_manager_get_instance
8+
nativeapi::TrayManager::GetInstance: native_tray_manager_get_instance
9+
defaults:
10+
function: native_{snake(name)}
11+
method: native_{snake(class)}_{snake(method)}

0 commit comments

Comments
 (0)