176
175
from distutils.command.build_ext import build_ext
178
177
have_pyrex = True
179
from Pyrex.Compiler.Version import version as pyrex_version
182
180
class build_ext_if_possible(build_ext):
184
user_options = build_ext.user_options + [
185
('allow-python-fallback', None,
186
"When an extension cannot be built, allow falling"
187
" back to the pure-python implementation.")
190
def initialize_options(self):
191
build_ext.initialize_options(self)
192
self.allow_python_fallback = False
196
184
build_ext.run(self)
197
185
except DistutilsPlatformError, e:
198
if not self.allow_python_fallback:
199
log.warn('\n Cannot build extensions.\n'
200
' Use "build_ext --allow-python-fallback" to use'
201
' slower python implementations instead.\n')
204
log.warn('\n Extensions cannot be built.\n'
205
' Using the slower Python implementations instead.\n')
187
log.warn('Extensions cannot be built, '
188
'will use the Python versions instead')
207
190
def build_extension(self, ext):
209
192
build_ext.build_extension(self, ext)
210
193
except CCompilerError:
211
if not self.allow_python_fallback:
212
log.warn('\n Cannot build extension "%s".\n'
213
' Use "build_ext --allow-python-fallback" to use'
214
' slower python implementations instead.\n'
217
log.warn('\n Building of "%s" extension failed.\n'
218
' Using the slower Python implementation instead.'
194
log.warn('Building of "%s" extension failed, '
195
'will use the Python version instead' % (ext.name,))
222
198
# Override the build_ext if we have Pyrex available
240
216
path = module_name.replace('.', '/')
241
217
pyrex_name = path + '.pyx'
242
218
c_name = path + '.c'
244
if sys.platform == 'win32':
245
# pyrex uses the macro WIN32 to detect the platform, even though it should
246
# be using something like _WIN32 or MS_WINDOWS, oh well, we can give it the
248
define_macros.append(('WIN32', None))
250
source = [pyrex_name]
220
ext_modules.append(Extension(module_name, [pyrex_name], **kwargs))
252
222
if not os.path.isfile(c_name):
253
223
unavailable_files.append(c_name)
257
source.extend(extra_source)
258
ext_modules.append(Extension(module_name, source,
259
define_macros=define_macros, libraries=libraries))
225
ext_modules.append(Extension(module_name, [c_name], **kwargs))
262
228
add_pyrex_extension('bzrlib._btree_serializer_c')
263
add_pyrex_extension('bzrlib._groupcompress_pyx',
264
extra_source=['bzrlib/diff-delta.c'])
265
add_pyrex_extension('bzrlib._chunks_to_lines_pyx')
229
add_pyrex_extension('bzrlib._dirstate_helpers_c')
266
230
add_pyrex_extension('bzrlib._knit_load_data_c')
267
add_pyrex_extension('bzrlib._chk_map_pyx', libraries=['z'])
231
add_pyrex_extension('bzrlib._readdir_pyx')
268
232
if sys.platform == 'win32':
269
add_pyrex_extension('bzrlib._dirstate_helpers_c',
270
libraries=['Ws2_32'])
271
add_pyrex_extension('bzrlib._walkdirs_win32')
273
if have_pyrex and pyrex_version == '0.9.4.1':
274
# Pyrex 0.9.4.1 fails to compile this extension correctly
275
# The code it generates re-uses a "local" pointer and
276
# calls "PY_DECREF" after having set it to NULL. (It mixes PY_XDECREF
277
# which is NULL safe with PY_DECREF which is not.)
278
print 'Cannot build extension "bzrlib._dirstate_helpers_c" using'
279
print 'your version of pyrex "%s". Please upgrade your pyrex' % (
281
print 'install. For now, the non-compiled (python) version will'
282
print 'be used instead.'
284
add_pyrex_extension('bzrlib._dirstate_helpers_c')
285
add_pyrex_extension('bzrlib._readdir_pyx')
233
# pyrex uses the macro WIN32 to detect the platform, even though it should
234
# be using something like _WIN32 or MS_WINDOWS, oh well, we can give it the
236
add_pyrex_extension('bzrlib._walkdirs_win32',
237
define_macros=[('WIN32', None)])
286
238
ext_modules.append(Extension('bzrlib._patiencediff_c', ['bzrlib/_patiencediff_c.c']))
346
298
excludes.extend("""pywin pywin.dialogs pywin.dialogs.list
347
299
win32ui crawler.Crawler""".split())
349
# NOTE: We still create a DLL version of the Python implemented shell
350
# extension for testing purposes - but it is *not* registered by
351
# default - our C++ one is instead. To discourage people thinking
352
# this DLL is still necessary, its called 'tbzr_old.dll'
354
302
modules=["tbzr"],
355
303
create_exe = False, # we only want a .dll
356
dest_base = 'tbzr_old',
358
305
com_targets.append(tbzr)
360
307
# tbzrcache executables - a "console" version for debugging and a
361
308
# GUI version that is generally used.
362
309
tbzrcache = dict(
363
script = os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
310
script = os.path.join(tbzr_root, "Scripts", "tbzrcache.py"),
364
311
icon_resources = icon_resources,
365
312
other_resources = other_resources,
374
321
# ditto for the tbzrcommand tool
375
322
tbzrcommand = dict(
376
script = os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
323
script = os.path.join(tbzr_root, "Scripts", "tbzrcommand.py"),
377
324
icon_resources = [(0,'bzr.ico')],
379
326
console_targets.append(tbzrcommand)
381
328
tbzrcommandw["dest_base"]="tbzrcommandw"
382
329
gui_targets.append(tbzrcommandw)
384
# A utility to see python output from both C++ and Python based shell
386
tracer = dict(script=os.path.join(tbzr_root, "scripts", "tbzrtrace.py"))
333
script = os.path.join(tbzr_root, "Scripts", "tbzrtest.py"),
335
console_targets.append(tbzrtest)
337
# A utility to see python output from the shell extension - this will
338
# die when we get a c++ extension
339
# any .py file from pywin32's win32 lib will do (other than
340
# win32traceutil itself that is)
342
win32_lib_dir = os.path.dirname(winerror.__file__)
343
tracer = dict(script = os.path.join(win32_lib_dir, "win32traceutil.py"),
344
dest_base="tbzr_tracer")
387
345
console_targets.append(tracer)
389
# The C++ implemented shell extensions.
390
dist_dir = os.path.join(tbzr_root, "shellext", "cpp", "tbzrshellext",
392
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x86.dll')]))
393
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x64.dll')]))
396
348
def get_qbzr_py2exe_info(includes, excludes, packages):
397
349
# PyQt4 itself still escapes the plugin detection code for some reason...
560
507
for root, dirs, files in os.walk('bzrlib/plugins'):
561
508
if root == 'bzrlib/plugins':
562
509
plugins = set(dirs)
563
# We ship plugins as normal files on the file-system - however,
564
# the build process can cause *some* of these plugin files to end
565
# up in library.zip. Thus, we saw (eg) "plugins/svn/test" in
566
# library.zip, and then saw import errors related to that as the
567
# rest of the svn plugin wasn't. So we tell py2exe to leave the
568
# plugins out of the .zip file
569
excludes.extend(["bzrlib.plugins." + d for d in dirs])
572
if os.path.splitext(i)[1] not in [".py", ".pyd", ".dll", ".mo"]:
512
if os.path.splitext(i)[1] not in [".py", ".pyd", ".dll"]:
574
514
if i == '__init__.py' and root == 'bzrlib/plugins':
593
data_files = topics_files + plugins_files
595
534
if 'qbzr' in plugins:
596
535
get_qbzr_py2exe_info(includes, excludes, packages)
599
get_svn_py2exe_info(includes, excludes, packages)
601
537
if "TBZR" in os.environ:
602
538
# TORTOISE_OVERLAYS_MSI_WIN32 must be set to the location of the
603
539
# TortoiseOverlays MSI installer file. It is in the TSVN svn repo and
604
540
# can be downloaded from (username=guest, blank password):
605
541
# http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays/version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
606
# Ditto for TORTOISE_OVERLAYS_MSI_X64, pointing at *-x64.msi.
607
for needed in ('TORTOISE_OVERLAYS_MSI_WIN32',
608
'TORTOISE_OVERLAYS_MSI_X64'):
609
if not os.path.isfile(os.environ.get(needed, '<nofile>')):
610
raise RuntimeError("Please set %s to the"
611
" location of the relevant TortoiseOverlays"
612
" .msi installer file" % needed)
542
if not os.path.isfile(os.environ.get('TORTOISE_OVERLAYS_MSI_WIN32',
544
raise RuntimeError("Please set TORTOISE_OVERLAYS_MSI_WIN32 to the"
545
" location of the Win32 TortoiseOverlays .msi"
613
547
get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
614
gui_targets, data_files)
616
550
# print this warning to stderr as output is redirected, so it is seen
617
551
# at build time. Also to stdout so it appears in the log