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
246
# should be using something like _WIN32 or MS_WINDOWS, oh well, we can
247
# give it the right value.
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))
262
add_pyrex_extension('bzrlib._annotator_pyx')
263
add_pyrex_extension('bzrlib._bencode_pyx')
264
add_pyrex_extension('bzrlib._btree_serializer_pyx')
265
add_pyrex_extension('bzrlib._chunks_to_lines_pyx')
266
add_pyrex_extension('bzrlib._groupcompress_pyx',
267
extra_source=['bzrlib/diff-delta.c'])
268
add_pyrex_extension('bzrlib._knit_load_data_pyx')
269
add_pyrex_extension('bzrlib._known_graph_pyx')
270
add_pyrex_extension('bzrlib._rio_pyx')
225
ext_modules.append(Extension(module_name, [c_name], **kwargs))
228
add_pyrex_extension('bzrlib._dirstate_helpers_c')
229
add_pyrex_extension('bzrlib._knit_load_data_c')
271
230
if sys.platform == 'win32':
272
add_pyrex_extension('bzrlib._dirstate_helpers_pyx',
273
libraries=['Ws2_32'])
274
add_pyrex_extension('bzrlib._walkdirs_win32')
277
if have_pyrex and pyrex_version == '0.9.4.1':
278
# Pyrex 0.9.4.1 fails to compile this extension correctly
279
# The code it generates re-uses a "local" pointer and
280
# calls "PY_DECREF" after having set it to NULL. (It mixes PY_XDECREF
281
# which is NULL safe with PY_DECREF which is not.)
282
print 'Cannot build extension "bzrlib._dirstate_helpers_pyx" using'
283
print 'your version of pyrex "%s". Please upgrade your pyrex' % (
285
print 'install. For now, the non-compiled (python) version will'
286
print 'be used instead.'
288
add_pyrex_extension('bzrlib._dirstate_helpers_pyx')
289
add_pyrex_extension('bzrlib._readdir_pyx')
291
add_pyrex_extension('bzrlib._chk_map_pyx', libraries=[z_lib])
292
ext_modules.append(Extension('bzrlib._patiencediff_c',
293
['bzrlib/_patiencediff_c.c']))
231
# pyrex uses the macro WIN32 to detect the platform, even though it should
232
# be using something like _WIN32 or MS_WINDOWS, oh well, we can give it the
234
add_pyrex_extension('bzrlib._walkdirs_win32',
235
define_macros=[('WIN32', None)])
236
ext_modules.append(Extension('bzrlib._patiencediff_c', ['bzrlib/_patiencediff_c.c']))
296
239
if unavailable_files:
303
246
def get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
304
gui_targets, data_files):
305
248
packages.append('tbzrcommands')
307
250
# ModuleFinder can't handle runtime changes to __path__, but
308
251
# win32com uses them. Hook this in so win32com.shell is found.
309
252
import modulefinder
311
import cPickle as pickle
312
254
for p in win32com.__path__[1:]:
313
255
modulefinder.AddPackagePath("win32com", p)
314
256
for extra in ["win32com.shell"]:
327
269
sys.path.append(os.path.join(tbzr_root, "shellext", "python"))
329
271
packages.append("tbzrlib")
331
# collect up our icons.
333
ico_root = os.path.join(tbzr_root, 'tbzrlib', 'resources')
334
icos = [] # list of (path_root, relative_ico_path)
335
# First always bzr's icon and its in the root of the bzr tree.
336
icos.append(('', 'bzr.ico'))
337
for root, dirs, files in os.walk(ico_root):
338
icos.extend([(ico_root, os.path.join(root, f)[len(ico_root)+1:])
339
for f in files if f.endswith('.ico')])
340
# allocate an icon ID for each file and the full path to the ico
341
icon_resources = [(rid, os.path.join(ico_dir, ico_name))
342
for rid, (ico_dir, ico_name) in enumerate(icos)]
343
# create a string resource with the mapping. Might as well save the
344
# runtime some effort and write a pickle.
345
# Runtime expects unicode objects with forward-slash seps.
346
fse = sys.getfilesystemencoding()
347
map_items = [(f.replace('\\', '/').decode(fse), rid)
348
for rid, (_, f) in enumerate(icos)]
349
ico_map = dict(map_items)
350
# Create a new resource type of 'ICON_MAP', and use ID=1
351
other_resources = [ ("ICON_MAP", 1, pickle.dumps(ico_map))]
353
272
excludes.extend("""pywin pywin.dialogs pywin.dialogs.list
354
273
win32ui crawler.Crawler""".split())
356
# NOTE: We still create a DLL version of the Python implemented shell
357
# extension for testing purposes - but it is *not* registered by
358
# default - our C++ one is instead. To discourage people thinking
359
# this DLL is still necessary, its called 'tbzr_old.dll'
361
276
modules=["tbzr"],
362
277
create_exe = False, # we only want a .dll
363
dest_base = 'tbzr_old',
365
279
com_targets.append(tbzr)
367
281
# tbzrcache executables - a "console" version for debugging and a
368
282
# GUI version that is generally used.
369
283
tbzrcache = dict(
370
script = os.path.join(tbzr_root, "scripts", "tbzrcache.py"),
371
icon_resources = icon_resources,
372
other_resources = other_resources,
284
script = os.path.join(tbzr_root, "Scripts", "tbzrcache.py"),
285
icon_resources = [(0,'bzr.ico')],
374
287
console_targets.append(tbzrcache)
381
294
# ditto for the tbzrcommand tool
382
295
tbzrcommand = dict(
383
script = os.path.join(tbzr_root, "scripts", "tbzrcommand.py"),
296
script = os.path.join(tbzr_root, "Scripts", "tbzrcommand.py"),
384
297
icon_resources = [(0,'bzr.ico')],
386
299
console_targets.append(tbzrcommand)
388
301
tbzrcommandw["dest_base"]="tbzrcommandw"
389
302
gui_targets.append(tbzrcommandw)
391
# A utility to see python output from both C++ and Python based shell
393
tracer = dict(script=os.path.join(tbzr_root, "scripts", "tbzrtrace.py"))
306
script = os.path.join(tbzr_root, "Scripts", "tbzrtest.py"),
308
console_targets.append(tbzrtest)
310
# A utility to see python output from the shell extension - this will
311
# die when we get a c++ extension
312
# any .py file from pywin32's win32 lib will do (other than
313
# win32traceutil itself that is)
315
win32_lib_dir = os.path.dirname(winerror.__file__)
316
tracer = dict(script = os.path.join(win32_lib_dir, "win32traceutil.py"),
317
dest_base="tbzr_tracer")
394
318
console_targets.append(tracer)
396
# The C++ implemented shell extensions.
397
dist_dir = os.path.join(tbzr_root, "shellext", "cpp", "tbzrshellext",
399
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x86.dll')]))
400
data_files.append(('', [os.path.join(dist_dir, 'tbzrshellext_x64.dll')]))
403
321
def get_qbzr_py2exe_info(includes, excludes, packages):
404
322
# PyQt4 itself still escapes the plugin detection code for some reason...
567
480
for root, dirs, files in os.walk('bzrlib/plugins'):
568
481
if root == 'bzrlib/plugins':
569
482
plugins = set(dirs)
570
# We ship plugins as normal files on the file-system - however,
571
# the build process can cause *some* of these plugin files to end
572
# up in library.zip. Thus, we saw (eg) "plugins/svn/test" in
573
# library.zip, and then saw import errors related to that as the
574
# rest of the svn plugin wasn't. So we tell py2exe to leave the
575
# plugins out of the .zip file
576
excludes.extend(["bzrlib.plugins." + d for d in dirs])
579
if os.path.splitext(i)[1] not in [".py", ".pyd", ".dll", ".mo"]:
485
if os.path.splitext(i)[1] not in [".py", ".pyd", ".dll"]:
581
487
if i == '__init__.py' and root == 'bzrlib/plugins':
600
data_files = topics_files + plugins_files
602
507
if 'qbzr' in plugins:
603
508
get_qbzr_py2exe_info(includes, excludes, packages)
606
get_svn_py2exe_info(includes, excludes, packages)
608
510
if "TBZR" in os.environ:
609
511
# TORTOISE_OVERLAYS_MSI_WIN32 must be set to the location of the
610
512
# TortoiseOverlays MSI installer file. It is in the TSVN svn repo and
611
513
# can be downloaded from (username=guest, blank password):
612
# http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays
613
# look for: version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
614
# Ditto for TORTOISE_OVERLAYS_MSI_X64, pointing at *-x64.msi.
615
for needed in ('TORTOISE_OVERLAYS_MSI_WIN32',
616
'TORTOISE_OVERLAYS_MSI_X64'):
617
url = ('http://guest:@tortoisesvn.tigris.org/svn/tortoisesvn'
619
if not os.path.isfile(os.environ.get(needed, '<nofile>')):
621
"\nPlease set %s to the location of the relevant"
622
"\nTortoiseOverlays .msi installer file."
623
" The installers can be found at"
625
"\ncheck in the version-X.Y.Z/bin/ subdir" % (needed, url))
514
# http://tortoisesvn.tigris.org/svn/tortoisesvn/TortoiseOverlays/version-1.0.4/bin/TortoiseOverlays-1.0.4.11886-win32.msi
515
if not os.path.isfile(os.environ.get('TORTOISE_OVERLAYS_MSI_WIN32',
517
raise RuntimeError("Please set TORTOISE_OVERLAYS_MSI_WIN32 to the"
518
" location of the Win32 TortoiseOverlays .msi"
626
520
get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
627
gui_targets, data_files)
629
523
# print this warning to stderr as output is redirected, so it is seen
630
524
# at build time. Also to stdout so it appears in the log