Skip to content

Commit 5e7500d

Browse files
authored
Merge pull request #28 from althonos/master
Improve compatibility of `build_rust` with `build_ext`
2 parents c329f88 + c5ea353 commit 5e7500d

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-25
lines changed

setuptools_rust/build.py

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class build_rust(Command):
2828
"Force debug to false for all rust extensions "),
2929
('qbuild', None,
3030
"Force enable quiet option for all rust extensions "),
31+
('build-temp', 't',
32+
"directory for temporary files (cargo 'target' directory) "),
3133
]
3234
boolean_options = ['inplace', 'debug', 'release', 'qbuild']
3335

@@ -37,24 +39,38 @@ def initialize_options(self):
3739
self.debug = None
3840
self.release = None
3941
self.qbuild = None
42+
self.build_temp = None
4043

4144
def finalize_options(self):
4245
self.extensions = [ext for ext in self.distribution.rust_extensions
4346
if isinstance(ext, RustExtension)]
4447

48+
# Inherit settings from the `build_ext` command
49+
self.set_undefined_options('build_ext',
50+
('build_temp', 'build_temp'),
51+
('debug', 'debug'),
52+
('inplace', 'inplace'),
53+
)
54+
4555
def build_extension(self, ext):
4656
executable = ext.binding == Binding.Exec
4757

4858
# Make sure that if pythonXX-sys is used, it builds against the current
4959
# executing python interpreter.
5060
bindir = os.path.dirname(sys.executable)
5161

62+
# Find where to put the temporary build files created by `cargo`
63+
targetdir = os.environ.get('CARGO_TARGET_DIR') \
64+
or os.path.join(self.build_temp, self.distribution.get_name())
65+
5266
env = os.environ.copy()
5367
env.update({
68+
'CARGO_TARGET_DIR': targetdir,
69+
5470
# disables rust's pkg-config seeking for specified packages,
5571
# which causes pythonXX-sys to fall back to detecting the
5672
# interpreter from the path.
57-
"PATH": bindir + os.pathsep + os.environ.get("PATH", "")
73+
"PATH": os.path.join(bindir, os.environ.get("PATH", "")),
5874
})
5975

6076
if not os.path.exists(ext.path):
@@ -64,11 +80,7 @@ def build_extension(self, ext):
6480
features = set(ext.features)
6581
features.update(cpython_feature(binding=ext.binding))
6682

67-
if ext.debug is None:
68-
debug_build = self.inplace
69-
else:
70-
debug_build = ext.debug
71-
83+
debug_build = ext.debug if ext.debug is not None else self.inplace
7284
debug_build = self.debug if self.debug is not None else debug_build
7385
if self.release:
7486
debug_build = False
@@ -136,20 +148,14 @@ def build_extension(self, ext):
136148
else:
137149
suffix = "release"
138150

139-
# location of files
140-
dir = os.environ.get('CARGO_TARGET_DIR', '').strip()
141-
if dir:
142-
target_dir = os.path.join(dir, suffix)
143-
else:
144-
target_dir = os.path.join(
145-
os.path.dirname(ext.path), "target/", suffix)
146-
151+
# location of cargo compiled files
152+
artifactsdir = os.path.join(targetdir, suffix)
147153
dylib_paths = []
148154

149155
if executable:
150156
for name, dest in ext.target.items():
151157
if name:
152-
path = os.path.join(target_dir, name)
158+
path = os.path.join(artifactsdir, name)
153159
if os.access(path, os.X_OK):
154160
dylib_paths.append((dest, path))
155161
continue
@@ -160,8 +166,8 @@ def build_extension(self, ext):
160166
name, target_dir))
161167
else:
162168
# search executable
163-
for name in os.listdir(target_dir):
164-
path = os.path.join(target_dir, name)
169+
for name in os.listdir(artifactsdir):
170+
path = os.path.join(artifactsdir, name)
165171
if name.startswith(".") or not os.path.isfile(path):
166172
continue
167173

@@ -175,20 +181,23 @@ def build_extension(self, ext):
175181
target_dir)
176182
else:
177183
if sys.platform == "win32":
178-
wildcard_so = "*.dll"
184+
dylib_ext = "dll"
179185
elif sys.platform == "darwin":
180-
wildcard_so = "*.dylib"
186+
dylib_ext = "dylib"
181187
else:
182-
wildcard_so = "*.so"
188+
dylib_ext = "so"
189+
190+
wildcard_so = "*{}.{}".format(ext.get_lib_name(), dylib_ext)
183191

184192
try:
185-
dylib_paths.append(
186-
(ext.name, glob.glob(
187-
os.path.join(target_dir, wildcard_so))[0]))
188-
except IndexError:
193+
dylib_paths.append((
194+
ext.name,
195+
next(glob.iglob(os.path.join(artifactsdir, wildcard_so)))
196+
))
197+
except StopIteration:
189198
raise DistutilsExecError(
190199
"rust build failed; unable to find any %s in %s" %
191-
(wildcard_so, target_dir))
200+
(wildcard_so, artifactsdir))
192201

193202
# Ask build_ext where the shared library would go if it had built it,
194203
# then copy it there.

setuptools_rust/extension.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
from distutils.errors import DistutilsSetupError
66
from .utils import Binding, Strip
77

8+
try:
9+
import configparser
10+
except ImportError:
11+
import ConfigParser as configparser
12+
813

914
import semantic_version
1015

@@ -91,6 +96,11 @@ def __init__(self, target, path,
9196

9297
self.path = path
9398

99+
def get_lib_name(self):
100+
cfg = configparser.ConfigParser()
101+
cfg.read(self.path)
102+
return cfg.get('lib', 'name').strip('"')
103+
94104
def get_rust_version(self):
95105
if self.rust_version is None:
96106
return None

0 commit comments

Comments
 (0)