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