]> git.saurik.com Git - wxWidgets.git/blob - wxPython/my_distutils.py
1. don't emulate OFN_OVERWRITEPROMPT, use the real thing
[wxWidgets.git] / wxPython / my_distutils.py
1
2 import sys, os, string
3
4 from distutils.msvccompiler import MSVCCompiler
5 from distutils.bcppcompiler import BCPPCompiler
6
7 from distutils.errors import \
8 DistutilsExecError, DistutilsPlatformError, \
9 CompileError, LibError, LinkError
10 from distutils.ccompiler import \
11 CCompiler, gen_preprocess_options, gen_lib_options
12
13 #----------------------------------------------------------------------
14
15 class MyMSVCCompiler(MSVCCompiler):
16
17 ## def __init__ (self,
18 ## verbose=0,
19 ## dry_run=0,
20 ## force=0):
21 ## MSVCCompiler.__init__(self, verbose, dry_run, force)
22
23 ## self.compile_options = [ '/nologo',
24 ## '/Ox',
25 ## '/MD',
26 ## '/W3',
27 ## '/GX',
28 ## ]
29 ## self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
30 ## '/Z7', '/D_DEBUG']
31
32
33
34
35 ##------------------------------------------------------------
36 ## Override the entire compile method just to add flags to the
37 ## RC command. There should be an easier way to do this from
38 ## distutils directly or in a derived class...
39 ##------------------------------------------------------------
40
41 def compile (self,
42 sources,
43 output_dir=None,
44 macros=None,
45 include_dirs=None,
46 debug=0,
47 extra_preargs=None,
48 extra_postargs=None):
49
50 (output_dir, macros, include_dirs) = \
51 self._fix_compile_args (output_dir, macros, include_dirs)
52 (objects, skip_sources) = self._prep_compile (sources, output_dir)
53
54 if extra_postargs is None:
55 extra_postargs = []
56
57 pp_opts = gen_preprocess_options (macros, include_dirs)
58 compile_opts = extra_preargs or []
59 compile_opts.append ('/c')
60 if debug:
61 compile_opts.extend (self.compile_options_debug)
62 else:
63 compile_opts.extend (self.compile_options)
64
65 for i in range (len (sources)):
66 src = sources[i] ; obj = objects[i]
67 ext = (os.path.splitext (src))[1]
68
69 if skip_sources[src]:
70 self.announce ("skipping %s (%s up-to-date)" % (src, obj))
71 else:
72 self.mkpath (os.path.dirname (obj))
73
74 if ext in self._c_extensions:
75 input_opt = "/Tc" + os.path.abspath(src) ### RPD
76 elif ext in self._cpp_extensions:
77 input_opt = "/Tp" + os.path.abspath(src) ### RPD
78 elif ext in self._rc_extensions:
79 # compile .RC to .RES file
80 input_opt = src
81 output_opt = "/fo" + obj
82 try:
83 self.spawn ([self.rc] + pp_opts + ### RPD changed this line
84 [output_opt] + [input_opt])
85 except DistutilsExecError, msg:
86 raise CompileError, msg
87 continue
88 elif ext in self._mc_extensions:
89
90 # Compile .MC to .RC file to .RES file.
91 # * '-h dir' specifies the directory for the
92 # generated include file
93 # * '-r dir' specifies the target directory of the
94 # generated RC file and the binary message resource
95 # it includes
96 #
97 # For now (since there are no options to change this),
98 # we use the source-directory for the include file and
99 # the build directory for the RC file and message
100 # resources. This works at least for win32all.
101
102 h_dir = os.path.dirname (src)
103 rc_dir = os.path.dirname (obj)
104 try:
105 # first compile .MC to .RC and .H file
106 self.spawn ([self.mc] +
107 ['-h', h_dir, '-r', rc_dir] + [src])
108 base, _ = os.path.splitext (os.path.basename (src))
109 rc_file = os.path.join (rc_dir, base + '.rc')
110 # then compile .RC to .RES file
111 self.spawn ([self.rc] +
112 ["/fo" + obj] + [rc_file])
113
114 except DistutilsExecError, msg:
115 raise CompileError, msg
116 continue
117 else:
118 # how to handle this file?
119 raise CompileError (
120 "Don't know how to compile %s to %s" % \
121 (src, obj))
122
123 output_opt = "/Fo" + obj
124 try:
125 self.spawn ([self.cc] + compile_opts + pp_opts +
126 [input_opt, output_opt] +
127 extra_postargs)
128 except DistutilsExecError, msg:
129 raise CompileError, msg
130
131 return objects
132
133 # compile ()
134
135
136
137 from distutils.file_util import write_file
138 class MyBCPPCompiler(BCPPCompiler):
139
140 ##------------------------------------------------------------
141 ## Override the entire compile method just to add flags to the
142 ## RC command. There should be an easier way to do this from
143 ## distutils directly or in a derived class...
144 ##------------------------------------------------------------
145
146 def compile (self,
147 sources,
148 output_dir=None,
149 macros=None,
150 include_dirs=None,
151 debug=0,
152 extra_preargs=None,
153 extra_postargs=None):
154
155 (output_dir, macros, include_dirs) = \
156 self._fix_compile_args (output_dir, macros, include_dirs)
157 (objects, skip_sources) = self._prep_compile (sources, output_dir)
158
159 if extra_postargs is None:
160 extra_postargs = []
161
162 pp_opts = gen_preprocess_options (macros, include_dirs)
163 compile_opts = extra_preargs or []
164 compile_opts.append ('-c')
165 if debug:
166 compile_opts.extend (self.compile_options_debug)
167 else:
168 compile_opts.extend (self.compile_options)
169
170 for i in range (len (sources)):
171 src = sources[i] ; obj = objects[i]
172 ext = (os.path.splitext (src))[1]
173
174 if skip_sources[src]:
175 self.announce ("skipping %s (%s up-to-date)" % (src, obj))
176 else:
177 src = os.path.normpath(src)
178 obj = os.path.normpath(obj)
179 self.mkpath(os.path.dirname(obj))
180
181 if ext == '.res':
182 # This is already a binary file -- skip it.
183 continue # the 'for' loop
184 if ext == '.rc':
185 # This needs to be compiled to a .res file -- do it now.
186 try:
187 self.spawn (["brcc32"] + pp_opts + ["-fo"] +
188 [obj] + [src]) ### RPD changed this lines only
189 except DistutilsExecError, msg:
190 raise CompileError, msg
191 continue # the 'for' loop
192
193 # The next two are both for the real compiler.
194 if ext in self._c_extensions:
195 input_opt = ""
196 elif ext in self._cpp_extensions:
197 input_opt = "-P"
198 else:
199 # Unknown file type -- no extra options. The compiler
200 # will probably fail, but let it just in case this is a
201 # file the compiler recognizes even if we don't.
202 input_opt = ""
203
204 output_opt = "-o" + obj
205
206 # Compiler command line syntax is: "bcc32 [options] file(s)".
207 # Note that the source file names must appear at the end of
208 # the command line.
209 try:
210 self.spawn ([self.cc] + compile_opts + pp_opts +
211 [input_opt, output_opt] +
212 extra_postargs + [src])
213 except DistutilsExecError, msg:
214 raise CompileError, msg
215
216 return objects
217
218 # compile ()
219
220 ####################################################################
221 # Now we need to replace cw32mt library used by default by distutils
222 # with cw32mti library as in wxWindows DLL make file
223 # Othervise we obtain Windows "Core dump" ;-).
224 #
225 # Evgeny A Cherkashin <eugeneai@icc.ru>
226 #
227 ####################################################################
228
229 def link (self,
230 target_desc,
231 objects,
232 output_filename,
233 output_dir=None,
234 libraries=None,
235 library_dirs=None,
236 runtime_library_dirs=None,
237 export_symbols=None,
238 debug=0,
239 extra_preargs=None,
240 extra_postargs=None,
241 build_temp=None):
242
243 # XXX this ignores 'build_temp'! should follow the lead of
244 # msvccompiler.py
245
246 (objects, output_dir) = self._fix_object_args (objects, output_dir)
247 (libraries, library_dirs, runtime_library_dirs) = \
248 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
249
250 if runtime_library_dirs:
251 self.warn ("I don't know what to do with 'runtime_library_dirs': "
252 + str (runtime_library_dirs))
253
254 if output_dir is not None:
255 output_filename = os.path.join (output_dir, output_filename)
256
257 if self._need_link (objects, output_filename):
258
259 # Figure out linker args based on type of target.
260 if target_desc == CCompiler.EXECUTABLE:
261 startup_obj = 'c0w32'
262 if debug:
263 ld_args = self.ldflags_exe_debug[:]
264 else:
265 ld_args = self.ldflags_exe[:]
266 else:
267 startup_obj = 'c0d32'
268 if debug:
269 ld_args = self.ldflags_shared_debug[:]
270 else:
271 ld_args = self.ldflags_shared[:]
272
273
274 # Create a temporary exports file for use by the linker
275 if export_symbols is None:
276 def_file = ''
277 else:
278 head, tail = os.path.split (output_filename)
279 modname, ext = os.path.splitext (tail)
280 temp_dir = os.path.dirname(objects[0]) # preserve tree structure
281 def_file = os.path.join (temp_dir, '%s.def' % modname)
282 contents = ['EXPORTS']
283 for sym in (export_symbols or []):
284 contents.append(' %s=_%s' % (sym, sym))
285 self.execute(write_file, (def_file, contents),
286 "writing %s" % def_file)
287
288 # Borland C++ has problems with '/' in paths
289 objects2 = map(os.path.normpath, objects)
290 # split objects in .obj and .res files
291 # Borland C++ needs them at different positions in the command line
292 objects = [startup_obj]
293 resources = []
294 for file in objects2:
295 (base, ext) = os.path.splitext(os.path.normcase(file))
296 if ext == '.res':
297 resources.append(file)
298 else:
299 objects.append(file)
300
301
302 for l in library_dirs:
303 ld_args.append("/L%s" % os.path.normpath(l))
304 ld_args.append("/L.") # we sometimes use relative paths
305
306 # list of object files
307 ld_args.extend(objects)
308
309 # XXX the command-line syntax for Borland C++ is a bit wonky;
310 # certain filenames are jammed together in one big string, but
311 # comma-delimited. This doesn't mesh too well with the
312 # Unix-centric attitude (with a DOS/Windows quoting hack) of
313 # 'spawn()', so constructing the argument list is a bit
314 # awkward. Note that doing the obvious thing and jamming all
315 # the filenames and commas into one argument would be wrong,
316 # because 'spawn()' would quote any filenames with spaces in
317 # them. Arghghh!. Apparently it works fine as coded...
318
319 # name of dll/exe file
320 ld_args.extend([',',output_filename])
321 # no map file and start libraries
322 ld_args.append(',,')
323
324 for lib in libraries:
325 # see if we find it and if there is a bcpp specific lib
326 # (xxx_bcpp.lib)
327 libfile = self.find_library_file(library_dirs, lib, debug)
328 if libfile is None:
329 ld_args.append(lib)
330 # probably a BCPP internal library -- don't warn
331 # self.warn('library %s not found.' % lib)
332 else:
333 # full name which prefers bcpp_xxx.lib over xxx.lib
334 ld_args.append(libfile)
335
336 # some default libraries
337 ld_args.append ('import32')
338 ld_args.append ('cw32mti') ### mt->mti (as in wx2)
339
340 # def file for export symbols
341 ld_args.extend([',',def_file])
342 # add resource files
343 ld_args.append(',')
344 ld_args.extend(resources)
345
346
347 if extra_preargs:
348 ld_args[:0] = extra_preargs
349 if extra_postargs:
350 ld_args.extend(extra_postargs)
351
352 self.mkpath (os.path.dirname (output_filename))
353 try:
354 self.spawn ([self.linker] + ld_args)
355 except DistutilsExecError, msg:
356 raise LinkError, msg
357
358 else:
359 self.announce ("skipping %s (up-to-date)" % output_filename)
360
361 # link ()
362
363
364
365 #----------------------------------------------------------------------
366 # Hack this module and class into the distutils...
367
368 from distutils import ccompiler
369
370 if hasattr(ccompiler, "default_compiler"):
371 ccompiler.default_compiler['nt'] = 'my_msvc'
372 elif hasattr(ccompiler, "_default_compilers"):
373 lst = list(ccompiler._default_compilers)
374 lst.remove( ('nt', 'msvc') )
375 lst.append( ('nt', 'my_msvc') )
376 ccompiler._default_compilers = tuple(lst)
377
378
379 ccompiler.compiler_class['my_msvc'] = ('my_distutils',
380 'MyMSVCCompiler',
381 'My MSVC derived class')
382
383
384 ccompiler.compiler_class['my_bcpp'] = ('my_distutils',
385 'MyBCPPCompiler',
386 'My BCPP derived class')
387
388 # make it look like it is part of the package...
389 import my_distutils
390 sys.modules['distutils.my_distutils'] = my_distutils
391
392
393 #----------------------------------------------------------------------
394 # More hacking... Distutils in Python 2.1 changed the strip_dir flag
395 # passed to object_filenames to true, which causes problems for us since
396 # there are a few duplicate source/object names between some of the
397 # extensions in wxPython. This hack replaces the CCompiler._prep_compile
398 # method with this one.
399
400 from distutils.dep_util import newer_pairwise
401
402 def _prep_compile (self, sources, output_dir):
403 """Determine the list of object files corresponding to 'sources',
404 and figure out which ones really need to be recompiled. Return a
405 list of all object files and a dictionary telling which source
406 files can be skipped.
407 """
408 # Get the list of expected output (object) files
409 objects = self.object_filenames (sources,
410 strip_dir=0,
411 output_dir=output_dir)
412
413 if self.force:
414 skip_source = {} # rebuild everything
415 for source in sources:
416 skip_source[source] = 0
417 else:
418 # Figure out which source files we have to recompile according
419 # to a simplistic check -- we just compare the source and
420 # object file, no deep dependency checking involving header
421 # files.
422 skip_source = {} # rebuild everything
423 for source in sources: # no wait, rebuild nothing
424 skip_source[source] = 1
425
426 (n_sources, n_objects) = newer_pairwise (sources, objects)
427 for source in n_sources: # no really, only rebuild what's
428 skip_source[source] = 0 # out-of-date
429
430 return (objects, skip_source)
431
432 # _prep_compile ()
433
434 CCompiler._prep_compile = _prep_compile
435
436
437
438
439 #----------------------------------------------------------------------
440 # Run SWIG the way I want it done
441
442 def run_swig(files, dir, gendir, package, USE_SWIG, force, swig_args, swig_deps=[]):
443 from distutils.file_util import copy_file
444 from distutils.dep_util import newer
445 from distutils.spawn import spawn
446
447 sources = []
448
449 for file in files:
450 basefile = os.path.splitext(file)[0]
451 i_file = os.path.join(dir, file)
452 py_file = os.path.join(dir, gendir, basefile+'.py')
453 cpp_file = os.path.join(dir, gendir, basefile+'.cpp')
454
455 sources.append(cpp_file)
456
457 if USE_SWIG:
458 for dep in swig_deps:
459 if newer(dep, py_file) or newer(dep, cpp_file):
460 force = 1
461 break
462
463 if force or newer(i_file, py_file) or newer(i_file, cpp_file):
464 # we need forward slashes here even on win32
465 cpp_file = string.join(string.split(cpp_file, '\\'), '/')
466 i_file = string.join(string.split(i_file, '\\'), '/')
467
468 cmd = ['swig'] + swig_args + ['-I'+dir, '-c', '-o', cpp_file, i_file]
469 spawn(cmd, verbose=1)
470
471 # copy the generated python file to the package directory
472 copy_file(py_file, package, update=not force, verbose=0)
473
474
475 return sources
476
477
478
479 #----------------------------------------------------------------------
480 # Update local copies of wxWindows contrib files
481
482
483 def contrib_copy_tree(src, dest, verbose=0):
484 from distutils.dir_util import mkpath, copy_tree
485
486 mkpath(dest, verbose=verbose)
487 copy_tree(src, dest, update=1, verbose=verbose)
488