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