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