@@ -3,9 +3,18 @@ use std::path::PathBuf;
33
44fn main ( ) {
55 let out_dir = PathBuf :: from ( env:: var ( "OUT_DIR" ) . unwrap ( ) ) ;
6- let target_dir = PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) . unwrap ( ) )
7- . join ( "target" )
8- . join ( env:: var ( "PROFILE" ) . unwrap_or ( "release" . into ( ) ) ) ;
6+ let manifest_dir = PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) . unwrap ( ) ) ;
7+ let profile = env:: var ( "PROFILE" ) . unwrap_or ( "release" . into ( ) ) ;
8+ let target = env:: var ( "TARGET" ) . unwrap_or_default ( ) ;
9+
10+ // Cargo puts output in target/<profile>/ OR target/<triple>/<profile>/
11+ // when --target is used. Output loader to both locations to be safe.
12+ let base_dir = manifest_dir. join ( "target" ) . join ( & profile) ;
13+ let triple_dir = if !target. is_empty ( ) {
14+ Some ( manifest_dir. join ( "target" ) . join ( & target) . join ( & profile) )
15+ } else {
16+ None
17+ } ;
918
1019 // Compile the loader .so
1120 // This tiny C library:
@@ -17,23 +26,26 @@ fn main() {
1726 std:: fs:: write ( & loader_c, LOADER_SOURCE ) . unwrap ( ) ;
1827
1928 // Platform-specific loader compilation
20- let target = env:: var ( "TARGET" ) . unwrap_or_default ( ) ;
2129 let is_windows = target. contains ( "windows" ) ;
2230 let is_macos = target. contains ( "apple" ) || target. contains ( "darwin" ) ;
2331
32+ std:: fs:: create_dir_all ( & base_dir) . ok ( ) ;
33+ if let Some ( ref td) = triple_dir {
34+ std:: fs:: create_dir_all ( td) . ok ( ) ;
35+ }
36+
2437 if is_windows {
2538 // On Windows, the loader is compiled by the C compiler from the host
2639 // For cross-compilation from Linux CI, we skip loader compilation
2740 // and rely on the Rust cdylib being named ring_python_impl.dll
2841 // The loader .dll is built separately or by MSVC on Windows CI
29- let loader_dll = target_dir . join ( "ring_python.dll" ) ;
42+ let loader_dll = base_dir . join ( "ring_python.dll" ) ;
3043 let status = std:: process:: Command :: new ( "cl.exe" )
3144 . args ( [
32- "/LD" , "/O2" , "/Fe:" , loader_dll. to_str ( ) . unwrap ( ) ,
45+ "/LD" , "/O2" , & format ! ( "/Fe:{} " , loader_dll. to_str( ) . unwrap( ) ) ,
3346 loader_c. to_str ( ) . unwrap ( ) ,
3447 ] )
3548 . status ( ) ;
36- // If cl.exe is not available (Linux CI), try gcc for Windows target
3749 if status. is_err ( ) || !status. unwrap ( ) . success ( ) {
3850 let status = std:: process:: Command :: new ( "gcc" )
3951 . args ( [
@@ -45,8 +57,11 @@ fn main() {
4557 . expect ( "Failed to compile loader" ) ;
4658 assert ! ( status. success( ) , "Failed to compile loader .dll" ) ;
4759 }
60+ if let Some ( ref td) = triple_dir {
61+ std:: fs:: copy ( & loader_dll, td. join ( "ring_python.dll" ) ) . ok ( ) ;
62+ }
4863 } else if is_macos {
49- let loader_dylib = target_dir . join ( "libring_python.dylib" ) ;
64+ let loader_dylib = base_dir . join ( "libring_python.dylib" ) ;
5065 let status = std:: process:: Command :: new ( "gcc" )
5166 . args ( [
5267 "-shared" , "-fPIC" , "-O2" ,
@@ -58,9 +73,13 @@ fn main() {
5873 . status ( )
5974 . expect ( "Failed to compile loader" ) ;
6075 assert ! ( status. success( ) , "Failed to compile loader .dylib" ) ;
76+ if let Some ( ref td) = triple_dir {
77+ std:: fs:: copy ( & loader_dylib, td. join ( "libring_python.dylib" ) ) . ok ( ) ;
78+ }
6179 } else {
6280 // Linux, FreeBSD, etc.
63- let loader_so = target_dir. join ( "libring_python.so" ) ;
81+ let loader_so = base_dir. join ( "libring_python.so" ) ;
82+ std:: fs:: create_dir_all ( & base_dir) . ok ( ) ;
6483 let status = std:: process:: Command :: new ( "gcc" )
6584 . args ( [
6685 "-shared" , "-fPIC" , "-O2" ,
@@ -72,9 +91,19 @@ fn main() {
7291 . status ( )
7392 . expect ( "Failed to compile loader" ) ;
7493 assert ! ( status. success( ) , "Failed to compile loader .so" ) ;
94+ if let Some ( ref td) = triple_dir {
95+ std:: fs:: create_dir_all ( td) . ok ( ) ;
96+ std:: fs:: copy ( & loader_so, td. join ( "libring_python.so" ) ) . ok ( ) ;
97+ }
7598 }
7699
77100 println ! ( "cargo:rerun-if-changed=build.rs" ) ;
101+
102+ // On macOS, allow undefined symbols (resolved at runtime by the loader)
103+ if is_macos {
104+ println ! ( "cargo:rustc-cdylib-link-arg=-undefined" ) ;
105+ println ! ( "cargo:rustc-cdylib-link-arg=dynamic_lookup" ) ;
106+ }
78107}
79108
80109const LOADER_SOURCE : & str = r#"
0 commit comments