import sys, os, string
from distutils.msvccompiler import MSVCCompiler
+from distutils.bcppcompiler import BCPPCompiler
from distutils.errors import \
DistutilsExecError, DistutilsPlatformError, \
self.mkpath (os.path.dirname (obj))
if ext in self._c_extensions:
- input_opt = "/Tc" + os.path.abspath(src)
+ input_opt = "/Tc" + os.path.abspath(src) ### RPD
elif ext in self._cpp_extensions:
- input_opt = "/Tp" + os.path.abspath(src)
+ input_opt = "/Tp" + os.path.abspath(src) ### RPD
elif ext in self._rc_extensions:
# compile .RC to .RES file
input_opt = src
output_opt = "/fo" + obj
try:
- self.spawn ([self.rc] + pp_opts + ### RPD changed this line only
+ self.spawn ([self.rc] + pp_opts + ### RPD changed this line
[output_opt] + [input_opt])
except DistutilsExecError, msg:
raise CompileError, msg
+from distutils.file_util import write_file
+class MyBCPPCompiler(BCPPCompiler):
+
##------------------------------------------------------------
- ## Now override the link() method to change where the import
- ## library is placed. Hopefully distutils will be updated
- ## someday to make this configurable...
+ ## Override the entire compile method just to add flags to the
+ ## RC command. There should be an easier way to do this from
+ ## distutils directly or in a derived class...
##------------------------------------------------------------
+ def compile (self,
+ sources,
+ output_dir=None,
+ macros=None,
+ include_dirs=None,
+ debug=0,
+ extra_preargs=None,
+ extra_postargs=None):
+
+ (output_dir, macros, include_dirs) = \
+ self._fix_compile_args (output_dir, macros, include_dirs)
+ (objects, skip_sources) = self._prep_compile (sources, output_dir)
+
+ if extra_postargs is None:
+ extra_postargs = []
+
+ pp_opts = gen_preprocess_options (macros, include_dirs)
+ compile_opts = extra_preargs or []
+ compile_opts.append ('-c')
+ if debug:
+ compile_opts.extend (self.compile_options_debug)
+ else:
+ compile_opts.extend (self.compile_options)
+
+ for i in range (len (sources)):
+ src = sources[i] ; obj = objects[i]
+ ext = (os.path.splitext (src))[1]
+
+ if skip_sources[src]:
+ self.announce ("skipping %s (%s up-to-date)" % (src, obj))
+ else:
+ src = os.path.normpath(src)
+ obj = os.path.normpath(obj)
+ self.mkpath(os.path.dirname(obj))
+
+ if ext == '.res':
+ # This is already a binary file -- skip it.
+ continue # the 'for' loop
+ if ext == '.rc':
+ # This needs to be compiled to a .res file -- do it now.
+ try:
+ self.spawn (["brcc32"] + pp_opts + ["-fo"] +
+ [obj] + [src]) ### RPD changed this lines only
+ except DistutilsExecError, msg:
+ raise CompileError, msg
+ continue # the 'for' loop
+
+ # The next two are both for the real compiler.
+ if ext in self._c_extensions:
+ input_opt = ""
+ elif ext in self._cpp_extensions:
+ input_opt = "-P"
+ else:
+ # Unknown file type -- no extra options. The compiler
+ # will probably fail, but let it just in case this is a
+ # file the compiler recognizes even if we don't.
+ input_opt = ""
+
+ output_opt = "-o" + obj
+
+ # Compiler command line syntax is: "bcc32 [options] file(s)".
+ # Note that the source file names must appear at the end of
+ # the command line.
+ try:
+ self.spawn ([self.cc] + compile_opts + pp_opts +
+ [input_opt, output_opt] +
+ extra_postargs + [src])
+ except DistutilsExecError, msg:
+ raise CompileError, msg
+
+ return objects
+
+ # compile ()
+
+ ####################################################################
+ # Now we need to replace cw32mt library used by default by distutils
+ # with cw32mti library as in wxWindows DLL make file
+ # Othervise we obtain Windows "Core dump" ;-).
+ #
+ # Evgeny A Cherkashin <eugeneai@icc.ru>
+ #
+ ####################################################################
+
def link (self,
target_desc,
objects,
extra_postargs=None,
build_temp=None):
+ # XXX this ignores 'build_temp'! should follow the lead of
+ # msvccompiler.py
+
(objects, output_dir) = self._fix_object_args (objects, output_dir)
(libraries, library_dirs, runtime_library_dirs) = \
self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
self.warn ("I don't know what to do with 'runtime_library_dirs': "
+ str (runtime_library_dirs))
- lib_opts = gen_lib_options (self,
- library_dirs, runtime_library_dirs,
- libraries)
if output_dir is not None:
output_filename = os.path.join (output_dir, output_filename)
if self._need_link (objects, output_filename):
+ # Figure out linker args based on type of target.
if target_desc == CCompiler.EXECUTABLE:
+ startup_obj = 'c0w32'
if debug:
- ldflags = self.ldflags_shared_debug[1:]
+ ld_args = self.ldflags_exe_debug[:]
else:
- ldflags = self.ldflags_shared[1:]
+ ld_args = self.ldflags_exe[:]
else:
+ startup_obj = 'c0d32'
if debug:
- ldflags = self.ldflags_shared_debug
+ ld_args = self.ldflags_shared_debug[:]
else:
- ldflags = self.ldflags_shared
+ ld_args = self.ldflags_shared[:]
- export_opts = []
- for sym in (export_symbols or []):
- export_opts.append("/EXPORT:" + sym)
- ld_args = (ldflags + lib_opts + export_opts +
- objects + ['/OUT:' + output_filename])
-
- # The MSVC linker generates .lib and .exp files, which cannot be
- # suppressed by any linker switches. The .lib files may even be
- # needed! Make sure they are generated in the temporary build
- # directory. Since they have different names for debug and release
- # builds, they can go into the same directory.
- if export_symbols is not None:
- (dll_name, dll_ext) = os.path.splitext(
- os.path.basename(output_filename))
+ # Create a temporary exports file for use by the linker
+ if export_symbols is None:
+ def_file = ''
+ else:
+ head, tail = os.path.split (output_filename)
+ modname, ext = os.path.splitext (tail)
+ temp_dir = os.path.dirname(objects[0]) # preserve tree structure
+ def_file = os.path.join (temp_dir, '%s.def' % modname)
+ contents = ['EXPORTS']
+ for sym in (export_symbols or []):
+ contents.append(' %s=_%s' % (sym, sym))
+ self.execute(write_file, (def_file, contents),
+ "writing %s" % def_file)
+
+ # Borland C++ has problems with '/' in paths
+ objects2 = map(os.path.normpath, objects)
+ # split objects in .obj and .res files
+ # Borland C++ needs them at different positions in the command line
+ objects = [startup_obj]
+ resources = []
+ for file in objects2:
+ (base, ext) = os.path.splitext(os.path.normcase(file))
+ if ext == '.res':
+ resources.append(file)
+ else:
+ objects.append(file)
+
+
+ for l in library_dirs:
+ ld_args.append("/L%s" % os.path.normpath(l))
+ ld_args.append("/L.") # we sometimes use relative paths
+
+ # list of object files
+ ld_args.extend(objects)
+
+ # XXX the command-line syntax for Borland C++ is a bit wonky;
+ # certain filenames are jammed together in one big string, but
+ # comma-delimited. This doesn't mesh too well with the
+ # Unix-centric attitude (with a DOS/Windows quoting hack) of
+ # 'spawn()', so constructing the argument list is a bit
+ # awkward. Note that doing the obvious thing and jamming all
+ # the filenames and commas into one argument would be wrong,
+ # because 'spawn()' would quote any filenames with spaces in
+ # them. Arghghh!. Apparently it works fine as coded...
+
+ # name of dll/exe file
+ ld_args.extend([',',output_filename])
+ # no map file and start libraries
+ ld_args.append(',,')
+
+ for lib in libraries:
+ # see if we find it and if there is a bcpp specific lib
+ # (xxx_bcpp.lib)
+ libfile = self.find_library_file(library_dirs, lib, debug)
+ if libfile is None:
+ ld_args.append(lib)
+ # probably a BCPP internal library -- don't warn
+ # self.warn('library %s not found.' % lib)
+ else:
+ # full name which prefers bcpp_xxx.lib over xxx.lib
+ ld_args.append(libfile)
- ## The old code
- ##implib_file = os.path.join(
- ## os.path.dirname(objects[0]),
- ## self.library_filename(dll_name))
+ # some default libraries
+ ld_args.append ('import32')
+ ld_args.append ('cw32mti') ### mt->mti (as in wx2)
- ## The new
- implib_file = os.path.join('build', 'ilib',
- self.library_filename(dll_name))
- self.mkpath(os.path.dirname(implib_file))
+ # def file for export symbols
+ ld_args.extend([',',def_file])
+ # add resource files
+ ld_args.append(',')
+ ld_args.extend(resources)
- ld_args.append ('/IMPLIB:' + implib_file)
if extra_preargs:
ld_args[:0] = extra_preargs
from distutils import ccompiler
-ccompiler.default_compiler['nt'] = 'my_msvc'
+if hasattr(ccompiler, "default_compiler"):
+ ccompiler.default_compiler['nt'] = 'my_msvc'
+elif hasattr(ccompiler, "_default_compilers"):
+ lst = list(ccompiler._default_compilers)
+ lst.remove( ('nt', 'msvc') )
+ lst.append( ('nt', 'my_msvc') )
+ ccompiler._default_compilers = tuple(lst)
+
+
ccompiler.compiler_class['my_msvc'] = ('my_distutils',
'MyMSVCCompiler',
'My MSVC derived class')
+ccompiler.compiler_class['my_bcpp'] = ('my_distutils',
+ 'MyBCPPCompiler',
+ 'My BCPP derived class')
+
# make it look like it is part of the package...
import my_distutils
sys.modules['distutils.my_distutils'] = my_distutils
+#----------------------------------------------------------------------
+# More hacking... Distutils in Python 2.1 changed the strip_dir flag
+# passed to object_filenames to true, which causes problems for us since
+# there are a few duplicate source/object names between some of the
+# extensions in wxPython. This hack replaces the CCompiler._prep_compile
+# method with this one.
+
+from distutils.dep_util import newer_pairwise
+
+def _prep_compile (self, sources, output_dir):
+ """Determine the list of object files corresponding to 'sources',
+ and figure out which ones really need to be recompiled. Return a
+ list of all object files and a dictionary telling which source
+ files can be skipped.
+ """
+ # Get the list of expected output (object) files
+ objects = self.object_filenames (sources,
+ strip_dir=0,
+ output_dir=output_dir)
+
+ if self.force:
+ skip_source = {} # rebuild everything
+ for source in sources:
+ skip_source[source] = 0
+ else:
+ # Figure out which source files we have to recompile according
+ # to a simplistic check -- we just compare the source and
+ # object file, no deep dependency checking involving header
+ # files.
+ skip_source = {} # rebuild everything
+ for source in sources: # no wait, rebuild nothing
+ skip_source[source] = 1
+
+ (n_sources, n_objects) = newer_pairwise (sources, objects)
+ for source in n_sources: # no really, only rebuild what's
+ skip_source[source] = 0 # out-of-date
+
+ return (objects, skip_source)
+
+# _prep_compile ()
+
+CCompiler._prep_compile = _prep_compile
+
+
#----------------------------------------------------------------------