@@ -33,6 +33,26 @@ def find_compiler():
3333 raise RuntimeError ('Unable to locate a compiler for preprocessing assembly' )
3434
3535
36+ def find_armasm64 ():
37+ """Find armasm64.exe in the PATH or common Visual Studio locations."""
38+ # First check PATH
39+ path = shutil .which ('armasm64.exe' )
40+ if path :
41+ return path
42+
43+ # Check common VS locations via environment
44+ vc_install_dir = os .environ .get ('VCINSTALLDIR' , '' )
45+ if vc_install_dir :
46+ candidate = os .path .join (vc_install_dir , 'bin' , 'Hostx64' , 'arm64' , 'armasm64.exe' )
47+ if os .path .exists (candidate ):
48+ return candidate
49+ candidate = os .path .join (vc_install_dir , 'bin' , 'Hostarm64' , 'arm64' , 'armasm64.exe' )
50+ if os .path .exists (candidate ):
51+ return candidate
52+
53+ raise RuntimeError ('Unable to locate armasm64.exe' )
54+
55+
3656def normalize_path (value ):
3757 return str (value ).strip ().strip ('"' )
3858
@@ -73,20 +93,37 @@ def preprocess(args):
7393 sys .stderr .write (result .stderr )
7494 raise RuntimeError (f'Preprocessing failed: { " " .join (command )} ' )
7595
76- # Strip preprocessor line directives that some assemblers can't handle
77- # (e.g., armasm64.exe doesn't accept #line directives)
78- cleaned = re .sub (r'^#\s*\d+\s+"[^"]*".*$' , '' , result .stdout , flags = re .MULTILINE )
79- cleaned = re .sub (r'^#\s*line\s+\d+.*$' , '' , cleaned , flags = re .MULTILINE )
96+ # Strip all preprocessor directives that assemblers can't handle
97+ # (e.g., armasm64.exe doesn't accept any # directives)
98+ # Remove lines starting with # (preprocessor output like #line, # 1 "file", etc.)
99+ lines = result .stdout .splitlines (keepends = True )
100+ cleaned_lines = [line for line in lines if not line .lstrip ().startswith ('#' )]
101+ cleaned = '' .join (cleaned_lines )
80102
81103 output .write_text (cleaned , encoding = 'utf-8' )
82104
105+ # If --assemble is specified, also run the assembler to produce an object file
106+ if args .assemble :
107+ assemble_output = Path (normalize_path (args .assemble ))
108+ assemble_output .parent .mkdir (parents = True , exist_ok = True )
109+
110+ armasm64 = find_armasm64 ()
111+ asm_command = [armasm64 , '-nologo' , '-g' , str (output ), '-o' , str (assemble_output )]
112+
113+ asm_result = subprocess .run (asm_command , capture_output = True , text = True )
114+ if asm_result .returncode != 0 :
115+ sys .stderr .write (asm_result .stderr )
116+ sys .stderr .write (asm_result .stdout )
117+ raise RuntimeError (f'Assembly failed: { " " .join (asm_command )} ' )
118+
83119
84120def main (argv = None ):
85121 parser = argparse .ArgumentParser (description = 'Preprocess libffi assembly source' )
86122 parser .add_argument ('--input' , required = True )
87123 parser .add_argument ('--output' , required = True )
88124 parser .add_argument ('--include-dir' , action = 'append' , default = [])
89125 parser .add_argument ('--define' , action = 'append' , default = [])
126+ parser .add_argument ('--assemble' , help = 'Also assemble the output to this object file' )
90127 args = parser .parse_args (argv )
91128
92129 preprocess (args )
0 commit comments