setup.py
changeset 40967 462a26756f70
parent 40966 1eaf62a67c1a
child 40980 f6987f654356
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',