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