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