Mercurial > hg
comparison setup.py @ 40967:462a26756f70
rust-cpython: build via HGWITHRUSTEXT=cpython
The existing behaviour, building the direct ffi bindings if
HGIWTHRUSTEXT is just set is unchanged, but if HGWITHRUSTEXT is
cpython, then the cpython bindings (aka mercurial/rustext.so) are
built.
Differential Revision: https://phab.mercurial-scm.org/D5436
author | Georges Racinet <gracinet@anybox.fr> |
---|---|
date | Thu, 06 Dec 2018 16:34:22 +0100 |
parents | 1eaf62a67c1a |
children | f6987f654356 |
comparison
equal
deleted
inserted
replaced
40966:1eaf62a67c1a | 40967:462a26756f70 |
---|---|
130 raise SystemExit( | 130 raise SystemExit( |
131 "Couldn't import standard bz2 (incomplete Python install).") | 131 "Couldn't import standard bz2 (incomplete Python install).") |
132 | 132 |
133 ispypy = "PyPy" in sys.version | 133 ispypy = "PyPy" in sys.version |
134 | 134 |
135 iswithrustextensions = 'HGWITHRUSTEXT' in os.environ | 135 hgrustext = os.environ.get('HGWITHRUSTEXT') |
136 # TODO record it for proper rebuild upon changes | |
137 # (see mercurial/__modulepolicy__.py) | |
138 if hgrustext != 'cpython' and hgrustext is not None: | |
139 hgrustext = 'direct-ffi' | |
136 | 140 |
137 import ctypes | 141 import ctypes |
138 import errno | 142 import errno |
139 import stat, subprocess, time | 143 import stat, subprocess, time |
140 import re | 144 import re |
456 def initialize_options(self): | 460 def initialize_options(self): |
457 self.zstd = True | 461 self.zstd = True |
458 return build_ext.initialize_options(self) | 462 return build_ext.initialize_options(self) |
459 | 463 |
460 def build_extensions(self): | 464 def build_extensions(self): |
465 ruststandalones = [e for e in self.extensions | |
466 if isinstance(e, RustStandaloneExtension)] | |
467 self.extensions = [e for e in self.extensions | |
468 if e not in ruststandalones] | |
461 # Filter out zstd if disabled via argument. | 469 # Filter out zstd if disabled via argument. |
462 if not self.zstd: | 470 if not self.zstd: |
463 self.extensions = [e for e in self.extensions | 471 self.extensions = [e for e in self.extensions |
464 if e.name != 'mercurial.zstd'] | 472 if e.name != 'mercurial.zstd'] |
473 | |
474 for rustext in ruststandalones: | |
475 rustext.build('' if self.inplace else self.build_lib) | |
465 | 476 |
466 return build_ext.build_extensions(self) | 477 return build_ext.build_extensions(self) |
467 | 478 |
468 def build_extension(self, ext): | 479 def build_extension(self, ext): |
469 if isinstance(ext, RustExtension): | 480 if isinstance(ext, RustExtension): |
901 | 912 |
902 class RustCompilationError(CCompilerError): | 913 class RustCompilationError(CCompilerError): |
903 """Exception class for Rust compilation errors.""" | 914 """Exception class for Rust compilation errors.""" |
904 | 915 |
905 class RustExtension(Extension): | 916 class RustExtension(Extension): |
906 """A C Extension, conditionnally enhanced with Rust code. | 917 """Base classes for concrete Rust Extension classes. |
907 | |
908 if iswithrustextensions is False, does nothing else than plain Extension | |
909 """ | 918 """ |
910 | 919 |
911 rusttargetdir = os.path.join('rust', 'target', 'release') | 920 rusttargetdir = os.path.join('rust', 'target', 'release') |
912 | 921 |
913 def __init__(self, mpath, sources, rustlibname, subcrate, **kw): | 922 def __init__(self, mpath, sources, rustlibname, subcrate, **kw): |
914 Extension.__init__(self, mpath, sources, **kw) | 923 Extension.__init__(self, mpath, sources, **kw) |
915 if not iswithrustextensions: | 924 if hgrustext is None: |
916 return | 925 return |
917 srcdir = self.rustsrcdir = os.path.join('rust', subcrate) | 926 srcdir = self.rustsrcdir = os.path.join('rust', subcrate) |
918 self.libraries.append(rustlibname) | |
919 self.extra_compile_args.append('-DWITH_RUST') | |
920 | 927 |
921 # adding Rust source and control files to depends so that the extension | 928 # adding Rust source and control files to depends so that the extension |
922 # gets rebuilt if they've changed | 929 # gets rebuilt if they've changed |
923 self.depends.append(os.path.join(srcdir, 'Cargo.toml')) | 930 self.depends.append(os.path.join(srcdir, 'Cargo.toml')) |
924 cargo_lock = os.path.join(srcdir, 'Cargo.lock') | 931 cargo_lock = os.path.join(srcdir, 'Cargo.lock') |
928 self.depends.extend(os.path.join(dirpath, fname) | 935 self.depends.extend(os.path.join(dirpath, fname) |
929 for fname in fnames | 936 for fname in fnames |
930 if os.path.splitext(fname)[1] == '.rs') | 937 if os.path.splitext(fname)[1] == '.rs') |
931 | 938 |
932 def rustbuild(self): | 939 def rustbuild(self): |
933 if not iswithrustextensions: | 940 if hgrustext is None: |
934 return | 941 return |
935 env = os.environ.copy() | 942 env = os.environ.copy() |
936 if 'HGTEST_RESTOREENV' in env: | 943 if 'HGTEST_RESTOREENV' in env: |
937 # Mercurial tests change HOME to a temporary directory, | 944 # Mercurial tests change HOME to a temporary directory, |
938 # but, if installed with rustup, the Rust toolchain needs | 945 # but, if installed with rustup, the Rust toolchain needs |
960 except subprocess.CalledProcessError: | 967 except subprocess.CalledProcessError: |
961 raise RustCompilationError( | 968 raise RustCompilationError( |
962 "Cargo failed. Working directory: %r, " | 969 "Cargo failed. Working directory: %r, " |
963 "command: %r, environment: %r" % (self.rustsrcdir, cmd, env)) | 970 "command: %r, environment: %r" % (self.rustsrcdir, cmd, env)) |
964 | 971 |
972 class RustEnhancedExtension(RustExtension): | |
973 """A C Extension, conditionally enhanced with Rust code. | |
974 | |
975 If the HGRUSTEXT environment variable is set to something else | |
976 than 'cpython', the Rust sources get compiled and linked within the | |
977 C target shared library object. | |
978 """ | |
979 | |
980 def __init__(self, mpath, sources, rustlibname, subcrate, **kw): | |
981 RustExtension.__init__(self, mpath, sources, rustlibname, subcrate, | |
982 **kw) | |
983 if hgrustext != 'direct-ffi': | |
984 return | |
985 self.extra_compile_args.append('-DWITH_RUST') | |
986 self.libraries.append(rustlibname) | |
987 self.library_dirs.append(self.rusttargetdir) | |
988 | |
989 class RustStandaloneExtension(RustExtension): | |
990 | |
991 def __init__(self, pydottedname, rustcrate, dylibname, **kw): | |
992 RustExtension.__init__(self, pydottedname, [], dylibname, rustcrate, | |
993 **kw) | |
994 self.dylibname = dylibname | |
995 | |
996 def build(self, target_dir): | |
997 self.rustbuild() | |
998 target = [target_dir] | |
999 target.extend(self.name.split('.')) | |
1000 ext = '.so' # TODO Unix only | |
1001 target[-1] += ext | |
1002 shutil.copy2(os.path.join(self.rusttargetdir, self.dylibname + ext), | |
1003 os.path.join(*target)) | |
1004 | |
1005 | |
965 extmodules = [ | 1006 extmodules = [ |
966 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'], | 1007 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'], |
967 include_dirs=common_include_dirs, | 1008 include_dirs=common_include_dirs, |
968 depends=common_depends), | 1009 depends=common_depends), |
969 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c', | 1010 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c', |
972 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers), | 1013 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers), |
973 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c', | 1014 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c', |
974 'mercurial/cext/mpatch.c'], | 1015 'mercurial/cext/mpatch.c'], |
975 include_dirs=common_include_dirs, | 1016 include_dirs=common_include_dirs, |
976 depends=common_depends), | 1017 depends=common_depends), |
977 RustExtension('mercurial.cext.parsers', ['mercurial/cext/charencode.c', | 1018 RustEnhancedExtension( |
978 'mercurial/cext/dirs.c', | 1019 'mercurial.cext.parsers', ['mercurial/cext/charencode.c', |
979 'mercurial/cext/manifest.c', | 1020 'mercurial/cext/dirs.c', |
980 'mercurial/cext/parsers.c', | 1021 'mercurial/cext/manifest.c', |
981 'mercurial/cext/pathencode.c', | 1022 'mercurial/cext/parsers.c', |
982 'mercurial/cext/revlog.c'], | 1023 'mercurial/cext/pathencode.c', |
983 'hgdirectffi', | 1024 'mercurial/cext/revlog.c'], |
984 'hg-direct-ffi', | 1025 'hgdirectffi', |
985 include_dirs=common_include_dirs, | 1026 'hg-direct-ffi', |
986 depends=common_depends + ['mercurial/cext/charencode.h', | 1027 include_dirs=common_include_dirs, |
987 'mercurial/cext/revlog.h', | 1028 depends=common_depends + ['mercurial/cext/charencode.h', |
988 'rust/hg-core/src/ancestors.rs', | 1029 'mercurial/cext/revlog.h', |
989 'rust/hg-core/src/lib.rs']), | 1030 'rust/hg-core/src/ancestors.rs', |
1031 'rust/hg-core/src/lib.rs']), | |
990 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'], | 1032 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'], |
991 include_dirs=common_include_dirs, | 1033 include_dirs=common_include_dirs, |
992 extra_compile_args=osutil_cflags, | 1034 extra_compile_args=osutil_cflags, |
993 extra_link_args=osutil_ldflags, | 1035 extra_link_args=osutil_ldflags, |
994 depends=common_depends), | 1036 depends=common_depends), |
997 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c', | 1039 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c', |
998 ]), | 1040 ]), |
999 Extension('hgext.fsmonitor.pywatchman.bser', | 1041 Extension('hgext.fsmonitor.pywatchman.bser', |
1000 ['hgext/fsmonitor/pywatchman/bser.c']), | 1042 ['hgext/fsmonitor/pywatchman/bser.c']), |
1001 ] | 1043 ] |
1044 | |
1045 if hgrustext == 'cpython': | |
1046 extmodules.append( | |
1047 RustStandaloneExtension('mercurial.rustext', 'hg-cpython', 'librusthg') | |
1048 ) | |
1049 | |
1002 | 1050 |
1003 sys.path.insert(0, 'contrib/python-zstandard') | 1051 sys.path.insert(0, 'contrib/python-zstandard') |
1004 import setup_zstd | 1052 import setup_zstd |
1005 extmodules.append(setup_zstd.get_c_extension( | 1053 extmodules.append(setup_zstd.get_c_extension( |
1006 name='mercurial.zstd', | 1054 name='mercurial.zstd', |