##// END OF EJS Templates
setup: disable -mno-cygwin if building under mingw32...
Bryan O'Sullivan -
r17121:d13f47c8 default
parent child Browse files
Show More
@@ -1,513 +1,528
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, 4, 0, 'final'):
9 9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10 10
11 11 if sys.version_info[0] >= 3:
12 12 def b(s):
13 13 '''A helper function to emulate 2.6+ bytes literals using string
14 14 literals.'''
15 15 return s.encode('latin1')
16 16 else:
17 17 def b(s):
18 18 '''A helper function to emulate 2.6+ bytes literals using string
19 19 literals.'''
20 20 return s
21 21
22 22 # Solaris Python packaging brain damage
23 23 try:
24 24 import hashlib
25 25 sha = hashlib.sha1()
26 26 except ImportError:
27 27 try:
28 28 import sha
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 except ImportError:
36 36 raise SystemExit(
37 37 "Couldn't import standard zlib (incomplete Python install).")
38 38
39 39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 40 isironpython = False
41 41 try:
42 42 isironpython = (platform.python_implementation()
43 43 .lower().find("ironpython") != -1)
44 44 except AttributeError:
45 45 pass
46 46
47 47 if isironpython:
48 48 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 49 else:
50 50 try:
51 51 import bz2
52 52 except ImportError:
53 53 raise SystemExit(
54 54 "Couldn't import standard bz2 (incomplete Python install).")
55 55
56 56 import os, subprocess, time
57 57 import shutil
58 58 import tempfile
59 59 from distutils import log
60 60 from distutils.core import setup, Command, Extension
61 61 from distutils.dist import Distribution
62 62 from distutils.command.build import build
63 63 from distutils.command.build_ext import build_ext
64 64 from distutils.command.build_py import build_py
65 65 from distutils.command.install_scripts import install_scripts
66 66 from distutils.spawn import spawn, find_executable
67 67 from distutils.ccompiler import new_compiler
68 from distutils import cygwinccompiler
68 69 from distutils.errors import CCompilerError, DistutilsExecError
69 70 from distutils.sysconfig import get_python_inc
70 71 from distutils.version import StrictVersion
71 72
72 73 convert2to3 = '--c2to3' in sys.argv
73 74 if convert2to3:
74 75 try:
75 76 from distutils.command.build_py import build_py_2to3 as build_py
76 77 from lib2to3.refactor import get_fixers_from_package as getfixers
77 78 except ImportError:
78 79 if sys.version_info[0] < 3:
79 80 raise SystemExit("--c2to3 is only compatible with python3.")
80 81 raise
81 82 sys.path.append('contrib')
82 83 elif sys.version_info[0] >= 3:
83 84 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
84 85
85 86 scripts = ['hg']
86 87 if os.name == 'nt':
87 88 scripts.append('contrib/win32/hg.bat')
88 89
89 90 # simplified version of distutils.ccompiler.CCompiler.has_function
90 91 # that actually removes its temporary files.
91 92 def hasfunction(cc, funcname):
92 93 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
93 94 devnull = oldstderr = None
94 95 try:
95 96 try:
96 97 fname = os.path.join(tmpdir, 'funcname.c')
97 98 f = open(fname, 'w')
98 99 f.write('int main(void) {\n')
99 100 f.write(' %s();\n' % funcname)
100 101 f.write('}\n')
101 102 f.close()
102 103 # Redirect stderr to /dev/null to hide any error messages
103 104 # from the compiler.
104 105 # This will have to be changed if we ever have to check
105 106 # for a function on Windows.
106 107 devnull = open('/dev/null', 'w')
107 108 oldstderr = os.dup(sys.stderr.fileno())
108 109 os.dup2(devnull.fileno(), sys.stderr.fileno())
109 110 objects = cc.compile([fname], output_dir=tmpdir)
110 111 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
111 112 except Exception:
112 113 return False
113 114 return True
114 115 finally:
115 116 if oldstderr is not None:
116 117 os.dup2(oldstderr, sys.stderr.fileno())
117 118 if devnull is not None:
118 119 devnull.close()
119 120 shutil.rmtree(tmpdir)
120 121
121 122 # py2exe needs to be installed to work
122 123 try:
123 124 import py2exe
124 125 py2exeloaded = True
125 126 # import py2exe's patched Distribution class
126 127 from distutils.core import Distribution
127 128 except ImportError:
128 129 py2exeloaded = False
129 130
130 131 def runcmd(cmd, env):
131 132 if sys.platform == 'plan9':
132 133 # subprocess kludge to work around issues in half-baked Python
133 134 # ports, notably bichued/python:
134 135 _, out, err = os.popen3(cmd)
135 136 return str(out), str(err)
136 137 else:
137 138 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
138 139 stderr=subprocess.PIPE, env=env)
139 140 out, err = p.communicate()
140 141 return out, err
141 142
142 143 def runhg(cmd, env):
143 144 out, err = runcmd(cmd, env)
144 145 # If root is executing setup.py, but the repository is owned by
145 146 # another user (as in "sudo python setup.py install") we will get
146 147 # trust warnings since the .hg/hgrc file is untrusted. That is
147 148 # fine, we don't want to load it anyway. Python may warn about
148 149 # a missing __init__.py in mercurial/locale, we also ignore that.
149 150 err = [e for e in err.splitlines()
150 151 if not e.startswith(b('Not trusting file')) \
151 152 and not e.startswith(b('warning: Not importing'))]
152 153 if err:
153 154 return ''
154 155 return out
155 156
156 157 version = ''
157 158
158 159 # Execute hg out of this directory with a custom environment which
159 160 # includes the pure Python modules in mercurial/pure. We also take
160 161 # care to not use any hgrc files and do no localization.
161 162 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
162 163 env = {'PYTHONPATH': os.pathsep.join(pypath),
163 164 'HGRCPATH': '',
164 165 'LANGUAGE': 'C'}
165 166 if 'LD_LIBRARY_PATH' in os.environ:
166 167 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
167 168 if 'SystemRoot' in os.environ:
168 169 # Copy SystemRoot into the custom environment for Python 2.6
169 170 # under Windows. Otherwise, the subprocess will fail with
170 171 # error 0xc0150004. See: http://bugs.python.org/issue3440
171 172 env['SystemRoot'] = os.environ['SystemRoot']
172 173
173 174 if os.path.isdir('.hg'):
174 175 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
175 176 l = runhg(cmd, env).split()
176 177 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
177 178 l.pop()
178 179 if len(l) > 1: # tag found
179 180 version = l[-1]
180 181 if l[0].endswith('+'): # propagate the dirty status to the tag
181 182 version += '+'
182 183 elif len(l) == 1: # no tag found
183 184 cmd = [sys.executable, 'hg', 'parents', '--template',
184 185 '{latesttag}+{latesttagdistance}-']
185 186 version = runhg(cmd, env) + l[0]
186 187 if version.endswith('+'):
187 188 version += time.strftime('%Y%m%d')
188 189 elif os.path.exists('.hg_archival.txt'):
189 190 kw = dict([[t.strip() for t in l.split(':', 1)]
190 191 for l in open('.hg_archival.txt')])
191 192 if 'tag' in kw:
192 193 version = kw['tag']
193 194 elif 'latesttag' in kw:
194 195 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
195 196 else:
196 197 version = kw.get('node', '')[:12]
197 198
198 199 if version:
199 200 f = open("mercurial/__version__.py", "w")
200 201 f.write('# this file is autogenerated by setup.py\n')
201 202 f.write('version = "%s"\n' % version)
202 203 f.close()
203 204
204 205
205 206 try:
206 207 from mercurial import __version__
207 208 version = __version__.version
208 209 except ImportError:
209 210 version = 'unknown'
210 211
211 212 class hgbuild(build):
212 213 # Insert hgbuildmo first so that files in mercurial/locale/ are found
213 214 # when build_py is run next.
214 215 sub_commands = [('build_mo', None),
215 216
216 217 # We also need build_ext before build_py. Otherwise, when 2to3 is
217 218 # called (in build_py), it will not find osutil & friends,
218 219 # thinking that those modules are global and, consequently, making
219 220 # a mess, now that all module imports are global.
220 221
221 222 ('build_ext', build.has_ext_modules),
222 223 ] + build.sub_commands
223 224
224 225 class hgbuildmo(build):
225 226
226 227 description = "build translations (.mo files)"
227 228
228 229 def run(self):
229 230 if not find_executable('msgfmt'):
230 231 self.warn("could not find msgfmt executable, no translations "
231 232 "will be built")
232 233 return
233 234
234 235 podir = 'i18n'
235 236 if not os.path.isdir(podir):
236 237 self.warn("could not find %s/ directory" % podir)
237 238 return
238 239
239 240 join = os.path.join
240 241 for po in os.listdir(podir):
241 242 if not po.endswith('.po'):
242 243 continue
243 244 pofile = join(podir, po)
244 245 modir = join('locale', po[:-3], 'LC_MESSAGES')
245 246 mofile = join(modir, 'hg.mo')
246 247 mobuildfile = join('mercurial', mofile)
247 248 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
248 249 if sys.platform != 'sunos5':
249 250 # msgfmt on Solaris does not know about -c
250 251 cmd.append('-c')
251 252 self.mkpath(join('mercurial', modir))
252 253 self.make_file([pofile], mobuildfile, spawn, (cmd,))
253 254
254 255
255 256 class hgdist(Distribution):
256 257 pure = 0
257 258
258 259 global_options = Distribution.global_options + \
259 260 [('pure', None, "use pure (slow) Python "
260 261 "code instead of C extensions"),
261 262 ('c2to3', None, "(experimental!) convert "
262 263 "code with 2to3"),
263 264 ]
264 265
265 266 def has_ext_modules(self):
266 267 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
267 268 # too late for some cases
268 269 return not self.pure and Distribution.has_ext_modules(self)
269 270
270 271 class hgbuildext(build_ext):
271 272
272 273 def build_extension(self, ext):
273 274 try:
274 275 build_ext.build_extension(self, ext)
275 276 except CCompilerError:
276 277 if not getattr(ext, 'optional', False):
277 278 raise
278 279 log.warn("Failed to build optional extension '%s' (skipping)",
279 280 ext.name)
280 281
281 282 class hgbuildpy(build_py):
282 283 if convert2to3:
283 284 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
284 285 getfixers("hgfixes")))
285 286
286 287 def finalize_options(self):
287 288 build_py.finalize_options(self)
288 289
289 290 if self.distribution.pure:
290 291 if self.py_modules is None:
291 292 self.py_modules = []
292 293 for ext in self.distribution.ext_modules:
293 294 if ext.name.startswith("mercurial."):
294 295 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
295 296 self.distribution.ext_modules = []
296 297 else:
297 298 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
298 299 raise SystemExit('Python headers are required to build '
299 300 'Mercurial')
300 301
301 302 def find_modules(self):
302 303 modules = build_py.find_modules(self)
303 304 for module in modules:
304 305 if module[0] == "mercurial.pure":
305 306 if module[1] != "__init__":
306 307 yield ("mercurial", module[1], module[2])
307 308 else:
308 309 yield module
309 310
310 311 class buildhgextindex(Command):
311 312 description = 'generate prebuilt index of hgext (for frozen package)'
312 313 user_options = []
313 314 _indexfilename = 'hgext/__index__.py'
314 315
315 316 def initialize_options(self):
316 317 pass
317 318
318 319 def finalize_options(self):
319 320 pass
320 321
321 322 def run(self):
322 323 if os.path.exists(self._indexfilename):
323 324 os.unlink(self._indexfilename)
324 325
325 326 # here no extension enabled, disabled() lists up everything
326 327 code = ('import pprint; from mercurial import extensions; '
327 328 'pprint.pprint(extensions.disabled())')
328 329 out, err = runcmd([sys.executable, '-c', code], env)
329 330 if err:
330 331 raise DistutilsExecError(err)
331 332
332 333 f = open(self._indexfilename, 'w')
333 334 f.write('# this file is autogenerated by setup.py\n')
334 335 f.write('docs = ')
335 336 f.write(out)
336 337 f.close()
337 338
338 339 class buildhgexe(build_ext):
339 340 description = 'compile hg.exe from mercurial/exewrapper.c'
340 341
341 342 def build_extensions(self):
342 343 if os.name != 'nt':
343 344 return
344 345 objects = self.compiler.compile(['mercurial/exewrapper.c'],
345 346 output_dir=self.build_temp)
346 347 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
347 348 target = os.path.join(dir, 'hg')
348 349 self.compiler.link_executable(objects, target,
349 350 output_dir=self.build_temp)
350 351
351 352 class hginstallscripts(install_scripts):
352 353 '''
353 354 This is a specialization of install_scripts that replaces the @LIBDIR@ with
354 355 the configured directory for modules. If possible, the path is made relative
355 356 to the directory for scripts.
356 357 '''
357 358
358 359 def initialize_options(self):
359 360 install_scripts.initialize_options(self)
360 361
361 362 self.install_lib = None
362 363
363 364 def finalize_options(self):
364 365 install_scripts.finalize_options(self)
365 366 self.set_undefined_options('install',
366 367 ('install_lib', 'install_lib'))
367 368
368 369 def run(self):
369 370 install_scripts.run(self)
370 371
371 372 if (os.path.splitdrive(self.install_dir)[0] !=
372 373 os.path.splitdrive(self.install_lib)[0]):
373 374 # can't make relative paths from one drive to another, so use an
374 375 # absolute path instead
375 376 libdir = self.install_lib
376 377 else:
377 378 common = os.path.commonprefix((self.install_dir, self.install_lib))
378 379 rest = self.install_dir[len(common):]
379 380 uplevel = len([n for n in os.path.split(rest) if n])
380 381
381 382 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
382 383
383 384 for outfile in self.outfiles:
384 385 fp = open(outfile, 'rb')
385 386 data = fp.read()
386 387 fp.close()
387 388
388 389 # skip binary files
389 390 if b('\0') in data:
390 391 continue
391 392
392 393 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
393 394 fp = open(outfile, 'wb')
394 395 fp.write(data)
395 396 fp.close()
396 397
397 398 cmdclass = {'build': hgbuild,
398 399 'build_mo': hgbuildmo,
399 400 'build_ext': hgbuildext,
400 401 'build_py': hgbuildpy,
401 402 'build_hgextindex': buildhgextindex,
402 403 'install_scripts': hginstallscripts,
403 404 'build_hgexe': buildhgexe,
404 405 }
405 406
406 407 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
407 408 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
408 409 'hgext.largefiles']
409 410
410 411 pymodules = []
411 412
412 413 extmodules = [
413 414 Extension('mercurial.base85', ['mercurial/base85.c']),
414 415 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
415 416 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
416 417 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
417 418 Extension('mercurial.parsers', ['mercurial/parsers.c']),
418 419 ]
419 420
420 421 osutil_ldflags = []
421 422
422 423 if sys.platform == 'darwin':
423 424 osutil_ldflags += ['-framework', 'ApplicationServices']
424 425
425 426 # disable osutil.c under windows + python 2.4 (issue1364)
426 427 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
427 428 pymodules.append('mercurial.pure.osutil')
428 429 else:
429 430 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
430 431 extra_link_args=osutil_ldflags))
431 432
433 # the -mno-cygwin option has been deprecated for years
434 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
435
436 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
437 def __init__(self, *args, **kwargs):
438 Mingw32CCompiler.__init__(self, *args, **kwargs)
439 for i in 'compiler compiler_so linker_exe linker_so'.split():
440 try:
441 getattr(self, i).remove('-mno-cygwin')
442 except ValueError:
443 pass
444
445 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
446
432 447 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
433 448 # The inotify extension is only usable with Linux 2.6 kernels.
434 449 # You also need a reasonably recent C library.
435 450 # In any case, if it fails to build the error will be skipped ('optional').
436 451 cc = new_compiler()
437 452 if hasfunction(cc, 'inotify_add_watch'):
438 453 inotify = Extension('hgext.inotify.linux._inotify',
439 454 ['hgext/inotify/linux/_inotify.c'],
440 455 ['mercurial'])
441 456 inotify.optional = True
442 457 extmodules.append(inotify)
443 458 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
444 459
445 460 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
446 461 'help/*.txt']}
447 462
448 463 def ordinarypath(p):
449 464 return p and p[0] != '.' and p[-1] != '~'
450 465
451 466 for root in ('templates',):
452 467 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
453 468 curdir = curdir.split(os.sep, 1)[1]
454 469 dirs[:] = filter(ordinarypath, dirs)
455 470 for f in filter(ordinarypath, files):
456 471 f = os.path.join(curdir, f)
457 472 packagedata['mercurial'].append(f)
458 473
459 474 datafiles = []
460 475 setupversion = version
461 476 extra = {}
462 477
463 478 if py2exeloaded:
464 479 extra['console'] = [
465 480 {'script':'hg',
466 481 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
467 482 'product_version':version}]
468 483 # sub command of 'build' because 'py2exe' does not handle sub_commands
469 484 build.sub_commands.insert(0, ('build_hgextindex', None))
470 485
471 486 if os.name == 'nt':
472 487 # Windows binary file versions for exe/dll files must have the
473 488 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
474 489 setupversion = version.split('+', 1)[0]
475 490
476 491 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
477 492 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
478 493 # distutils.sysconfig
479 494 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
480 495 if version:
481 496 version = version[0]
482 497 xcode4 = (version.startswith('Xcode') and
483 498 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
484 499 else:
485 500 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
486 501 # installed, but instead with only command-line tools. Assume
487 502 # that only happens on >= Lion, thus no PPC support.
488 503 xcode4 = True
489 504
490 505 if xcode4:
491 506 os.environ['ARCHFLAGS'] = ''
492 507
493 508 setup(name='mercurial',
494 509 version=setupversion,
495 510 author='Matt Mackall',
496 511 author_email='mpm@selenic.com',
497 512 url='http://mercurial.selenic.com/',
498 513 description='Scalable distributed SCM',
499 514 license='GNU GPLv2+',
500 515 scripts=scripts,
501 516 packages=packages,
502 517 py_modules=pymodules,
503 518 ext_modules=extmodules,
504 519 data_files=datafiles,
505 520 package_data=packagedata,
506 521 cmdclass=cmdclass,
507 522 distclass=hgdist,
508 523 options=dict(py2exe=dict(packages=['hgext', 'email']),
509 524 bdist_mpkg=dict(zipdist=True,
510 525 license='COPYING',
511 526 readme='contrib/macosx/Readme.html',
512 527 welcome='contrib/macosx/Welcome.html')),
513 528 **extra)
General Comments 0
You need to be logged in to leave comments. Login now