##// END OF EJS Templates
setup: compile zstd C extension...
Gregory Szorc -
r30436:788ea4ac default
parent child Browse files
Show More
@@ -1,730 +1,734 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
9 raise SystemExit("Mercurial requires Python 2.6 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 printf = eval('print')
12 printf = eval('print')
13 libdir_escape = 'unicode_escape'
13 libdir_escape = 'unicode_escape'
14 else:
14 else:
15 libdir_escape = 'string_escape'
15 libdir_escape = 'string_escape'
16 def printf(*args, **kwargs):
16 def printf(*args, **kwargs):
17 f = kwargs.get('file', sys.stdout)
17 f = kwargs.get('file', sys.stdout)
18 end = kwargs.get('end', '\n')
18 end = kwargs.get('end', '\n')
19 f.write(b' '.join(args) + end)
19 f.write(b' '.join(args) + end)
20
20
21 # Solaris Python packaging brain damage
21 # Solaris Python packaging brain damage
22 try:
22 try:
23 import hashlib
23 import hashlib
24 sha = hashlib.sha1()
24 sha = hashlib.sha1()
25 except ImportError:
25 except ImportError:
26 try:
26 try:
27 import sha
27 import sha
28 sha.sha # silence unused import warning
28 sha.sha # silence unused import warning
29 except ImportError:
29 except ImportError:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 zlib.compressobj # silence unused import warning
35 zlib.compressobj # silence unused import warning
36 except ImportError:
36 except ImportError:
37 raise SystemExit(
37 raise SystemExit(
38 "Couldn't import standard zlib (incomplete Python install).")
38 "Couldn't import standard zlib (incomplete Python install).")
39
39
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
41 isironpython = False
41 isironpython = False
42 try:
42 try:
43 isironpython = (platform.python_implementation()
43 isironpython = (platform.python_implementation()
44 .lower().find("ironpython") != -1)
44 .lower().find("ironpython") != -1)
45 except AttributeError:
45 except AttributeError:
46 pass
46 pass
47
47
48 if isironpython:
48 if isironpython:
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
50 else:
50 else:
51 try:
51 try:
52 import bz2
52 import bz2
53 bz2.BZ2Compressor # silence unused import warning
53 bz2.BZ2Compressor # silence unused import warning
54 except ImportError:
54 except ImportError:
55 raise SystemExit(
55 raise SystemExit(
56 "Couldn't import standard bz2 (incomplete Python install).")
56 "Couldn't import standard bz2 (incomplete Python install).")
57
57
58 ispypy = "PyPy" in sys.version
58 ispypy = "PyPy" in sys.version
59
59
60 import ctypes
60 import ctypes
61 import os, stat, subprocess, time
61 import os, stat, subprocess, time
62 import re
62 import re
63 import shutil
63 import shutil
64 import tempfile
64 import tempfile
65 from distutils import log
65 from distutils import log
66 if 'FORCE_SETUPTOOLS' in os.environ:
66 if 'FORCE_SETUPTOOLS' in os.environ:
67 from setuptools import setup
67 from setuptools import setup
68 else:
68 else:
69 from distutils.core import setup
69 from distutils.core import setup
70 from distutils.ccompiler import new_compiler
70 from distutils.ccompiler import new_compiler
71 from distutils.core import Command, Extension
71 from distutils.core import Command, Extension
72 from distutils.dist import Distribution
72 from distutils.dist import Distribution
73 from distutils.command.build import build
73 from distutils.command.build import build
74 from distutils.command.build_ext import build_ext
74 from distutils.command.build_ext import build_ext
75 from distutils.command.build_py import build_py
75 from distutils.command.build_py import build_py
76 from distutils.command.build_scripts import build_scripts
76 from distutils.command.build_scripts import build_scripts
77 from distutils.command.install_lib import install_lib
77 from distutils.command.install_lib import install_lib
78 from distutils.command.install_scripts import install_scripts
78 from distutils.command.install_scripts import install_scripts
79 from distutils.spawn import spawn, find_executable
79 from distutils.spawn import spawn, find_executable
80 from distutils import file_util
80 from distutils import file_util
81 from distutils.errors import (
81 from distutils.errors import (
82 CCompilerError,
82 CCompilerError,
83 DistutilsError,
83 DistutilsError,
84 DistutilsExecError,
84 DistutilsExecError,
85 )
85 )
86 from distutils.sysconfig import get_python_inc, get_config_var
86 from distutils.sysconfig import get_python_inc, get_config_var
87 from distutils.version import StrictVersion
87 from distutils.version import StrictVersion
88
88
89 scripts = ['hg']
89 scripts = ['hg']
90 if os.name == 'nt':
90 if os.name == 'nt':
91 # We remove hg.bat if we are able to build hg.exe.
91 # We remove hg.bat if we are able to build hg.exe.
92 scripts.append('contrib/win32/hg.bat')
92 scripts.append('contrib/win32/hg.bat')
93
93
94 # simplified version of distutils.ccompiler.CCompiler.has_function
94 # simplified version of distutils.ccompiler.CCompiler.has_function
95 # that actually removes its temporary files.
95 # that actually removes its temporary files.
96 def hasfunction(cc, funcname):
96 def hasfunction(cc, funcname):
97 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
97 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
98 devnull = oldstderr = None
98 devnull = oldstderr = None
99 try:
99 try:
100 fname = os.path.join(tmpdir, 'funcname.c')
100 fname = os.path.join(tmpdir, 'funcname.c')
101 f = open(fname, 'w')
101 f = open(fname, 'w')
102 f.write('int main(void) {\n')
102 f.write('int main(void) {\n')
103 f.write(' %s();\n' % funcname)
103 f.write(' %s();\n' % funcname)
104 f.write('}\n')
104 f.write('}\n')
105 f.close()
105 f.close()
106 # Redirect stderr to /dev/null to hide any error messages
106 # Redirect stderr to /dev/null to hide any error messages
107 # from the compiler.
107 # from the compiler.
108 # This will have to be changed if we ever have to check
108 # This will have to be changed if we ever have to check
109 # for a function on Windows.
109 # for a function on Windows.
110 devnull = open('/dev/null', 'w')
110 devnull = open('/dev/null', 'w')
111 oldstderr = os.dup(sys.stderr.fileno())
111 oldstderr = os.dup(sys.stderr.fileno())
112 os.dup2(devnull.fileno(), sys.stderr.fileno())
112 os.dup2(devnull.fileno(), sys.stderr.fileno())
113 objects = cc.compile([fname], output_dir=tmpdir)
113 objects = cc.compile([fname], output_dir=tmpdir)
114 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
114 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
115 return True
115 return True
116 except Exception:
116 except Exception:
117 return False
117 return False
118 finally:
118 finally:
119 if oldstderr is not None:
119 if oldstderr is not None:
120 os.dup2(oldstderr, sys.stderr.fileno())
120 os.dup2(oldstderr, sys.stderr.fileno())
121 if devnull is not None:
121 if devnull is not None:
122 devnull.close()
122 devnull.close()
123 shutil.rmtree(tmpdir)
123 shutil.rmtree(tmpdir)
124
124
125 # py2exe needs to be installed to work
125 # py2exe needs to be installed to work
126 try:
126 try:
127 import py2exe
127 import py2exe
128 py2exe.Distribution # silence unused import warning
128 py2exe.Distribution # silence unused import warning
129 py2exeloaded = True
129 py2exeloaded = True
130 # import py2exe's patched Distribution class
130 # import py2exe's patched Distribution class
131 from distutils.core import Distribution
131 from distutils.core import Distribution
132 except ImportError:
132 except ImportError:
133 py2exeloaded = False
133 py2exeloaded = False
134
134
135 def runcmd(cmd, env):
135 def runcmd(cmd, env):
136 if (sys.platform == 'plan9'
136 if (sys.platform == 'plan9'
137 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
137 and (sys.version_info[0] == 2 and sys.version_info[1] < 7)):
138 # subprocess kludge to work around issues in half-baked Python
138 # subprocess kludge to work around issues in half-baked Python
139 # ports, notably bichued/python:
139 # ports, notably bichued/python:
140 _, out, err = os.popen3(cmd)
140 _, out, err = os.popen3(cmd)
141 return str(out), str(err)
141 return str(out), str(err)
142 else:
142 else:
143 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
143 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
144 stderr=subprocess.PIPE, env=env)
144 stderr=subprocess.PIPE, env=env)
145 out, err = p.communicate()
145 out, err = p.communicate()
146 return out, err
146 return out, err
147
147
148 def runhg(cmd, env):
148 def runhg(cmd, env):
149 out, err = runcmd(cmd, env)
149 out, err = runcmd(cmd, env)
150 # If root is executing setup.py, but the repository is owned by
150 # If root is executing setup.py, but the repository is owned by
151 # another user (as in "sudo python setup.py install") we will get
151 # another user (as in "sudo python setup.py install") we will get
152 # trust warnings since the .hg/hgrc file is untrusted. That is
152 # trust warnings since the .hg/hgrc file is untrusted. That is
153 # fine, we don't want to load it anyway. Python may warn about
153 # fine, we don't want to load it anyway. Python may warn about
154 # a missing __init__.py in mercurial/locale, we also ignore that.
154 # a missing __init__.py in mercurial/locale, we also ignore that.
155 err = [e for e in err.splitlines()
155 err = [e for e in err.splitlines()
156 if not e.startswith(b'not trusting file') \
156 if not e.startswith(b'not trusting file') \
157 and not e.startswith(b'warning: Not importing') \
157 and not e.startswith(b'warning: Not importing') \
158 and not e.startswith(b'obsolete feature not enabled')]
158 and not e.startswith(b'obsolete feature not enabled')]
159 if err:
159 if err:
160 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
160 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
161 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
161 printf(b'\n'.join([b' ' + e for e in err]), file=sys.stderr)
162 return ''
162 return ''
163 return out
163 return out
164
164
165 version = ''
165 version = ''
166
166
167 # Execute hg out of this directory with a custom environment which takes care
167 # Execute hg out of this directory with a custom environment which takes care
168 # to not use any hgrc files and do no localization.
168 # to not use any hgrc files and do no localization.
169 env = {'HGMODULEPOLICY': 'py',
169 env = {'HGMODULEPOLICY': 'py',
170 'HGRCPATH': '',
170 'HGRCPATH': '',
171 'LANGUAGE': 'C'}
171 'LANGUAGE': 'C'}
172 if 'LD_LIBRARY_PATH' in os.environ:
172 if 'LD_LIBRARY_PATH' in os.environ:
173 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
173 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
174 if 'SystemRoot' in os.environ:
174 if 'SystemRoot' in os.environ:
175 # Copy SystemRoot into the custom environment for Python 2.6
175 # Copy SystemRoot into the custom environment for Python 2.6
176 # under Windows. Otherwise, the subprocess will fail with
176 # under Windows. Otherwise, the subprocess will fail with
177 # error 0xc0150004. See: http://bugs.python.org/issue3440
177 # error 0xc0150004. See: http://bugs.python.org/issue3440
178 env['SystemRoot'] = os.environ['SystemRoot']
178 env['SystemRoot'] = os.environ['SystemRoot']
179
179
180 if os.path.isdir('.hg'):
180 if os.path.isdir('.hg'):
181 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
181 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
182 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
182 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
183 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
183 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
184 if numerictags: # tag(s) found
184 if numerictags: # tag(s) found
185 version = numerictags[-1]
185 version = numerictags[-1]
186 if hgid.endswith('+'): # propagate the dirty status to the tag
186 if hgid.endswith('+'): # propagate the dirty status to the tag
187 version += '+'
187 version += '+'
188 else: # no tag found
188 else: # no tag found
189 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
189 ltagcmd = [sys.executable, 'hg', 'parents', '--template',
190 '{latesttag}']
190 '{latesttag}']
191 ltag = runhg(ltagcmd, env)
191 ltag = runhg(ltagcmd, env)
192 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
192 changessincecmd = [sys.executable, 'hg', 'log', '-T', 'x\n', '-r',
193 "only(.,'%s')" % ltag]
193 "only(.,'%s')" % ltag]
194 changessince = len(runhg(changessincecmd, env).splitlines())
194 changessince = len(runhg(changessincecmd, env).splitlines())
195 version = '%s+%s-%s' % (ltag, changessince, hgid)
195 version = '%s+%s-%s' % (ltag, changessince, hgid)
196 if version.endswith('+'):
196 if version.endswith('+'):
197 version += time.strftime('%Y%m%d')
197 version += time.strftime('%Y%m%d')
198 elif os.path.exists('.hg_archival.txt'):
198 elif os.path.exists('.hg_archival.txt'):
199 kw = dict([[t.strip() for t in l.split(':', 1)]
199 kw = dict([[t.strip() for t in l.split(':', 1)]
200 for l in open('.hg_archival.txt')])
200 for l in open('.hg_archival.txt')])
201 if 'tag' in kw:
201 if 'tag' in kw:
202 version = kw['tag']
202 version = kw['tag']
203 elif 'latesttag' in kw:
203 elif 'latesttag' in kw:
204 if 'changessincelatesttag' in kw:
204 if 'changessincelatesttag' in kw:
205 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
205 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
206 else:
206 else:
207 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
207 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
208 else:
208 else:
209 version = kw.get('node', '')[:12]
209 version = kw.get('node', '')[:12]
210
210
211 if version:
211 if version:
212 with open("mercurial/__version__.py", "w") as f:
212 with open("mercurial/__version__.py", "w") as f:
213 f.write('# this file is autogenerated by setup.py\n')
213 f.write('# this file is autogenerated by setup.py\n')
214 f.write('version = "%s"\n' % version)
214 f.write('version = "%s"\n' % version)
215
215
216 try:
216 try:
217 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
217 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
218 os.environ['HGMODULEPOLICY'] = 'py'
218 os.environ['HGMODULEPOLICY'] = 'py'
219 from mercurial import __version__
219 from mercurial import __version__
220 version = __version__.version
220 version = __version__.version
221 except ImportError:
221 except ImportError:
222 version = 'unknown'
222 version = 'unknown'
223 finally:
223 finally:
224 if oldpolicy is None:
224 if oldpolicy is None:
225 del os.environ['HGMODULEPOLICY']
225 del os.environ['HGMODULEPOLICY']
226 else:
226 else:
227 os.environ['HGMODULEPOLICY'] = oldpolicy
227 os.environ['HGMODULEPOLICY'] = oldpolicy
228
228
229 class hgbuild(build):
229 class hgbuild(build):
230 # Insert hgbuildmo first so that files in mercurial/locale/ are found
230 # Insert hgbuildmo first so that files in mercurial/locale/ are found
231 # when build_py is run next.
231 # when build_py is run next.
232 sub_commands = [('build_mo', None)] + build.sub_commands
232 sub_commands = [('build_mo', None)] + build.sub_commands
233
233
234 class hgbuildmo(build):
234 class hgbuildmo(build):
235
235
236 description = "build translations (.mo files)"
236 description = "build translations (.mo files)"
237
237
238 def run(self):
238 def run(self):
239 if not find_executable('msgfmt'):
239 if not find_executable('msgfmt'):
240 self.warn("could not find msgfmt executable, no translations "
240 self.warn("could not find msgfmt executable, no translations "
241 "will be built")
241 "will be built")
242 return
242 return
243
243
244 podir = 'i18n'
244 podir = 'i18n'
245 if not os.path.isdir(podir):
245 if not os.path.isdir(podir):
246 self.warn("could not find %s/ directory" % podir)
246 self.warn("could not find %s/ directory" % podir)
247 return
247 return
248
248
249 join = os.path.join
249 join = os.path.join
250 for po in os.listdir(podir):
250 for po in os.listdir(podir):
251 if not po.endswith('.po'):
251 if not po.endswith('.po'):
252 continue
252 continue
253 pofile = join(podir, po)
253 pofile = join(podir, po)
254 modir = join('locale', po[:-3], 'LC_MESSAGES')
254 modir = join('locale', po[:-3], 'LC_MESSAGES')
255 mofile = join(modir, 'hg.mo')
255 mofile = join(modir, 'hg.mo')
256 mobuildfile = join('mercurial', mofile)
256 mobuildfile = join('mercurial', mofile)
257 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
257 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
258 if sys.platform != 'sunos5':
258 if sys.platform != 'sunos5':
259 # msgfmt on Solaris does not know about -c
259 # msgfmt on Solaris does not know about -c
260 cmd.append('-c')
260 cmd.append('-c')
261 self.mkpath(join('mercurial', modir))
261 self.mkpath(join('mercurial', modir))
262 self.make_file([pofile], mobuildfile, spawn, (cmd,))
262 self.make_file([pofile], mobuildfile, spawn, (cmd,))
263
263
264
264
265 class hgdist(Distribution):
265 class hgdist(Distribution):
266 pure = False
266 pure = False
267 cffi = ispypy
267 cffi = ispypy
268
268
269 global_options = Distribution.global_options + \
269 global_options = Distribution.global_options + \
270 [('pure', None, "use pure (slow) Python "
270 [('pure', None, "use pure (slow) Python "
271 "code instead of C extensions"),
271 "code instead of C extensions"),
272 ]
272 ]
273
273
274 def has_ext_modules(self):
274 def has_ext_modules(self):
275 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
275 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
276 # too late for some cases
276 # too late for some cases
277 return not self.pure and Distribution.has_ext_modules(self)
277 return not self.pure and Distribution.has_ext_modules(self)
278
278
279 class hgbuildext(build_ext):
279 class hgbuildext(build_ext):
280
280
281 def build_extension(self, ext):
281 def build_extension(self, ext):
282 try:
282 try:
283 build_ext.build_extension(self, ext)
283 build_ext.build_extension(self, ext)
284 except CCompilerError:
284 except CCompilerError:
285 if not getattr(ext, 'optional', False):
285 if not getattr(ext, 'optional', False):
286 raise
286 raise
287 log.warn("Failed to build optional extension '%s' (skipping)",
287 log.warn("Failed to build optional extension '%s' (skipping)",
288 ext.name)
288 ext.name)
289
289
290 class hgbuildscripts(build_scripts):
290 class hgbuildscripts(build_scripts):
291 def run(self):
291 def run(self):
292 if os.name != 'nt' or self.distribution.pure:
292 if os.name != 'nt' or self.distribution.pure:
293 return build_scripts.run(self)
293 return build_scripts.run(self)
294
294
295 exebuilt = False
295 exebuilt = False
296 try:
296 try:
297 self.run_command('build_hgexe')
297 self.run_command('build_hgexe')
298 exebuilt = True
298 exebuilt = True
299 except (DistutilsError, CCompilerError):
299 except (DistutilsError, CCompilerError):
300 log.warn('failed to build optional hg.exe')
300 log.warn('failed to build optional hg.exe')
301
301
302 if exebuilt:
302 if exebuilt:
303 # Copying hg.exe to the scripts build directory ensures it is
303 # Copying hg.exe to the scripts build directory ensures it is
304 # installed by the install_scripts command.
304 # installed by the install_scripts command.
305 hgexecommand = self.get_finalized_command('build_hgexe')
305 hgexecommand = self.get_finalized_command('build_hgexe')
306 dest = os.path.join(self.build_dir, 'hg.exe')
306 dest = os.path.join(self.build_dir, 'hg.exe')
307 self.mkpath(self.build_dir)
307 self.mkpath(self.build_dir)
308 self.copy_file(hgexecommand.hgexepath, dest)
308 self.copy_file(hgexecommand.hgexepath, dest)
309
309
310 # Remove hg.bat because it is redundant with hg.exe.
310 # Remove hg.bat because it is redundant with hg.exe.
311 self.scripts.remove('contrib/win32/hg.bat')
311 self.scripts.remove('contrib/win32/hg.bat')
312
312
313 return build_scripts.run(self)
313 return build_scripts.run(self)
314
314
315 class hgbuildpy(build_py):
315 class hgbuildpy(build_py):
316 def finalize_options(self):
316 def finalize_options(self):
317 build_py.finalize_options(self)
317 build_py.finalize_options(self)
318
318
319 if self.distribution.pure:
319 if self.distribution.pure:
320 self.distribution.ext_modules = []
320 self.distribution.ext_modules = []
321 elif self.distribution.cffi:
321 elif self.distribution.cffi:
322 from mercurial.cffi import (
322 from mercurial.cffi import (
323 bdiff,
323 bdiff,
324 mpatch,
324 mpatch,
325 )
325 )
326 exts = [mpatch.ffi.distutils_extension(),
326 exts = [mpatch.ffi.distutils_extension(),
327 bdiff.ffi.distutils_extension()]
327 bdiff.ffi.distutils_extension()]
328 # cffi modules go here
328 # cffi modules go here
329 if sys.platform == 'darwin':
329 if sys.platform == 'darwin':
330 from mercurial.cffi import osutil
330 from mercurial.cffi import osutil
331 exts.append(osutil.ffi.distutils_extension())
331 exts.append(osutil.ffi.distutils_extension())
332 self.distribution.ext_modules = exts
332 self.distribution.ext_modules = exts
333 else:
333 else:
334 h = os.path.join(get_python_inc(), 'Python.h')
334 h = os.path.join(get_python_inc(), 'Python.h')
335 if not os.path.exists(h):
335 if not os.path.exists(h):
336 raise SystemExit('Python headers are required to build '
336 raise SystemExit('Python headers are required to build '
337 'Mercurial but weren\'t found in %s' % h)
337 'Mercurial but weren\'t found in %s' % h)
338
338
339 def run(self):
339 def run(self):
340 if self.distribution.pure:
340 if self.distribution.pure:
341 modulepolicy = 'py'
341 modulepolicy = 'py'
342 else:
342 else:
343 modulepolicy = 'c'
343 modulepolicy = 'c'
344 with open("mercurial/__modulepolicy__.py", "w") as f:
344 with open("mercurial/__modulepolicy__.py", "w") as f:
345 f.write('# this file is autogenerated by setup.py\n')
345 f.write('# this file is autogenerated by setup.py\n')
346 f.write('modulepolicy = "%s"\n' % modulepolicy)
346 f.write('modulepolicy = "%s"\n' % modulepolicy)
347
347
348 build_py.run(self)
348 build_py.run(self)
349
349
350 class buildhgextindex(Command):
350 class buildhgextindex(Command):
351 description = 'generate prebuilt index of hgext (for frozen package)'
351 description = 'generate prebuilt index of hgext (for frozen package)'
352 user_options = []
352 user_options = []
353 _indexfilename = 'hgext/__index__.py'
353 _indexfilename = 'hgext/__index__.py'
354
354
355 def initialize_options(self):
355 def initialize_options(self):
356 pass
356 pass
357
357
358 def finalize_options(self):
358 def finalize_options(self):
359 pass
359 pass
360
360
361 def run(self):
361 def run(self):
362 if os.path.exists(self._indexfilename):
362 if os.path.exists(self._indexfilename):
363 with open(self._indexfilename, 'w') as f:
363 with open(self._indexfilename, 'w') as f:
364 f.write('# empty\n')
364 f.write('# empty\n')
365
365
366 # here no extension enabled, disabled() lists up everything
366 # here no extension enabled, disabled() lists up everything
367 code = ('import pprint; from mercurial import extensions; '
367 code = ('import pprint; from mercurial import extensions; '
368 'pprint.pprint(extensions.disabled())')
368 'pprint.pprint(extensions.disabled())')
369 out, err = runcmd([sys.executable, '-c', code], env)
369 out, err = runcmd([sys.executable, '-c', code], env)
370 if err:
370 if err:
371 raise DistutilsExecError(err)
371 raise DistutilsExecError(err)
372
372
373 with open(self._indexfilename, 'w') as f:
373 with open(self._indexfilename, 'w') as f:
374 f.write('# this file is autogenerated by setup.py\n')
374 f.write('# this file is autogenerated by setup.py\n')
375 f.write('docs = ')
375 f.write('docs = ')
376 f.write(out)
376 f.write(out)
377
377
378 class buildhgexe(build_ext):
378 class buildhgexe(build_ext):
379 description = 'compile hg.exe from mercurial/exewrapper.c'
379 description = 'compile hg.exe from mercurial/exewrapper.c'
380
380
381 def build_extensions(self):
381 def build_extensions(self):
382 if os.name != 'nt':
382 if os.name != 'nt':
383 return
383 return
384 if isinstance(self.compiler, HackedMingw32CCompiler):
384 if isinstance(self.compiler, HackedMingw32CCompiler):
385 self.compiler.compiler_so = self.compiler.compiler # no -mdll
385 self.compiler.compiler_so = self.compiler.compiler # no -mdll
386 self.compiler.dll_libraries = [] # no -lmsrvc90
386 self.compiler.dll_libraries = [] # no -lmsrvc90
387
387
388 # Different Python installs can have different Python library
388 # Different Python installs can have different Python library
389 # names. e.g. the official CPython distribution uses pythonXY.dll
389 # names. e.g. the official CPython distribution uses pythonXY.dll
390 # and MinGW uses libpythonX.Y.dll.
390 # and MinGW uses libpythonX.Y.dll.
391 _kernel32 = ctypes.windll.kernel32
391 _kernel32 = ctypes.windll.kernel32
392 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
392 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
393 ctypes.c_void_p,
393 ctypes.c_void_p,
394 ctypes.c_ulong]
394 ctypes.c_ulong]
395 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
395 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
396 size = 1000
396 size = 1000
397 buf = ctypes.create_string_buffer(size + 1)
397 buf = ctypes.create_string_buffer(size + 1)
398 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
398 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
399 size)
399 size)
400
400
401 if filelen > 0 and filelen != size:
401 if filelen > 0 and filelen != size:
402 dllbasename = os.path.basename(buf.value)
402 dllbasename = os.path.basename(buf.value)
403 if not dllbasename.lower().endswith('.dll'):
403 if not dllbasename.lower().endswith('.dll'):
404 raise SystemExit('Python DLL does not end with .dll: %s' %
404 raise SystemExit('Python DLL does not end with .dll: %s' %
405 dllbasename)
405 dllbasename)
406 pythonlib = dllbasename[:-4]
406 pythonlib = dllbasename[:-4]
407 else:
407 else:
408 log.warn('could not determine Python DLL filename; '
408 log.warn('could not determine Python DLL filename; '
409 'assuming pythonXY')
409 'assuming pythonXY')
410
410
411 hv = sys.hexversion
411 hv = sys.hexversion
412 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
412 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
413
413
414 log.info('using %s as Python library name' % pythonlib)
414 log.info('using %s as Python library name' % pythonlib)
415 with open('mercurial/hgpythonlib.h', 'wb') as f:
415 with open('mercurial/hgpythonlib.h', 'wb') as f:
416 f.write('/* this file is autogenerated by setup.py */\n')
416 f.write('/* this file is autogenerated by setup.py */\n')
417 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
417 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
418 objects = self.compiler.compile(['mercurial/exewrapper.c'],
418 objects = self.compiler.compile(['mercurial/exewrapper.c'],
419 output_dir=self.build_temp)
419 output_dir=self.build_temp)
420 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
420 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
421 target = os.path.join(dir, 'hg')
421 target = os.path.join(dir, 'hg')
422 self.compiler.link_executable(objects, target,
422 self.compiler.link_executable(objects, target,
423 libraries=[],
423 libraries=[],
424 output_dir=self.build_temp)
424 output_dir=self.build_temp)
425
425
426 @property
426 @property
427 def hgexepath(self):
427 def hgexepath(self):
428 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
428 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
429 return os.path.join(self.build_temp, dir, 'hg.exe')
429 return os.path.join(self.build_temp, dir, 'hg.exe')
430
430
431 class hginstalllib(install_lib):
431 class hginstalllib(install_lib):
432 '''
432 '''
433 This is a specialization of install_lib that replaces the copy_file used
433 This is a specialization of install_lib that replaces the copy_file used
434 there so that it supports setting the mode of files after copying them,
434 there so that it supports setting the mode of files after copying them,
435 instead of just preserving the mode that the files originally had. If your
435 instead of just preserving the mode that the files originally had. If your
436 system has a umask of something like 027, preserving the permissions when
436 system has a umask of something like 027, preserving the permissions when
437 copying will lead to a broken install.
437 copying will lead to a broken install.
438
438
439 Note that just passing keep_permissions=False to copy_file would be
439 Note that just passing keep_permissions=False to copy_file would be
440 insufficient, as it might still be applying a umask.
440 insufficient, as it might still be applying a umask.
441 '''
441 '''
442
442
443 def run(self):
443 def run(self):
444 realcopyfile = file_util.copy_file
444 realcopyfile = file_util.copy_file
445 def copyfileandsetmode(*args, **kwargs):
445 def copyfileandsetmode(*args, **kwargs):
446 src, dst = args[0], args[1]
446 src, dst = args[0], args[1]
447 dst, copied = realcopyfile(*args, **kwargs)
447 dst, copied = realcopyfile(*args, **kwargs)
448 if copied:
448 if copied:
449 st = os.stat(src)
449 st = os.stat(src)
450 # Persist executable bit (apply it to group and other if user
450 # Persist executable bit (apply it to group and other if user
451 # has it)
451 # has it)
452 if st[stat.ST_MODE] & stat.S_IXUSR:
452 if st[stat.ST_MODE] & stat.S_IXUSR:
453 setmode = int('0755', 8)
453 setmode = int('0755', 8)
454 else:
454 else:
455 setmode = int('0644', 8)
455 setmode = int('0644', 8)
456 m = stat.S_IMODE(st[stat.ST_MODE])
456 m = stat.S_IMODE(st[stat.ST_MODE])
457 m = (m & ~int('0777', 8)) | setmode
457 m = (m & ~int('0777', 8)) | setmode
458 os.chmod(dst, m)
458 os.chmod(dst, m)
459 file_util.copy_file = copyfileandsetmode
459 file_util.copy_file = copyfileandsetmode
460 try:
460 try:
461 install_lib.run(self)
461 install_lib.run(self)
462 finally:
462 finally:
463 file_util.copy_file = realcopyfile
463 file_util.copy_file = realcopyfile
464
464
465 class hginstallscripts(install_scripts):
465 class hginstallscripts(install_scripts):
466 '''
466 '''
467 This is a specialization of install_scripts that replaces the @LIBDIR@ with
467 This is a specialization of install_scripts that replaces the @LIBDIR@ with
468 the configured directory for modules. If possible, the path is made relative
468 the configured directory for modules. If possible, the path is made relative
469 to the directory for scripts.
469 to the directory for scripts.
470 '''
470 '''
471
471
472 def initialize_options(self):
472 def initialize_options(self):
473 install_scripts.initialize_options(self)
473 install_scripts.initialize_options(self)
474
474
475 self.install_lib = None
475 self.install_lib = None
476
476
477 def finalize_options(self):
477 def finalize_options(self):
478 install_scripts.finalize_options(self)
478 install_scripts.finalize_options(self)
479 self.set_undefined_options('install',
479 self.set_undefined_options('install',
480 ('install_lib', 'install_lib'))
480 ('install_lib', 'install_lib'))
481
481
482 def run(self):
482 def run(self):
483 install_scripts.run(self)
483 install_scripts.run(self)
484
484
485 # It only makes sense to replace @LIBDIR@ with the install path if
485 # It only makes sense to replace @LIBDIR@ with the install path if
486 # the install path is known. For wheels, the logic below calculates
486 # the install path is known. For wheels, the logic below calculates
487 # the libdir to be "../..". This is because the internal layout of a
487 # the libdir to be "../..". This is because the internal layout of a
488 # wheel archive looks like:
488 # wheel archive looks like:
489 #
489 #
490 # mercurial-3.6.1.data/scripts/hg
490 # mercurial-3.6.1.data/scripts/hg
491 # mercurial/__init__.py
491 # mercurial/__init__.py
492 #
492 #
493 # When installing wheels, the subdirectories of the "<pkg>.data"
493 # When installing wheels, the subdirectories of the "<pkg>.data"
494 # directory are translated to system local paths and files therein
494 # directory are translated to system local paths and files therein
495 # are copied in place. The mercurial/* files are installed into the
495 # are copied in place. The mercurial/* files are installed into the
496 # site-packages directory. However, the site-packages directory
496 # site-packages directory. However, the site-packages directory
497 # isn't known until wheel install time. This means we have no clue
497 # isn't known until wheel install time. This means we have no clue
498 # at wheel generation time what the installed site-packages directory
498 # at wheel generation time what the installed site-packages directory
499 # will be. And, wheels don't appear to provide the ability to register
499 # will be. And, wheels don't appear to provide the ability to register
500 # custom code to run during wheel installation. This all means that
500 # custom code to run during wheel installation. This all means that
501 # we can't reliably set the libdir in wheels: the default behavior
501 # we can't reliably set the libdir in wheels: the default behavior
502 # of looking in sys.path must do.
502 # of looking in sys.path must do.
503
503
504 if (os.path.splitdrive(self.install_dir)[0] !=
504 if (os.path.splitdrive(self.install_dir)[0] !=
505 os.path.splitdrive(self.install_lib)[0]):
505 os.path.splitdrive(self.install_lib)[0]):
506 # can't make relative paths from one drive to another, so use an
506 # can't make relative paths from one drive to another, so use an
507 # absolute path instead
507 # absolute path instead
508 libdir = self.install_lib
508 libdir = self.install_lib
509 else:
509 else:
510 common = os.path.commonprefix((self.install_dir, self.install_lib))
510 common = os.path.commonprefix((self.install_dir, self.install_lib))
511 rest = self.install_dir[len(common):]
511 rest = self.install_dir[len(common):]
512 uplevel = len([n for n in os.path.split(rest) if n])
512 uplevel = len([n for n in os.path.split(rest) if n])
513
513
514 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
514 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
515
515
516 for outfile in self.outfiles:
516 for outfile in self.outfiles:
517 with open(outfile, 'rb') as fp:
517 with open(outfile, 'rb') as fp:
518 data = fp.read()
518 data = fp.read()
519
519
520 # skip binary files
520 # skip binary files
521 if b'\0' in data:
521 if b'\0' in data:
522 continue
522 continue
523
523
524 # During local installs, the shebang will be rewritten to the final
524 # During local installs, the shebang will be rewritten to the final
525 # install path. During wheel packaging, the shebang has a special
525 # install path. During wheel packaging, the shebang has a special
526 # value.
526 # value.
527 if data.startswith(b'#!python'):
527 if data.startswith(b'#!python'):
528 log.info('not rewriting @LIBDIR@ in %s because install path '
528 log.info('not rewriting @LIBDIR@ in %s because install path '
529 'not known' % outfile)
529 'not known' % outfile)
530 continue
530 continue
531
531
532 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
532 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
533 with open(outfile, 'wb') as fp:
533 with open(outfile, 'wb') as fp:
534 fp.write(data)
534 fp.write(data)
535
535
536 cmdclass = {'build': hgbuild,
536 cmdclass = {'build': hgbuild,
537 'build_mo': hgbuildmo,
537 'build_mo': hgbuildmo,
538 'build_ext': hgbuildext,
538 'build_ext': hgbuildext,
539 'build_py': hgbuildpy,
539 'build_py': hgbuildpy,
540 'build_scripts': hgbuildscripts,
540 'build_scripts': hgbuildscripts,
541 'build_hgextindex': buildhgextindex,
541 'build_hgextindex': buildhgextindex,
542 'install_lib': hginstalllib,
542 'install_lib': hginstalllib,
543 'install_scripts': hginstallscripts,
543 'install_scripts': hginstallscripts,
544 'build_hgexe': buildhgexe,
544 'build_hgexe': buildhgexe,
545 }
545 }
546
546
547 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
547 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
548 'mercurial.pure',
548 'mercurial.pure',
549 'hgext', 'hgext.convert', 'hgext.fsmonitor',
549 'hgext', 'hgext.convert', 'hgext.fsmonitor',
550 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
550 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
551 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
551 'hgext.largefiles', 'hgext.zeroconf', 'hgext3rd']
552
552
553 common_depends = ['mercurial/bitmanipulation.h',
553 common_depends = ['mercurial/bitmanipulation.h',
554 'mercurial/compat.h',
554 'mercurial/compat.h',
555 'mercurial/util.h']
555 'mercurial/util.h']
556
556
557 osutil_cflags = []
557 osutil_cflags = []
558 osutil_ldflags = []
558 osutil_ldflags = []
559
559
560 # platform specific macros: HAVE_SETPROCTITLE
560 # platform specific macros: HAVE_SETPROCTITLE
561 for plat, func in [(re.compile('freebsd'), 'setproctitle')]:
561 for plat, func in [(re.compile('freebsd'), 'setproctitle')]:
562 if plat.search(sys.platform) and hasfunction(new_compiler(), func):
562 if plat.search(sys.platform) and hasfunction(new_compiler(), func):
563 osutil_cflags.append('-DHAVE_%s' % func.upper())
563 osutil_cflags.append('-DHAVE_%s' % func.upper())
564
564
565 if sys.platform == 'darwin':
565 if sys.platform == 'darwin':
566 osutil_ldflags += ['-framework', 'ApplicationServices']
566 osutil_ldflags += ['-framework', 'ApplicationServices']
567
567
568 extmodules = [
568 extmodules = [
569 Extension('mercurial.base85', ['mercurial/base85.c'],
569 Extension('mercurial.base85', ['mercurial/base85.c'],
570 depends=common_depends),
570 depends=common_depends),
571 Extension('mercurial.bdiff', ['mercurial/bdiff.c',
571 Extension('mercurial.bdiff', ['mercurial/bdiff.c',
572 'mercurial/bdiff_module.c'],
572 'mercurial/bdiff_module.c'],
573 depends=common_depends + ['mercurial/bdiff.h']),
573 depends=common_depends + ['mercurial/bdiff.h']),
574 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
574 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
575 depends=common_depends),
575 depends=common_depends),
576 Extension('mercurial.mpatch', ['mercurial/mpatch.c',
576 Extension('mercurial.mpatch', ['mercurial/mpatch.c',
577 'mercurial/mpatch_module.c'],
577 'mercurial/mpatch_module.c'],
578 depends=common_depends),
578 depends=common_depends),
579 Extension('mercurial.parsers', ['mercurial/dirs.c',
579 Extension('mercurial.parsers', ['mercurial/dirs.c',
580 'mercurial/manifest.c',
580 'mercurial/manifest.c',
581 'mercurial/parsers.c',
581 'mercurial/parsers.c',
582 'mercurial/pathencode.c'],
582 'mercurial/pathencode.c'],
583 depends=common_depends),
583 depends=common_depends),
584 Extension('mercurial.osutil', ['mercurial/osutil.c'],
584 Extension('mercurial.osutil', ['mercurial/osutil.c'],
585 extra_compile_args=osutil_cflags,
585 extra_compile_args=osutil_cflags,
586 extra_link_args=osutil_ldflags,
586 extra_link_args=osutil_ldflags,
587 depends=common_depends),
587 depends=common_depends),
588 Extension('hgext.fsmonitor.pywatchman.bser',
588 Extension('hgext.fsmonitor.pywatchman.bser',
589 ['hgext/fsmonitor/pywatchman/bser.c']),
589 ['hgext/fsmonitor/pywatchman/bser.c']),
590 ]
590 ]
591
591
592 sys.path.insert(0, 'contrib/python-zstandard')
593 import setup_zstd
594 extmodules.append(setup_zstd.get_c_extension('mercurial.zstd'))
595
592 try:
596 try:
593 from distutils import cygwinccompiler
597 from distutils import cygwinccompiler
594
598
595 # the -mno-cygwin option has been deprecated for years
599 # the -mno-cygwin option has been deprecated for years
596 compiler = cygwinccompiler.Mingw32CCompiler
600 compiler = cygwinccompiler.Mingw32CCompiler
597
601
598 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
602 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
599 def __init__(self, *args, **kwargs):
603 def __init__(self, *args, **kwargs):
600 compiler.__init__(self, *args, **kwargs)
604 compiler.__init__(self, *args, **kwargs)
601 for i in 'compiler compiler_so linker_exe linker_so'.split():
605 for i in 'compiler compiler_so linker_exe linker_so'.split():
602 try:
606 try:
603 getattr(self, i).remove('-mno-cygwin')
607 getattr(self, i).remove('-mno-cygwin')
604 except ValueError:
608 except ValueError:
605 pass
609 pass
606
610
607 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
611 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
608 except ImportError:
612 except ImportError:
609 # the cygwinccompiler package is not available on some Python
613 # the cygwinccompiler package is not available on some Python
610 # distributions like the ones from the optware project for Synology
614 # distributions like the ones from the optware project for Synology
611 # DiskStation boxes
615 # DiskStation boxes
612 class HackedMingw32CCompiler(object):
616 class HackedMingw32CCompiler(object):
613 pass
617 pass
614
618
615 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
619 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
616 'help/*.txt',
620 'help/*.txt',
617 'help/internals/*.txt',
621 'help/internals/*.txt',
618 'default.d/*.rc',
622 'default.d/*.rc',
619 'dummycert.pem']}
623 'dummycert.pem']}
620
624
621 def ordinarypath(p):
625 def ordinarypath(p):
622 return p and p[0] != '.' and p[-1] != '~'
626 return p and p[0] != '.' and p[-1] != '~'
623
627
624 for root in ('templates',):
628 for root in ('templates',):
625 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
629 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
626 curdir = curdir.split(os.sep, 1)[1]
630 curdir = curdir.split(os.sep, 1)[1]
627 dirs[:] = filter(ordinarypath, dirs)
631 dirs[:] = filter(ordinarypath, dirs)
628 for f in filter(ordinarypath, files):
632 for f in filter(ordinarypath, files):
629 f = os.path.join(curdir, f)
633 f = os.path.join(curdir, f)
630 packagedata['mercurial'].append(f)
634 packagedata['mercurial'].append(f)
631
635
632 datafiles = []
636 datafiles = []
633 setupversion = version
637 setupversion = version
634 extra = {}
638 extra = {}
635
639
636 if py2exeloaded:
640 if py2exeloaded:
637 extra['console'] = [
641 extra['console'] = [
638 {'script':'hg',
642 {'script':'hg',
639 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others',
643 'copyright':'Copyright (C) 2005-2016 Matt Mackall and others',
640 'product_version':version}]
644 'product_version':version}]
641 # sub command of 'build' because 'py2exe' does not handle sub_commands
645 # sub command of 'build' because 'py2exe' does not handle sub_commands
642 build.sub_commands.insert(0, ('build_hgextindex', None))
646 build.sub_commands.insert(0, ('build_hgextindex', None))
643 # put dlls in sub directory so that they won't pollute PATH
647 # put dlls in sub directory so that they won't pollute PATH
644 extra['zipfile'] = 'lib/library.zip'
648 extra['zipfile'] = 'lib/library.zip'
645
649
646 if os.name == 'nt':
650 if os.name == 'nt':
647 # Windows binary file versions for exe/dll files must have the
651 # Windows binary file versions for exe/dll files must have the
648 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
652 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
649 setupversion = version.split('+', 1)[0]
653 setupversion = version.split('+', 1)[0]
650
654
651 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
655 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
652 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
656 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
653 if version:
657 if version:
654 version = version[0]
658 version = version[0]
655 if sys.version_info[0] == 3:
659 if sys.version_info[0] == 3:
656 version = version.decode('utf-8')
660 version = version.decode('utf-8')
657 xcode4 = (version.startswith('Xcode') and
661 xcode4 = (version.startswith('Xcode') and
658 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
662 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
659 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
663 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
660 else:
664 else:
661 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
665 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
662 # installed, but instead with only command-line tools. Assume
666 # installed, but instead with only command-line tools. Assume
663 # that only happens on >= Lion, thus no PPC support.
667 # that only happens on >= Lion, thus no PPC support.
664 xcode4 = True
668 xcode4 = True
665 xcode51 = False
669 xcode51 = False
666
670
667 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
671 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
668 # distutils.sysconfig
672 # distutils.sysconfig
669 if xcode4:
673 if xcode4:
670 os.environ['ARCHFLAGS'] = ''
674 os.environ['ARCHFLAGS'] = ''
671
675
672 # XCode 5.1 changes clang such that it now fails to compile if the
676 # XCode 5.1 changes clang such that it now fails to compile if the
673 # -mno-fused-madd flag is passed, but the version of Python shipped with
677 # -mno-fused-madd flag is passed, but the version of Python shipped with
674 # OS X 10.9 Mavericks includes this flag. This causes problems in all
678 # OS X 10.9 Mavericks includes this flag. This causes problems in all
675 # C extension modules, and a bug has been filed upstream at
679 # C extension modules, and a bug has been filed upstream at
676 # http://bugs.python.org/issue21244. We also need to patch this here
680 # http://bugs.python.org/issue21244. We also need to patch this here
677 # so Mercurial can continue to compile in the meantime.
681 # so Mercurial can continue to compile in the meantime.
678 if xcode51:
682 if xcode51:
679 cflags = get_config_var('CFLAGS')
683 cflags = get_config_var('CFLAGS')
680 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
684 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
681 os.environ['CFLAGS'] = (
685 os.environ['CFLAGS'] = (
682 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
686 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
683
687
684 setup(name='mercurial',
688 setup(name='mercurial',
685 version=setupversion,
689 version=setupversion,
686 author='Matt Mackall and many others',
690 author='Matt Mackall and many others',
687 author_email='mercurial@selenic.com',
691 author_email='mercurial@selenic.com',
688 url='https://mercurial-scm.org/',
692 url='https://mercurial-scm.org/',
689 download_url='https://mercurial-scm.org/release/',
693 download_url='https://mercurial-scm.org/release/',
690 description=('Fast scalable distributed SCM (revision control, version '
694 description=('Fast scalable distributed SCM (revision control, version '
691 'control) system'),
695 'control) system'),
692 long_description=('Mercurial is a distributed SCM tool written in Python.'
696 long_description=('Mercurial is a distributed SCM tool written in Python.'
693 ' It is used by a number of large projects that require'
697 ' It is used by a number of large projects that require'
694 ' fast, reliable distributed revision control, such as '
698 ' fast, reliable distributed revision control, such as '
695 'Mozilla.'),
699 'Mozilla.'),
696 license='GNU GPLv2 or any later version',
700 license='GNU GPLv2 or any later version',
697 classifiers=[
701 classifiers=[
698 'Development Status :: 6 - Mature',
702 'Development Status :: 6 - Mature',
699 'Environment :: Console',
703 'Environment :: Console',
700 'Intended Audience :: Developers',
704 'Intended Audience :: Developers',
701 'Intended Audience :: System Administrators',
705 'Intended Audience :: System Administrators',
702 'License :: OSI Approved :: GNU General Public License (GPL)',
706 'License :: OSI Approved :: GNU General Public License (GPL)',
703 'Natural Language :: Danish',
707 'Natural Language :: Danish',
704 'Natural Language :: English',
708 'Natural Language :: English',
705 'Natural Language :: German',
709 'Natural Language :: German',
706 'Natural Language :: Italian',
710 'Natural Language :: Italian',
707 'Natural Language :: Japanese',
711 'Natural Language :: Japanese',
708 'Natural Language :: Portuguese (Brazilian)',
712 'Natural Language :: Portuguese (Brazilian)',
709 'Operating System :: Microsoft :: Windows',
713 'Operating System :: Microsoft :: Windows',
710 'Operating System :: OS Independent',
714 'Operating System :: OS Independent',
711 'Operating System :: POSIX',
715 'Operating System :: POSIX',
712 'Programming Language :: C',
716 'Programming Language :: C',
713 'Programming Language :: Python',
717 'Programming Language :: Python',
714 'Topic :: Software Development :: Version Control',
718 'Topic :: Software Development :: Version Control',
715 ],
719 ],
716 scripts=scripts,
720 scripts=scripts,
717 packages=packages,
721 packages=packages,
718 ext_modules=extmodules,
722 ext_modules=extmodules,
719 data_files=datafiles,
723 data_files=datafiles,
720 package_data=packagedata,
724 package_data=packagedata,
721 cmdclass=cmdclass,
725 cmdclass=cmdclass,
722 distclass=hgdist,
726 distclass=hgdist,
723 options={'py2exe': {'packages': ['hgext', 'email']},
727 options={'py2exe': {'packages': ['hgext', 'email']},
724 'bdist_mpkg': {'zipdist': False,
728 'bdist_mpkg': {'zipdist': False,
725 'license': 'COPYING',
729 'license': 'COPYING',
726 'readme': 'contrib/macosx/Readme.html',
730 'readme': 'contrib/macosx/Readme.html',
727 'welcome': 'contrib/macosx/Welcome.html',
731 'welcome': 'contrib/macosx/Welcome.html',
728 },
732 },
729 },
733 },
730 **extra)
734 **extra)
General Comments 0
You need to be logged in to leave comments. Login now