22"""
33Script to regenerate bindings by:
441. Pulling latest cxx_impl submodule
5- 2. Updating macos/Classes/cnativeapi.mm include statements
6- 3. Updating ios/Classes/cnativeapi.mm include statements
7- 4. Updating ffigen.yaml with all C API header files
8- 5. Generating bindings with ffigen
5+ 2. Updating macos/cnativeapi/Sources/cnativeapi/cnativeapi.mm include statements
6+ 3. Updating ios/cnativeapi/Sources/cnativeapi/cnativeapi.mm include statements
7+ 4. Updating macos/cnativeapi/Sources/cnativeapi/include/cnativeapi.h
8+ 5. Updating ios/cnativeapi/Sources/cnativeapi/include/cnativeapi.h
9+ 6. Updating ffigen.yaml with all C API header files
10+ 7. Generating bindings with ffigen
911"""
1012
1113import os
@@ -67,9 +69,95 @@ def find_capi_headers(cxx_impl_dir):
6769 return sorted (headers )
6870
6971
72+ def find_cpp_headers (cxx_impl_dir ):
73+ """Find all C++ API header files (*.h) in cxx_impl/src, excluding capi/ and platform/."""
74+ src_dir = cxx_impl_dir / "src"
75+ if not src_dir .exists ():
76+ return []
77+
78+ headers = []
79+ # Find all .h files in src/ and subdirectories, excluding capi/ and platform/
80+ for header_file in src_dir .rglob ("*.h" ):
81+ file_str = str (header_file )
82+ # Skip capi/ and platform/ directories
83+ if "/capi/" in file_str or "/platform/" in file_str :
84+ continue
85+ # Calculate relative path from cnativeapi.h location
86+ # cnativeapi.h is at packages/cnativeapi/{platform}/cnativeapi/Sources/cnativeapi/include/
87+ # cxx_impl is at packages/cnativeapi/cxx_impl/
88+ # So relative path should be ../../../../../cxx_impl/src/...
89+ rel_path = os .path .relpath (header_file , cxx_impl_dir .parent )
90+ headers .append ((rel_path , header_file ))
91+
92+ # Sort by path for consistent ordering
93+ headers .sort (key = lambda x : x [0 ])
94+ return [h [0 ] for h in headers ]
95+
96+
97+ def update_cnativeapi_h (header_path , cxx_impl_dir ):
98+ """Update cnativeapi.h file with C++ and C API header includes."""
99+ print (f"Updating { header_path .name } ..." )
100+
101+ # Find all C++ API headers (returns paths relative to cxx_impl_dir.parent)
102+ cpp_headers = find_cpp_headers (cxx_impl_dir )
103+ print (f" Found { len (cpp_headers )} C++ API headers" )
104+
105+ # Find all C API headers (returns paths relative to cxx_impl_dir.parent)
106+ capi_headers = find_capi_headers (cxx_impl_dir )
107+ print (f" Found { len (capi_headers )} C API headers" )
108+
109+ # Calculate relative path from header_path to cxx_impl_dir
110+ # header_path is at packages/cnativeapi/{platform}/cnativeapi/Sources/cnativeapi/include/
111+ # cxx_impl_dir is at packages/cnativeapi/cxx_impl/
112+ cxx_impl_rel = os .path .relpath (cxx_impl_dir , header_path .parent )
113+
114+ # Generate C++ includes
115+ cpp_includes = []
116+ for header in cpp_headers :
117+ # header is like "cxx_impl/src/accessibility_manager.h"
118+ # Need to convert to relative path from header_path
119+ # Join cxx_impl_rel with the part after "cxx_impl/"
120+ if header .startswith ("cxx_impl/" ):
121+ rel_path = os .path .join (cxx_impl_rel , header [len ("cxx_impl/" ):])
122+ else :
123+ rel_path = os .path .join (cxx_impl_rel , "src" , header )
124+ # Normalize path separators
125+ rel_path = rel_path .replace ("\\ " , "/" )
126+ cpp_includes .append (f'#include "{ rel_path } "' )
127+
128+ # Generate C API includes
129+ capi_includes = []
130+ for header in capi_headers :
131+ # header is like "cxx_impl/src/capi/accessibility_manager_c.h"
132+ # Need to convert to relative path from header_path
133+ if header .startswith ("cxx_impl/" ):
134+ rel_path = os .path .join (cxx_impl_rel , header [len ("cxx_impl/" ):])
135+ else :
136+ rel_path = os .path .join (cxx_impl_rel , "src" , "capi" , header )
137+ # Normalize path separators
138+ rel_path = rel_path .replace ("\\ " , "/" )
139+ capi_includes .append (f'#include "{ rel_path } "' )
140+
141+ # Generate header file content
142+ content = "#pragma once\n \n "
143+ content += "#ifdef __cplusplus\n "
144+ content += "// C++ API headers\n "
145+ content += "\n " .join (cpp_includes ) + "\n "
146+ content += "#endif\n \n "
147+ content += "// C API headers (available for both C and C++)\n "
148+ content += "\n " .join (capi_includes ) + "\n "
149+
150+ # Write header file
151+ with open (header_path , "w" , encoding = "utf-8" ) as f :
152+ f .write (content )
153+
154+ print (f" Updated { header_path .name } successfully" )
155+ return True
156+
157+
70158def update_ffigen_yaml (ffigen_path , capi_headers ):
71159 """Update ffigen.yaml with all C API header files."""
72- print ("\n Step 4/5 : Updating ffigen configuration" )
160+ print ("\n Step 6/7 : Updating ffigen configuration" )
73161 print (f"Found { len (capi_headers )} C API header files to process..." )
74162
75163 with open (ffigen_path , "r" , encoding = "utf-8" ) as f :
@@ -214,9 +302,9 @@ def update_nativeapi_mm(nativeapi_path, cxx_impl_dir, platform):
214302 file_str = str (file_path )
215303
216304 # Calculate relative path from cnativeapi.mm location
217- # cnativeapi.mm is at packages/cnativeapi/{platform}/Classes /
305+ # cnativeapi.mm is at packages/cnativeapi/{platform}/cnativeapi/Sources/cnativeapi /
218306 # cxx_impl is at packages/cnativeapi/cxx_impl/
219- # So relative path should be ../../cxx_impl/src/...
307+ # So relative path should be ../../../../ cxx_impl/src/...
220308 rel_path = os .path .relpath (file_path , nativeapi_path .parent )
221309
222310 if "/capi/" in file_str :
@@ -243,12 +331,16 @@ def update_nativeapi_mm(nativeapi_path, cxx_impl_dir, platform):
243331 print (f" - Foundation files: { len (foundation_files )} " )
244332 print (f" - Core files: { len (core_files )} " )
245333
246- # Build the new include section (no trailing newline, match original format)
334+ # Build the new include section
247335 new_include_section = match .group (1 ) + "\n " .join (new_includes )
248336
249337 # Replace the old include section with the new one
250338 new_content = content [: match .start ()] + new_include_section
251339
340+ # Ensure file ends with a newline
341+ if not new_content .endswith ("\n " ):
342+ new_content += "\n "
343+
252344 # Write back to file
253345 with open (nativeapi_path , "w" , encoding = "utf-8" ) as f :
254346 f .write (new_content )
@@ -257,10 +349,10 @@ def update_nativeapi_mm(nativeapi_path, cxx_impl_dir, platform):
257349
258350
259351def update_macos_mm (cnativeapi_dir , cxx_impl_dir ):
260- """Update macos/Classes /cnativeapi.mm."""
261- print ("\n Step 2/5 : Updating macOS platform bindings" )
352+ """Update macos/cnativeapi/Sources/cnativeapi /cnativeapi.mm."""
353+ print ("\n Step 2/7 : Updating macOS platform bindings" )
262354
263- macos_mm_path = cnativeapi_dir / "macos/Classes /cnativeapi.mm"
355+ macos_mm_path = cnativeapi_dir / "macos/cnativeapi/Sources/cnativeapi /cnativeapi.mm"
264356
265357 if not macos_mm_path .exists ():
266358 print (f"Error: { macos_mm_path } not found" )
@@ -275,10 +367,10 @@ def update_macos_mm(cnativeapi_dir, cxx_impl_dir):
275367
276368
277369def update_ios_mm (cnativeapi_dir , cxx_impl_dir ):
278- """Update ios/Classes /cnativeapi.mm."""
279- print ("\n Step 3/5 : Updating iOS platform bindings" )
370+ """Update ios/cnativeapi/Sources/cnativeapi /cnativeapi.mm."""
371+ print ("\n Step 3/7 : Updating iOS platform bindings" )
280372
281- ios_mm_path = cnativeapi_dir / "ios/Classes /cnativeapi.mm"
373+ ios_mm_path = cnativeapi_dir / "ios/cnativeapi/Sources/cnativeapi /cnativeapi.mm"
282374
283375 if not ios_mm_path .exists ():
284376 print (f"Error: { ios_mm_path } not found" )
@@ -292,6 +384,42 @@ def update_ios_mm(cnativeapi_dir, cxx_impl_dir):
292384 return False
293385
294386
387+ def update_macos_h (cnativeapi_dir , cxx_impl_dir ):
388+ """Update macos/cnativeapi/Sources/cnativeapi/include/cnativeapi.h."""
389+ print ("\n Step 4/7: Updating macOS header file" )
390+
391+ macos_h_path = cnativeapi_dir / "macos/cnativeapi/Sources/cnativeapi/include/cnativeapi.h"
392+
393+ if not macos_h_path .exists ():
394+ print (f"Error: { macos_h_path } not found" )
395+ return False
396+
397+ if update_cnativeapi_h (macos_h_path , cxx_impl_dir ):
398+ print ("macOS header updated successfully" )
399+ return True
400+ else :
401+ print ("Failed to update macOS header" )
402+ return False
403+
404+
405+ def update_ios_h (cnativeapi_dir , cxx_impl_dir ):
406+ """Update ios/cnativeapi/Sources/cnativeapi/include/cnativeapi.h."""
407+ print ("\n Step 5/7: Updating iOS header file" )
408+
409+ ios_h_path = cnativeapi_dir / "ios/cnativeapi/Sources/cnativeapi/include/cnativeapi.h"
410+
411+ if not ios_h_path .exists ():
412+ print (f"Error: { ios_h_path } not found" )
413+ return False
414+
415+ if update_cnativeapi_h (ios_h_path , cxx_impl_dir ):
416+ print ("iOS header updated successfully" )
417+ return True
418+ else :
419+ print ("Failed to update iOS header" )
420+ return False
421+
422+
295423def main ():
296424 """Main function to regenerate bindings."""
297425 cnativeapi_dir = Path (__file__ ).parent
@@ -310,17 +438,27 @@ def main():
310438 print (f"\n Error: cxx_impl directory not found: { cxx_impl_dir } " )
311439 return 1
312440
313- # Step 2: Update macos/Classes /cnativeapi.mm
441+ # Step 2: Update macos/cnativeapi/Sources/cnativeapi /cnativeapi.mm
314442 if not update_macos_mm (cnativeapi_dir , cxx_impl_dir ):
315443 print ("\n Error: macOS bindings update failed" )
316444 return 1
317445
318- # Step 3: Update ios/Classes /cnativeapi.mm
446+ # Step 3: Update ios/cnativeapi/Sources/cnativeapi /cnativeapi.mm
319447 if not update_ios_mm (cnativeapi_dir , cxx_impl_dir ):
320448 print ("\n Error: iOS bindings update failed" )
321449 return 1
322450
323- # Step 4: Update ffigen.yaml
451+ # Step 4: Update macos/cnativeapi/Sources/cnativeapi/include/cnativeapi.h
452+ if not update_macos_h (cnativeapi_dir , cxx_impl_dir ):
453+ print ("\n Error: macOS header update failed" )
454+ return 1
455+
456+ # Step 5: Update ios/cnativeapi/Sources/cnativeapi/include/cnativeapi.h
457+ if not update_ios_h (cnativeapi_dir , cxx_impl_dir ):
458+ print ("\n Error: iOS header update failed" )
459+ return 1
460+
461+ # Step 6: Update ffigen.yaml
324462 capi_headers = find_capi_headers (cxx_impl_dir )
325463 if not capi_headers :
326464 print ("\n Warning: No C API headers found in cxx_impl" )
@@ -329,8 +467,8 @@ def main():
329467 print ("\n Error: Failed to update ffigen configuration" )
330468 return 1
331469
332- # Step 5 : Generate bindings using ffigen
333- print ("\n Step 5/5 : Generating Dart bindings" )
470+ # Step 7 : Generate bindings using ffigen
471+ print ("\n Step 7/7 : Generating Dart bindings" )
334472 print ("Running ffigen to generate Dart bindings from C headers..." )
335473
336474 ffigen_cmd = ["dart" , "run" , "ffigen" , "--config" , "ffigen.yaml" ]
0 commit comments