]>
Commit | Line | Data |
---|---|---|
c368d904 RD |
1 | |
2 | import sys, os, string | |
3 | ||
4 | from distutils.msvccompiler import MSVCCompiler | |
22d08289 | 5 | from distutils.bcppcompiler import BCPPCompiler |
c368d904 RD |
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 | ||
a703a33a RD |
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 | ||
c368d904 RD |
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: | |
d1679124 | 75 | input_opt = "/Tc" + os.path.abspath(src) ### RPD |
c368d904 | 76 | elif ext in self._cpp_extensions: |
d1679124 | 77 | input_opt = "/Tp" + os.path.abspath(src) ### RPD |
c368d904 RD |
78 | elif ext in self._rc_extensions: |
79 | # compile .RC to .RES file | |
80 | input_opt = src | |
81 | output_opt = "/fo" + obj | |
82 | try: | |
d1679124 | 83 | self.spawn ([self.rc] + pp_opts + ### RPD changed this line |
c368d904 RD |
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 | ||
22d08289 RD |
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 | ||
c368d904 RD |
363 | |
364 | ||
365 | #---------------------------------------------------------------------- | |
366 | # Hack this module and class into the distutils... | |
367 | ||
368 | from distutils import ccompiler | |
369 | ||
743e91ff RD |
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 | ||
c368d904 RD |
379 | ccompiler.compiler_class['my_msvc'] = ('my_distutils', |
380 | 'MyMSVCCompiler', | |
381 | 'My MSVC derived class') | |
382 | ||
383 | ||
22d08289 RD |
384 | ccompiler.compiler_class['my_bcpp'] = ('my_distutils', |
385 | 'MyBCPPCompiler', | |
386 | 'My BCPP derived class') | |
387 | ||
c368d904 RD |
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 | ||
743e91ff RD |
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 | ||
c368d904 RD |
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 |