5
5
import shutil
6
6
import sys
7
7
import subprocess
8
+ import sysconfig
8
9
from distutils .errors import (
9
10
CompileError ,
10
11
DistutilsExecError ,
11
12
DistutilsFileError ,
13
+ DistutilsPlatformError ,
12
14
)
13
15
from subprocess import check_output
14
16
15
17
from .command import RustCommand
16
18
from .extension import Binding , RustExtension , Strip
17
- from .utils import rust_features , get_rust_target_info
19
+ from .utils import rust_features , get_rust_target_info , get_rust_target_list
18
20
21
+ class _TargetInfo :
22
+ def __init__ (self , triple = None , cross_lib = None , linker = None , link_args = None ):
23
+ self .triple = triple
24
+ self .cross_lib = cross_lib
25
+ self .linker = linker
26
+ self .link_args = link_args
19
27
20
28
class build_rust (RustCommand ):
21
29
""" Command for building Rust crates via cargo. """
@@ -60,20 +68,66 @@ def finalize_options(self):
60
68
("inplace" , "inplace" ),
61
69
)
62
70
63
- def get_target_triple (self ):
71
+ def get_target_info (self ):
64
72
# If we are on a 64-bit machine, but running a 32-bit Python, then
65
73
# we'll target a 32-bit Rust build.
66
74
# Automatic target detection can be overridden via the CARGO_BUILD_TARGET
67
75
# environment variable.
76
+
68
77
if os .getenv ("CARGO_BUILD_TARGET" ):
69
- return os .environ ["CARGO_BUILD_TARGET" ]
78
+ return _TargetInfo ( os .environ ["CARGO_BUILD_TARGET" ])
70
79
elif self .plat_name == "win32" :
71
- return "i686-pc-windows-msvc"
80
+ return _TargetInfo ( "i686-pc-windows-msvc" )
72
81
elif self .plat_name == "win-amd64" :
73
- return "x86_64-pc-windows-msvc"
82
+ return _TargetInfo ( "x86_64-pc-windows-msvc" )
74
83
elif self .plat_name .startswith ("macosx-" ) and platform .machine () == "x86_64" :
75
84
# x86_64 or arm64 macOS targeting x86_64
76
- return "x86_64-apple-darwin"
85
+ return _TargetInfo ("x86_64-apple-darwin" )
86
+ else :
87
+ return self .get_nix_target_info ()
88
+
89
+ def get_nix_target_info (self ):
90
+ # See https://github.com/PyO3/setuptools-rust/issues/138
91
+ # This is to support cross compiling on *NIX, where plat_name isn't
92
+ # necessarily the same as the system we are running on. *NIX systems
93
+ # have more detailed information available in sysconfig. We need that
94
+ # because plat_name doesn't give us information on e.g., glibc vs musl.
95
+ host_type = sysconfig .get_config_var ('HOST_GNU_TYPE' )
96
+ build_type = sysconfig .get_config_var ('BUILD_GNU_TYPE' )
97
+
98
+ if not host_type or host_type == build_type :
99
+ # not *NIX, or not cross compiling
100
+ return _TargetInfo ()
101
+
102
+ stdlib = sysconfig .get_path ('stdlib' )
103
+ cross_lib = os .path .dirname (stdlib )
104
+
105
+ bldshared = sysconfig .get_config_var ('BLDSHARED' )
106
+ if not bldshared :
107
+ linker = None
108
+ linker_args = None
109
+ else :
110
+ bldshared = bldshared .split ()
111
+ linker = bldshared [0 ]
112
+ linker_args = bldshared [1 :]
113
+
114
+ # hopefully an exact match
115
+ targets = get_rust_target_list ()
116
+ if host_type in targets :
117
+ return _TargetInfo (host_type , cross_lib , linker , linker_args )
118
+
119
+ # the vendor field can be ignored, so x86_64-pc-linux-gnu is compatible
120
+ # with x86_64-unknown-linux-gnu
121
+ components = host_type .split ('-' )
122
+ if len (components ) == 4 :
123
+ components [1 ] = 'unknown'
124
+ host_type2 = '-' .join (components )
125
+ if host_type2 in targets :
126
+ return _TargetInfo (host_type2 , cross_lib , linker , linker_args )
127
+
128
+ raise DistutilsPlatformError (
129
+ "Don't know the correct rust target for system type %s. Please "
130
+ "set the CARGO_BUILD_TARGET environment variable." % host_type )
77
131
78
132
def run_for_extension (self , ext : RustExtension ):
79
133
arch_flags = os .getenv ("ARCHFLAGS" )
@@ -95,7 +149,11 @@ def run_for_extension(self, ext: RustExtension):
95
149
def build_extension (self , ext : RustExtension , target_triple = None ):
96
150
executable = ext .binding == Binding .Exec
97
151
98
- rust_target_info = get_rust_target_info ()
152
+ if target_triple is None :
153
+ target_info = self .get_target_info ()
154
+ else :
155
+ target_info = _TargetInfo (target_triple )
156
+ rust_target_info = get_rust_target_info (target_info .triple )
99
157
100
158
# Make sure that if pythonXX-sys is used, it builds against the current
101
159
# executing python interpreter.
@@ -112,12 +170,15 @@ def build_extension(self, ext: RustExtension, target_triple=None):
112
170
"PYO3_PYTHON" : os .environ .get ("PYO3_PYTHON" , sys .executable ),
113
171
}
114
172
)
173
+
174
+ if target_info .cross_lib :
175
+ env .setdefault ("PYO3_CROSS_LIB_DIR" , target_info .cross_lib )
176
+
115
177
rustflags = ""
116
178
117
- target_triple = target_triple or self .get_target_triple ()
118
179
target_args = []
119
- if target_triple is not None :
120
- target_args = ["--target" , target_triple ]
180
+ if target_info . triple is not None :
181
+ target_args = ["--target" , target_info . triple ]
121
182
122
183
# Find where to put the temporary build files created by `cargo`
123
184
metadata_command = [
@@ -180,6 +241,12 @@ def build_extension(self, ext: RustExtension, target_triple=None):
180
241
args .extend (["--" , "--crate-type" , "cdylib" ])
181
242
args .extend (ext .rustc_flags or [])
182
243
244
+ if target_info .linker is not None :
245
+ args .extend (["-C" , "linker=" + target_info .linker ])
246
+ # We're ignoring target_info.link_args for now because we're not
247
+ # sure if they will always do the right thing. Might help with some
248
+ # of the OS-specific logic below if it does.
249
+
183
250
# OSX requires special linker argument
184
251
if sys .platform == "darwin" :
185
252
args .extend (
@@ -229,7 +296,7 @@ def build_extension(self, ext: RustExtension, target_triple=None):
229
296
suffix = "release"
230
297
231
298
# location of cargo compiled files
232
- artifactsdir = os .path .join (target_dir , target_triple or "" , suffix )
299
+ artifactsdir = os .path .join (target_dir , target_info . triple or "" , suffix )
233
300
dylib_paths = []
234
301
235
302
if executable :
0 commit comments