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',