@@ -291,6 +291,12 @@ def process_typedecl(self, node):
291291 if node .coord is None or coord .find (include_dir ) != - 1 :
292292 typedecl = f"{ self .generator .visit (node )} ;"
293293 typedecl = ARRAY_SIZEOF_PATTERN .sub ("[...]" , typedecl )
294+
295+ # Fix _Bool array compatibility issues
296+ # Replace _Bool arrays with unsigned char arrays for CFFI compatibility
297+ typedecl = re .sub (r"\b_Bool\s*\[([^\]]*)\]" , r"unsigned char[\1]" , typedecl )
298+ typedecl = re .sub (r"\bbool\s*\[([^\]]*)\]" , r"unsigned char[\1]" , typedecl )
299+
294300 if typedecl not in self .typedecls :
295301 self .typedecls .append (typedecl )
296302
@@ -572,6 +578,7 @@ def preprocess_header_manually(header_path):
572578 """Manually preprocess a header file by expanding simple #define statements.
573579
574580 This is a fallback for when no C preprocessor is available.
581+ This version is much more conservative to preserve header structure.
575582 """
576583 with open (header_path , "r" , encoding = "utf-8" , errors = "ignore" ) as f :
577584 content = f .read ()
@@ -585,54 +592,30 @@ def preprocess_header_manually(header_path):
585592 # Remove // style comments
586593 content = re .sub (r"//.*" , "" , content )
587594
588- # Simple define replacements for common patterns
589- defines = {
590- "SMPT_EXPORTS" : "" ,
591- "SMPT_DLL" : "" ,
592- "UC_MAIN" : "" ,
593- "__cplusplus" : "" ,
594- "_Bool" : "unsigned char" , # Use unsigned char for better compatibility
595- "bool" : "unsigned char" ,
596- "true" : "1" ,
597- "false" : "0" ,
598- }
595+ # Very conservative preprocessing - only fix things that definitely break pycparser
596+ # Don't mess with complex #define statements or conditional compilation
599597
600- # Add platform-specific defines
601- if platform .system () == "Windows" :
602- defines ["_WIN32" ] = "1"
603- defines ["_MSC_VER" ] = "1900"
604- defines ["_WINDOWS" ] = "1"
605- elif platform .system () == "Linux" :
606- defines ["__linux__" ] = "1"
607- defines ["__unix__" ] = "1"
608- else : # Darwin/macOS
609- defines ["__APPLE__" ] = "1"
610- defines ["__MACH__" ] = "1"
611-
612- # Replace simple #define statements and clean up
613- for define , value in defines .items ():
614- # Add proper #define if not already present
615- if f"#define { define } " not in content :
616- content = f"#define { define } { value } \n " + content
617- # Also handle direct usage
618- content = content .replace (f"#{ define } " , f"#define { define } { value } " )
619-
620- # Add essential type definitions that might be missing
621- essential_types = """
622- #ifndef __STDC_VERSION__
623- #define __STDC_VERSION__ 199901L
624- #endif
598+ # Handle _Bool arrays specifically for compatibility
599+ # Replace _Bool arrays with unsigned char arrays to fix CFFI type issues
600+ content = re .sub (r"\b_Bool\s*\[([^\]]*)\]" , r"unsigned char[\1]" , content )
601+ content = re .sub (r"\bbool\s*\[([^\]]*)\]" , r"unsigned char[\1]" , content )
625602
603+ # Only add the most essential type definitions that pycparser needs
604+ # Don't redefine __STDC_VERSION__ - that causes the macOS redefinition warning
605+ essential_types = """
606+ /* Minimal essential types for pycparser - don't redefine __STDC_VERSION__ */
626607#ifndef __bool_true_false_are_defined
627608#define __bool_true_false_are_defined 1
628609typedef unsigned char _Bool;
629610#endif
630611
631612#ifndef __cplusplus
613+ #ifndef bool
632614#define bool _Bool
633615#define true 1
634616#define false 0
635617#endif
618+ #endif
636619
637620/* Define common GCC attributes away */
638621#define __attribute__(x)
@@ -642,9 +625,6 @@ def preprocess_header_manually(header_path):
642625#define __always_inline
643626#define __builtin_va_list char*
644627#define __asm__(x)
645- #define __signed__ signed
646- #define __const const
647- #define __volatile__ volatile
648628
649629"""
650630 content = essential_types + content
@@ -695,9 +675,10 @@ def try_parse_with_better_args(header_path, header_name):
695675 "-DSMPT_EXPORTS=" ,
696676 "-DSMPT_DLL=" ,
697677 "-DUC_MAIN=" ,
698- # Add stdbool.h compatibility
678+ # Add stdbool.h compatibility - but don't override built-in __STDC_VERSION__
699679 "-D__bool_true_false_are_defined=1" ,
700- "-D__STDC_VERSION__=199901L" ,
680+ # Don't redefine __STDC_VERSION__ - let the compiler use its built-in value
681+ # This prevents the "macro redefined" warning on macOS
701682 ],
702683 },
703684 # Fallback 1: cpp with minimal args only
@@ -714,6 +695,7 @@ def try_parse_with_better_args(header_path, header_name):
714695 "-DSMPT_API=" , # Define away SMPT_API
715696 "-DSMPT_EXPORTS=" ,
716697 "-DSMPT_DLL=" ,
698+ # Don't add any manual constants here - let the headers define them naturally
717699 ],
718700 },
719701 # Fallback 2: no cpp at all
@@ -840,29 +822,35 @@ def try_parse_with_better_args(header_path, header_name):
840822 )
841823
842824defines = set ()
843- for header_path in HEADERS :
844- with open (os .sep .join ([include_dir , header_path ])) as header_file :
845- header = header_file .read ()
846- for match in DEFINE_PATTERN .finditer (header ):
847- if (
848- match .group (1 ) in DEFINE_BLACKLIST
849- or match .group (1 ) in collector .typedecls
850- or match .group (1 ) in collector .functions
851- ):
852- continue
853- try :
854- int (match .group (2 ), 0 )
855- defines .add (f"#define { match .group (1 )} { match .group (2 )} " )
856- except Exception :
857- defines .add (f"#define { match .group (1 )} ..." )
858825
826+ # Don't manually add constants - let them be parsed from headers naturally
827+ # This prevents issues with conditional compilation and macro redefinition
828+
829+ for header_path in HEADERS :
830+ header_full_path = os .sep .join ([include_dir , header_path ])
831+ if os .path .exists (header_full_path ):
832+ with open (header_full_path , encoding = "utf-8" , errors = "ignore" ) as header_file :
833+ header = header_file .read ()
834+ for match in DEFINE_PATTERN .finditer (header ):
835+ if (
836+ match .group (1 ) in DEFINE_BLACKLIST
837+ or match .group (1 ) in collector .typedecls
838+ or match .group (1 ) in collector .functions
839+ ):
840+ continue
841+ try :
842+ int (match .group (2 ), 0 )
843+ defines .add (f"#define { match .group (1 )} { match .group (2 )} " )
844+ except Exception :
845+ defines .add (f"#define { match .group (1 )} ..." )
859846print (
860847 f"Processing { len (defines )} defines, { len (collector .typedecls )} types, "
861848 f"{ len (collector .functions )} functions"
862849)
863850
864851cdef = "\n " .join (itertools .chain (* [defines , collector .typedecls , collector .functions ]))
865852
853+ # Post-process the cdef to fix any remaining compatibility issues
866854cdef = cdef .replace ("[Smpt_Length_Max_Packet_Size]" , "[1200]" )
867855cdef = cdef .replace ("[Smpt_Length_Packet_Input_Buffer_Rows]" , "[100]" )
868856cdef = cdef .replace (
@@ -874,6 +862,11 @@ def try_parse_with_better_args(header_path, header_name):
874862cdef = cdef .replace ("[Smpt_Length_Points]" , "[16]" )
875863cdef = cdef .replace ("[Smpt_Length_Number_Of_Channels]" , "[8]" )
876864
865+ # Final cleanup: ensure all _Bool arrays are converted to unsigned char arrays
866+ # This handles any cases that might have been missed during parsing
867+ cdef = re .sub (r"\b_Bool\s*\[([^\]]*)\]" , r"unsigned char[\1]" , cdef )
868+ cdef = re .sub (r"\bbool\s*\[([^\]]*)\]" , r"unsigned char[\1]" , cdef )
869+
877870# Fix platform-specific field errors
878871if "serial_port_handle_" in cdef and not sys .platform .startswith ("win" ):
879872 # Remove the Windows-specific field for non-Windows platforms
0 commit comments