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