Defined Cargo features for Python3, making them overall simpler to
use, hooked them in build and made mercurial.rustext importable.
This is tested with Python 3.6.7.
hg-reviewers |
Defined Cargo features for Python3, making them overall simpler to
use, hooked them in build and made mercurial.rustext importable.
This is tested with Python 3.6.7.
Lint Skipped |
Unit Tests Skipped |
Queued, thanks.
We'll probably need to add suffix to the filename to disambiguate py2/3
modules. It's $PYTHON-config --extension-suffix on my Linux machine, but
I don't know if it can be obtained directly in setup.py.
@yuja great, thanks. Didn't know about this suffix, apparently it can be obtained through the sysconfig module (thats what $PYTHON-config does)
~ $ python2 -c "import sysconfig; print(sysconfig.get_config_var('SO'))" .so ~ $ python3 -c "import sysconfig; print(sysconfig.get_config_var('SO'))" -c:1: DeprecationWarning: SO is deprecated, use EXT_SUFFIX .cpython-37m-x86_64-linux-gnu.so ~ $ python3 -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))" .cpython-37m-x86_64-linux-gnu.so
I suppose that's also the thing to use to build for Windows or other operating systems.
Path | Packages | |||
---|---|---|---|---|
M | mercurial/__init__.py (4 lines) | |||
M | rust/Cargo.lock (1 line) | |||
M | rust/hg-cpython/Cargo.toml (9 lines) | |||
M | setup.py (10 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
Georges Racinet | Dec 17 2018, 9:05 AM |
if fullname.startswith('mercurial.cext.'): | if fullname.startswith('mercurial.cext.'): | ||||
return None | return None | ||||
# third-party packages are expected to be dual-version clean | # third-party packages are expected to be dual-version clean | ||||
if fullname.startswith('mercurial.thirdparty'): | if fullname.startswith('mercurial.thirdparty'): | ||||
return None | return None | ||||
# zstd is already dual-version clean, don't try and mangle it | # zstd is already dual-version clean, don't try and mangle it | ||||
if fullname.startswith('mercurial.zstd'): | if fullname.startswith('mercurial.zstd'): | ||||
return None | return None | ||||
# rustext is built for the right python version, | |||||
# don't try and mangle it | |||||
if fullname.startswith('mercurial.rustext'): | |||||
return None | |||||
# pywatchman is already dual-version clean, don't try and mangle it | # pywatchman is already dual-version clean, don't try and mangle it | ||||
if fullname.startswith('hgext.fsmonitor.pywatchman'): | if fullname.startswith('hgext.fsmonitor.pywatchman'): | ||||
return None | return None | ||||
# Try to find the module using other registered finders. | # Try to find the module using other registered finders. | ||||
spec = None | spec = None | ||||
for finder in sys.meta_path: | for finder in sys.meta_path: | ||||
if finder == self: | if finder == self: |
[[package]] | [[package]] | ||||
name = "cpython" | name = "cpython" | ||||
version = "0.2.1" | version = "0.2.1" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
dependencies = [ | dependencies = [ | ||||
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | "python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
] | ] | ||||
[[package]] | [[package]] | ||||
name = "hg-core" | name = "hg-core" | ||||
version = "0.1.0" | version = "0.1.0" | ||||
[[package]] | [[package]] | ||||
name = "hg-cpython" | name = "hg-cpython" |
[package] | [package] | ||||
name = "hg-cpython" | name = "hg-cpython" | ||||
version = "0.1.0" | version = "0.1.0" | ||||
authors = ["Georges Racinet <gracinet@anybox.fr>"] | authors = ["Georges Racinet <gracinet@anybox.fr>"] | ||||
[lib] | [lib] | ||||
name='rusthg' | name='rusthg' | ||||
crate-type = ["cdylib"] | crate-type = ["cdylib"] | ||||
[features] | [features] | ||||
default = ["python27", "python27-sys"] | default = ["python27"] | ||||
python27 = ["cpython/python27-sys", "cpython/extension-module-2-7"] | python27 = ["cpython/python27-sys", | ||||
"cpython/extension-module-2-7", | |||||
"python27-sys", | |||||
] | |||||
python3 = ["python3-sys", "cpython/python3-sys", "cpython/extension-module"] | |||||
[dependencies] | [dependencies] | ||||
hg-core = { path = "../hg-core" } | hg-core = { path = "../hg-core" } | ||||
libc = '*' | libc = '*' | ||||
[dependencies.cpython] | [dependencies.cpython] | ||||
version = "*" | version = "*" | ||||
default-features = false | default-features = false | ||||
[dependencies.python27-sys] | [dependencies.python27-sys] | ||||
version = "0.2.1" | version = "0.2.1" | ||||
optional = true | optional = true | ||||
[dependencies.python3-sys] | [dependencies.python3-sys] | ||||
version = "0.2.1" | version = "0.2.1" | ||||
optional = true | optional = true |
"""Exception class for Rust compilation errors.""" | """Exception class for Rust compilation errors.""" | ||||
class RustExtension(Extension): | class RustExtension(Extension): | ||||
"""Base classes for concrete Rust Extension classes. | """Base classes for concrete Rust Extension classes. | ||||
""" | """ | ||||
rusttargetdir = os.path.join('rust', 'target', 'release') | rusttargetdir = os.path.join('rust', 'target', 'release') | ||||
def __init__(self, mpath, sources, rustlibname, subcrate, **kw): | def __init__(self, mpath, sources, rustlibname, subcrate, | ||||
py3_features=None, **kw): | |||||
Extension.__init__(self, mpath, sources, **kw) | Extension.__init__(self, mpath, sources, **kw) | ||||
if hgrustext is None: | if hgrustext is None: | ||||
return | return | ||||
srcdir = self.rustsrcdir = os.path.join('rust', subcrate) | srcdir = self.rustsrcdir = os.path.join('rust', subcrate) | ||||
self.py3_features = py3_features | |||||
# adding Rust source and control files to depends so that the extension | # adding Rust source and control files to depends so that the extension | ||||
# gets rebuilt if they've changed | # gets rebuilt if they've changed | ||||
self.depends.append(os.path.join(srcdir, 'Cargo.toml')) | self.depends.append(os.path.join(srcdir, 'Cargo.toml')) | ||||
cargo_lock = os.path.join(srcdir, 'Cargo.lock') | cargo_lock = os.path.join(srcdir, 'Cargo.lock') | ||||
if os.path.exists(cargo_lock): | if os.path.exists(cargo_lock): | ||||
self.depends.append(cargo_lock) | self.depends.append(cargo_lock) | ||||
for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')): | for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')): | ||||
# invoke this build. | # invoke this build. | ||||
# Unix only fix (os.path.expanduser not really reliable if | # Unix only fix (os.path.expanduser not really reliable if | ||||
# HOME is shadowed like this) | # HOME is shadowed like this) | ||||
import pwd | import pwd | ||||
env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir | env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir | ||||
cargocmd = ['cargo', 'build', '-vv', '--release'] | cargocmd = ['cargo', 'build', '-vv', '--release'] | ||||
if sys.version_info[0] == 3 and self.py3_features is not None: | |||||
cargocmd.extend(('--features', self.py3_features, | |||||
'--no-default-features')) | |||||
try: | try: | ||||
subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir) | subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir) | ||||
except OSError as exc: | except OSError as exc: | ||||
if exc.errno == errno.ENOENT: | if exc.errno == errno.ENOENT: | ||||
raise RustCompilationError("Cargo not found") | raise RustCompilationError("Cargo not found") | ||||
elif exc.errno == errno.EACCES: | elif exc.errno == errno.EACCES: | ||||
raise RustCompilationError( | raise RustCompilationError( | ||||
"Cargo found, but permisssion to execute it is denied") | "Cargo found, but permisssion to execute it is denied") | ||||
'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c', | 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c', | ||||
]), | ]), | ||||
Extension('hgext.fsmonitor.pywatchman.bser', | Extension('hgext.fsmonitor.pywatchman.bser', | ||||
['hgext/fsmonitor/pywatchman/bser.c']), | ['hgext/fsmonitor/pywatchman/bser.c']), | ||||
] | ] | ||||
if hgrustext == 'cpython': | if hgrustext == 'cpython': | ||||
extmodules.append( | extmodules.append( | ||||
RustStandaloneExtension('mercurial.rustext', 'hg-cpython', 'librusthg') | RustStandaloneExtension('mercurial.rustext', 'hg-cpython', 'librusthg', | ||||
py3_features='python3') | |||||
) | ) | ||||
sys.path.insert(0, 'contrib/python-zstandard') | sys.path.insert(0, 'contrib/python-zstandard') | ||||
import setup_zstd | import setup_zstd | ||||
extmodules.append(setup_zstd.get_c_extension( | extmodules.append(setup_zstd.get_c_extension( | ||||
name='mercurial.zstd', | name='mercurial.zstd', | ||||
root=os.path.abspath(os.path.dirname(__file__)))) | root=os.path.abspath(os.path.dirname(__file__)))) |