@@ -568,35 +568,54 @@ pub struct CrossCompileConfig {
568
568
os : String ,
569
569
}
570
570
571
- #[ allow( unused) ]
572
- pub fn any_cross_compiling_env_vars_set ( ) -> bool {
573
- env:: var_os ( "PYO3_CROSS" ) . is_some ( )
574
- || env:: var_os ( "PYO3_CROSS_LIB_DIR" ) . is_some ( )
575
- || env:: var_os ( "PYO3_CROSS_PYTHON_VERSION" ) . is_some ( )
571
+ pub ( crate ) struct CrossCompileEnvVars {
572
+ pyo3_cross : Option < OsString > ,
573
+ pyo3_cross_lib_dir : Option < OsString > ,
574
+ pyo3_cross_python_version : Option < OsString > ,
576
575
}
577
576
578
- fn cross_compiling_from_cargo_env ( ) -> Result < Option < CrossCompileConfig > > {
579
- let host = cargo_env_var ( "HOST" ) . ok_or ( "expected HOST env var" ) ?;
580
- let target = cargo_env_var ( "TARGET" ) . ok_or ( "expected TARGET env var" ) ?;
581
-
582
- if host == target {
583
- // Definitely not cross compiling if the host matches the target
584
- return Ok ( None ) ;
577
+ impl CrossCompileEnvVars {
578
+ pub fn any ( & self ) -> bool {
579
+ self . pyo3_cross . is_some ( )
580
+ || self . pyo3_cross_lib_dir . is_some ( )
581
+ || self . pyo3_cross_python_version . is_some ( )
585
582
}
583
+ }
586
584
587
- if target == "i686-pc-windows-msvc" && host == "x86_64-pc-windows-msvc" {
588
- // Not cross-compiling to compile for 32-bit Python from windows 64-bit
589
- return Ok ( None ) ;
585
+ pub ( crate ) fn cross_compile_env_vars ( ) -> CrossCompileEnvVars {
586
+ CrossCompileEnvVars {
587
+ pyo3_cross : env:: var_os ( "PYO3_CROSS" ) ,
588
+ pyo3_cross_lib_dir : env:: var_os ( "PYO3_CROSS_LIB_DIR" ) ,
589
+ pyo3_cross_python_version : env:: var_os ( "PYO3_CROSS_PYTHON_VERSION" ) ,
590
590
}
591
+ }
591
592
592
- let target_arch =
593
- cargo_env_var ( "CARGO_CFG_TARGET_ARCH" ) . ok_or ( "expected CARGO_CFG_TARGET_ARCH env var" ) ?;
594
- let target_vendor = cargo_env_var ( "CARGO_CFG_TARGET_VENDOR" )
595
- . ok_or ( "expected CARGO_CFG_TARGET_VENDOR env var" ) ?;
596
- let target_os =
597
- cargo_env_var ( "CARGO_CFG_TARGET_OS" ) . ok_or ( "expected CARGO_CFG_TARGET_OS env var" ) ?;
598
-
599
- cross_compiling ( & host, & target_arch, & target_vendor, & target_os)
593
+ fn cross_compiling_from_vars (
594
+ target_arch : & str ,
595
+ target_os : & str ,
596
+ target_vendor : & str ,
597
+ cross_compile_vars : CrossCompileEnvVars ,
598
+ ) -> Result < CrossCompileConfig > {
599
+ Ok ( CrossCompileConfig {
600
+ lib_dir : cross_compile_vars
601
+ . pyo3_cross_lib_dir
602
+ . ok_or ( "The PYO3_CROSS_LIB_DIR environment variable must be set when cross-compiling" ) ?
603
+ . into ( ) ,
604
+ arch : target_arch. into ( ) ,
605
+ vendor : target_vendor. into ( ) ,
606
+ os : target_os. into ( ) ,
607
+ version : cross_compile_vars
608
+ . pyo3_cross_python_version
609
+ . map ( |os_string| {
610
+ let utf8_str = os_string
611
+ . to_str ( )
612
+ . ok_or ( "PYO3_CROSS_PYTHON_VERSION is not valid utf-8." ) ?;
613
+ utf8_str
614
+ . parse ( )
615
+ . context ( "failed to parse PYO3_CROSS_PYTHON_VERSION" )
616
+ } )
617
+ . transpose ( ) ?,
618
+ } )
600
619
}
601
620
602
621
/// Detect whether we are cross compiling and return an assembled CrossCompileConfig if so.
@@ -619,52 +638,24 @@ pub fn cross_compiling(
619
638
target_vendor : & str ,
620
639
target_os : & str ,
621
640
) -> Result < Option < CrossCompileConfig > > {
622
- let cross = env_var ( "PYO3_CROSS" ) ;
623
- let cross_lib_dir = env_var ( "PYO3_CROSS_LIB_DIR" ) ;
624
- let cross_python_version = env_var ( "PYO3_CROSS_PYTHON_VERSION" ) ;
625
-
626
- let target_triple = format ! (
627
- "{}-{}-{}" ,
628
- target_arch,
629
- target_vendor,
630
- if target_os == "macos" {
631
- "darwin"
632
- } else {
633
- target_os
634
- }
635
- ) ;
636
-
637
- if cross. is_none ( ) && cross_lib_dir. is_none ( ) && cross_python_version. is_none ( ) {
638
- // No cross-compiling environment variables set; try to determine if this is a known case
639
- // which is not cross-compilation.
641
+ let env_vars = cross_compile_env_vars ( ) ;
640
642
641
- if target_triple == "x86_64-apple-darwin" && host == "aarch64-apple-darwin" {
642
- // Not cross-compiling to compile for x86-64 Python from macOS arm64
643
- return Ok ( None ) ;
644
- }
645
-
646
- if target_triple == "aarch64-apple-darwin" && host == "x86_64-apple-darwin" {
647
- // Not cross-compiling to compile for arm64 Python from macOS x86_64
648
- return Ok ( None ) ;
649
- }
650
-
651
- if host. starts_with ( & target_triple) {
652
- // Not cross-compiling if arch-vendor-os is all the same
653
- // e.g. x86_64-unknown-linux-musl on x86_64-unknown-linux-gnu host
654
- return Ok ( None ) ;
655
- }
643
+ if !env_vars. any ( ) && is_not_cross_compiling ( host, target_arch, target_vendor, target_os) {
644
+ return Ok ( None ) ;
656
645
}
657
646
658
647
// At this point we assume that we are cross compiling.
659
648
660
649
Ok ( Some ( CrossCompileConfig {
661
- lib_dir : cross_lib_dir
650
+ lib_dir : env_vars
651
+ . pyo3_cross_lib_dir
662
652
. ok_or ( "The PYO3_CROSS_LIB_DIR environment variable must be set when cross-compiling" ) ?
663
653
. into ( ) ,
664
654
arch : target_arch. into ( ) ,
665
655
vendor : target_vendor. into ( ) ,
666
656
os : target_os. into ( ) ,
667
- version : cross_python_version
657
+ version : env_vars
658
+ . pyo3_cross_python_version
668
659
. map ( |os_string| {
669
660
let utf8_str = os_string
670
661
. to_str ( )
@@ -677,6 +668,39 @@ pub fn cross_compiling(
677
668
} ) )
678
669
}
679
670
671
+ fn is_not_cross_compiling (
672
+ host : & str ,
673
+ target_arch : & str ,
674
+ target_vendor : & str ,
675
+ target_os : & str ,
676
+ ) -> bool {
677
+ let target_triple = format ! (
678
+ "{}-{}-{}" ,
679
+ if target_arch == "x86" {
680
+ "i686"
681
+ } else {
682
+ target_arch
683
+ } ,
684
+ target_vendor,
685
+ if target_os == "macos" {
686
+ "darwin"
687
+ } else {
688
+ target_os
689
+ }
690
+ ) ;
691
+
692
+ // Not cross-compiling if arch-vendor-os is all the same
693
+ // e.g. x86_64-unknown-linux-musl on x86_64-unknown-linux-gnu host
694
+ // x86_64-pc-windows-gnu on x86_64-pc-windows-msvc host
695
+ host. starts_with ( & target_triple)
696
+ // Not cross-compiling to compile for 32-bit Python from windows 64-bit
697
+ || ( target_triple == "i686-pc-windows" && host. starts_with ( "x86_64-pc-windows" ) )
698
+ // Not cross-compiling to compile for x86-64 Python from macOS arm64
699
+ || ( target_triple == "x86_64-apple-darwin" && host == "aarch64-apple-darwin" )
700
+ // Not cross-compiling to compile for arm64 Python from macOS x86_64
701
+ || ( target_triple == "aarch64-apple-darwin" && host == "x86_64-apple-darwin" )
702
+ }
703
+
680
704
#[ allow( non_camel_case_types) ]
681
705
#[ derive( Debug , Clone , Hash , PartialEq , Eq ) ]
682
706
pub enum BuildFlag {
@@ -1280,13 +1304,33 @@ fn fixup_config_for_abi3(
1280
1304
/// This must be called from PyO3's build script, because it relies on environment variables such as
1281
1305
/// CARGO_CFG_TARGET_OS which aren't available at any other time.
1282
1306
pub fn make_cross_compile_config ( ) -> Result < Option < InterpreterConfig > > {
1283
- let mut interpreter_config = if let Some ( paths) = cross_compiling_from_cargo_env ( ) ? {
1284
- load_cross_compile_config ( paths) ?
1285
- } else {
1286
- return Ok ( None ) ;
1287
- } ;
1288
- fixup_config_for_abi3 ( & mut interpreter_config, get_abi3_version ( ) ) ?;
1289
- Ok ( Some ( interpreter_config) )
1307
+ let env_vars = cross_compile_env_vars ( ) ;
1308
+
1309
+ let host = cargo_env_var ( "HOST" ) . ok_or ( "expected HOST env var" ) ?;
1310
+ let target = cargo_env_var ( "TARGET" ) . ok_or ( "expected TARGET env var" ) ?;
1311
+
1312
+ let target_arch =
1313
+ cargo_env_var ( "CARGO_CFG_TARGET_ARCH" ) . ok_or ( "expected CARGO_CFG_TARGET_ARCH env var" ) ?;
1314
+ let target_vendor = cargo_env_var ( "CARGO_CFG_TARGET_VENDOR" )
1315
+ . ok_or ( "expected CARGO_CFG_TARGET_VENDOR env var" ) ?;
1316
+ let target_os =
1317
+ cargo_env_var ( "CARGO_CFG_TARGET_OS" ) . ok_or ( "expected CARGO_CFG_TARGET_OS env var" ) ?;
1318
+
1319
+ if env_vars. any ( ) {
1320
+ let cross_config =
1321
+ cross_compiling_from_vars ( & target_arch, & target_os, & target_vendor, env_vars) ?;
1322
+ let mut interpreter_config = load_cross_compile_config ( cross_config) ?;
1323
+ fixup_config_for_abi3 ( & mut interpreter_config, get_abi3_version ( ) ) ?;
1324
+ return Ok ( Some ( interpreter_config) ) ;
1325
+ }
1326
+
1327
+ ensure ! (
1328
+ host == target || is_not_cross_compiling( & host, & target_arch, & target_os, & target_vendor) ,
1329
+ "PyO3 detected compile host {host} and build target {target}, but none of PYO3_CROSS, PYO3_CROSS_LIB_DIR \
1330
+ or PYO3_CROSS_PYTHON_VERSION environment variables are set."
1331
+ ) ;
1332
+
1333
+ Ok ( None )
1290
1334
}
1291
1335
1292
1336
/// Generates an interpreter config which will be hard-coded into the pyo3-build-config crate.
0 commit comments