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