@@ -3,33 +3,40 @@ use std::env;
33/// Print necessary link arguments for the library depending on the build
44/// configuration (static or shared)
55pub fn print_linker_args ( ) {
6- let target = env:: var ( "TARGET" ) . unwrap_or_default ( ) ;
6+ println ! ( "cargo:rerun-if-env-changed=RUST_SHARED_BUILD" ) ;
7+ println ! ( "cargo:rerun-if-env-changed=BLDSHARED_EXE" ) ;
8+ println ! ( "cargo:rerun-if-env-changed=BLDSHARED_ARGS" ) ;
9+ println ! ( "cargo:rerun-if-env-changed=LIBPYTHON" ) ;
10+ println ! ( "cargo:rerun-if-env-changed=PYTHON_BUILD_DIR" ) ;
11+ println ! ( "cargo:rerun-if-env-changed=CARGO_CFG_TARGET_OS" ) ;
12+
13+ let target_os = env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap_or_default ( ) ;
14+ let shared_build =
15+ env:: var ( "RUST_SHARED_BUILD" ) . unwrap_or_default ( ) == "1" || target_os == "ios" ;
716
817 // On Apple platforms (macOS, iOS), Cargo's cdylib produces a Mach-O
918 // dynamiclib (via -dynamiclib), but CPython's C extensions are built as
1019 // bundles (via -bundle). Unlike bundles, dynamiclibs require all symbols
1120 // to be resolved at link time. Pass -undefined dynamic_lookup so that
1221 // Python C API symbols are resolved at load time by the interpreter.
13- if target . contains ( "apple" ) {
22+ if target_os == "macos" || target_os == "ios" {
1423 println ! ( "cargo:rustc-cdylib-link-arg=-undefined" ) ;
1524 println ! ( "cargo:rustc-cdylib-link-arg=dynamic_lookup" ) ;
1625 }
1726
27+ // Apple framework builds for iOS encode framework search/link flags in
28+ // BLDSHARED_EXE. Skip the linker executable itself and filter out flags
29+ // that conflict with Cargo's own cdylib invocation.
30+ if shared_build
31+ && let Ok ( args) = env:: var ( "BLDSHARED_EXE" )
32+ {
33+ print_link_args ( & args, true ) ;
34+ }
35+
1836 // Pass platform-specific shared link arguments (e.g. PY_CORE_LDFLAGS)
1937 // from the CPython build system.
2038 if let Ok ( args) = env:: var ( "BLDSHARED_ARGS" ) {
21- let args = shlex:: split ( & args) . expect ( "Invalid BLDSHARED_ARGS" ) ;
22- let mut iter = args. iter ( ) ;
23- while let Some ( arg) = iter. next ( ) {
24- // -bundle_loader is incompatible with Cargo's cdylib on macOS
25- // (it only works with -bundle, not -dynamiclib). Skip it and
26- // its argument.
27- if arg == "-bundle_loader" {
28- iter. next ( ) ; // skip the path argument
29- continue ;
30- }
31- println ! ( "cargo:rustc-cdylib-link-arg={}" , arg) ;
32- }
39+ print_link_args ( & args, false ) ;
3340 }
3441
3542 // On Android (and Cygwin), extension modules must link against libpython.
@@ -52,3 +59,44 @@ pub fn print_linker_args() {
5259
5360 // Static linker configuration is in cpython-rust-staticlib
5461}
62+
63+ fn print_link_args ( raw : & str , skip_first : bool ) {
64+ let mut args = shlex:: split ( raw) . expect ( "Invalid linker args" ) ;
65+ if skip_first && !args. is_empty ( ) {
66+ args. remove ( 0 ) ;
67+ }
68+
69+ let build_dir = env:: var ( "PYTHON_BUILD_DIR" ) . ok ( ) ;
70+ let mut i = 0 ;
71+ while i < args. len ( ) {
72+ match args[ i] . as_str ( ) {
73+ // -bundle_loader only works with -bundle, not with Cargo's
74+ // cdylib mode (-dynamiclib).
75+ "-bundle_loader" => {
76+ i += 2 ;
77+ }
78+ // Cargo chooses the Mach-O output type for cdylib already.
79+ "-bundle" | "-dynamiclib" => {
80+ i += 1 ;
81+ }
82+ // dynamic_lookup is added explicitly for Apple targets above.
83+ "-undefined" if i + 1 < args. len ( ) && args[ i + 1 ] == "dynamic_lookup" => {
84+ i += 2 ;
85+ }
86+ "-F" if i + 1 < args. len ( ) => {
87+ let value = if args[ i + 1 ] == "." {
88+ build_dir. clone ( ) . unwrap_or_else ( || "." . to_string ( ) )
89+ } else {
90+ args[ i + 1 ] . clone ( )
91+ } ;
92+ println ! ( "cargo:rustc-cdylib-link-arg=-F" ) ;
93+ println ! ( "cargo:rustc-cdylib-link-arg={value}" ) ;
94+ i += 2 ;
95+ }
96+ _ => {
97+ println ! ( "cargo:rustc-cdylib-link-arg={}" , args[ i] ) ;
98+ i += 1 ;
99+ }
100+ }
101+ }
102+ }
0 commit comments