44
55use crate :: error:: { AndromedaError , Result , read_file_with_context} ;
66use libsui:: { Elf , Macho , PortableExecutable } ;
7+ use serde:: { Deserialize , Serialize } ;
78use std:: { env:: current_exe, fs:: File , path:: Path } ;
89
910pub static ANDROMEDA_JS_CODE_SECTION : & str = "ANDROMEDABINCODE" ;
11+ pub static ANDROMEDA_CONFIG_SECTION : & str = "ANDROMEDACONFIG" ;
12+
13+ /// Configuration embedded in compiled binaries
14+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
15+ pub struct EmbeddedConfig {
16+ pub verbose : bool ,
17+ pub no_strict : bool ,
18+ }
1019
1120#[ allow( clippy:: result_large_err) ]
1221#[ cfg_attr( feature = "hotpath" , hotpath:: measure) ]
13- pub fn compile ( result_name : & Path , input_file : & Path ) -> Result < ( ) > {
22+ pub fn compile (
23+ result_name : & Path ,
24+ input_file : & Path ,
25+ verbose : bool ,
26+ no_strict : bool ,
27+ ) -> Result < ( ) > {
1428 // Validate input file exists and is readable
1529 if !input_file. exists ( ) {
1630 return Err ( AndromedaError :: file_not_found (
@@ -45,6 +59,16 @@ pub fn compile(result_name: &Path, input_file: &Path) -> Result<()> {
4559
4660 let js = js_content. into_bytes ( ) ;
4761
62+ // Create embedded config
63+ let config = EmbeddedConfig { verbose, no_strict } ;
64+ let config_json = serde_json:: to_vec ( & config) . map_err ( |e| {
65+ AndromedaError :: config_error (
66+ "Failed to serialize embedded config" . to_string ( ) ,
67+ None ,
68+ Some ( Box :: new ( e) ) ,
69+ )
70+ } ) ?;
71+
4872 // Validate output directory exists or can be created
4973 if let Some ( parent) = result_name. parent ( )
5074 && !parent. exists ( )
@@ -70,6 +94,7 @@ pub fn compile(result_name: &Path, input_file: &Path) -> Result<()> {
7094
7195 match os {
7296 "macos" => {
97+ // First pass: write JS code section
7398 Macho :: from ( exe)
7499 . map_err ( |e| {
75100 AndromedaError :: compile_error (
@@ -91,16 +116,54 @@ pub fn compile(result_name: &Path, input_file: &Path) -> Result<()> {
91116 . build_and_sign ( & mut out)
92117 . map_err ( |e| {
93118 AndromedaError :: compile_error (
94- "Failed to build and sign macOS executable" . to_string ( ) ,
119+ "Failed to build and sign macOS executable (first pass)" . to_string ( ) ,
120+ input_file. to_path_buf ( ) ,
121+ result_name. to_path_buf ( ) ,
122+ Some ( Box :: new ( e) ) ,
123+ )
124+ } ) ?;
125+
126+ // Second pass: re-read and add config section
127+ let exe_with_js = std:: fs:: read ( result_name)
128+ . map_err ( |e| AndromedaError :: file_read_error ( result_name. to_path_buf ( ) , e) ) ?;
129+ let mut out = File :: create ( result_name) . map_err ( |e| {
130+ AndromedaError :: permission_denied (
131+ format ! ( "creating output file {}" , result_name. display( ) ) ,
132+ Some ( result_name. to_path_buf ( ) ) ,
133+ e,
134+ )
135+ } ) ?;
136+ Macho :: from ( exe_with_js)
137+ . map_err ( |e| {
138+ AndromedaError :: compile_error (
139+ "Failed to parse macOS executable (second pass)" . to_string ( ) ,
140+ input_file. to_path_buf ( ) ,
141+ result_name. to_path_buf ( ) ,
142+ Some ( Box :: new ( e) ) ,
143+ )
144+ } ) ?
145+ . write_section ( ANDROMEDA_CONFIG_SECTION , config_json)
146+ . map_err ( |e| {
147+ AndromedaError :: compile_error (
148+ "Failed to write config section to macOS executable" . to_string ( ) ,
149+ input_file. to_path_buf ( ) ,
150+ result_name. to_path_buf ( ) ,
151+ Some ( Box :: new ( e) ) ,
152+ )
153+ } ) ?
154+ . build_and_sign ( & mut out)
155+ . map_err ( |e| {
156+ AndromedaError :: compile_error (
157+ "Failed to build and sign macOS executable (second pass)" . to_string ( ) ,
95158 input_file. to_path_buf ( ) ,
96159 result_name. to_path_buf ( ) ,
97160 Some ( Box :: new ( e) ) ,
98161 )
99162 } ) ?;
100163 }
101164 "linux" => {
102- Elf :: new ( & exe)
103- . append ( ANDROMEDA_JS_CODE_SECTION , & js, & mut out)
165+ let elf = Elf :: new ( & exe) ;
166+ elf . append ( ANDROMEDA_JS_CODE_SECTION , & js, & mut out)
104167 . map_err ( |e| {
105168 AndromedaError :: compile_error (
106169 "Failed to append JavaScript section to Linux executable" . to_string ( ) ,
@@ -109,6 +172,27 @@ pub fn compile(result_name: &Path, input_file: &Path) -> Result<()> {
109172 Some ( Box :: new ( e) ) ,
110173 )
111174 } ) ?;
175+ // Note: libsui's Elf doesn't support multiple appends in sequence
176+ // We need to re-read the file and append the config section
177+ let exe_with_js = std:: fs:: read ( result_name)
178+ . map_err ( |e| AndromedaError :: file_read_error ( result_name. to_path_buf ( ) , e) ) ?;
179+ let mut out = File :: create ( result_name) . map_err ( |e| {
180+ AndromedaError :: permission_denied (
181+ format ! ( "creating output file {}" , result_name. display( ) ) ,
182+ Some ( result_name. to_path_buf ( ) ) ,
183+ e,
184+ )
185+ } ) ?;
186+ Elf :: new ( & exe_with_js)
187+ . append ( ANDROMEDA_CONFIG_SECTION , & config_json, & mut out)
188+ . map_err ( |e| {
189+ AndromedaError :: compile_error (
190+ "Failed to append config section to Linux executable" . to_string ( ) ,
191+ input_file. to_path_buf ( ) ,
192+ result_name. to_path_buf ( ) ,
193+ Some ( Box :: new ( e) ) ,
194+ )
195+ } ) ?;
112196 }
113197 "windows" => {
114198 PortableExecutable :: from ( & exe)
@@ -129,6 +213,15 @@ pub fn compile(result_name: &Path, input_file: &Path) -> Result<()> {
129213 Some ( Box :: new ( e) ) ,
130214 )
131215 } ) ?
216+ . write_resource ( ANDROMEDA_CONFIG_SECTION , config_json)
217+ . map_err ( |e| {
218+ AndromedaError :: compile_error (
219+ "Failed to write config resource to Windows executable" . to_string ( ) ,
220+ input_file. to_path_buf ( ) ,
221+ result_name. to_path_buf ( ) ,
222+ Some ( Box :: new ( e) ) ,
223+ )
224+ } ) ?
132225 . build ( & mut out)
133226 . map_err ( |e| {
134227 AndromedaError :: compile_error (
0 commit comments