initial commit
This commit is contained in:
		| @@ -0,0 +1,408 @@ | ||||
| """distutils.bcppcompiler | ||||
|  | ||||
| Contains BorlandCCompiler, an implementation of the abstract CCompiler class | ||||
| for the Borland C++ compiler. | ||||
| """ | ||||
|  | ||||
| # This implementation by Lyle Johnson, based on the original msvccompiler.py | ||||
| # module and using the directions originally published by Gordon Williams. | ||||
|  | ||||
| # XXX looks like there's a LOT of overlap between these two classes: | ||||
| # someone should sit down and factor out the common code as | ||||
| # WindowsCCompiler!  --GPW | ||||
|  | ||||
|  | ||||
| import os | ||||
| import warnings | ||||
|  | ||||
| from .errors import ( | ||||
|     DistutilsExecError, | ||||
|     CompileError, | ||||
|     LibError, | ||||
|     LinkError, | ||||
|     UnknownFileError, | ||||
| ) | ||||
| from .ccompiler import CCompiler, gen_preprocess_options | ||||
| from .file_util import write_file | ||||
| from .dep_util import newer | ||||
| from ._log import log | ||||
|  | ||||
|  | ||||
| warnings.warn( | ||||
|     "bcppcompiler is deprecated and slated to be removed " | ||||
|     "in the future. Please discontinue use or file an issue " | ||||
|     "with pypa/distutils describing your use case.", | ||||
|     DeprecationWarning, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class BCPPCompiler(CCompiler): | ||||
|     """Concrete class that implements an interface to the Borland C/C++ | ||||
|     compiler, as defined by the CCompiler abstract class. | ||||
|     """ | ||||
|  | ||||
|     compiler_type = 'bcpp' | ||||
|  | ||||
|     # Just set this so CCompiler's constructor doesn't barf.  We currently | ||||
|     # don't use the 'set_executables()' bureaucracy provided by CCompiler, | ||||
|     # as it really isn't necessary for this sort of single-compiler class. | ||||
|     # Would be nice to have a consistent interface with UnixCCompiler, | ||||
|     # though, so it's worth thinking about. | ||||
|     executables = {} | ||||
|  | ||||
|     # Private class data (need to distinguish C from C++ source for compiler) | ||||
|     _c_extensions = ['.c'] | ||||
|     _cpp_extensions = ['.cc', '.cpp', '.cxx'] | ||||
|  | ||||
|     # Needed for the filename generation methods provided by the | ||||
|     # base class, CCompiler. | ||||
|     src_extensions = _c_extensions + _cpp_extensions | ||||
|     obj_extension = '.obj' | ||||
|     static_lib_extension = '.lib' | ||||
|     shared_lib_extension = '.dll' | ||||
|     static_lib_format = shared_lib_format = '%s%s' | ||||
|     exe_extension = '.exe' | ||||
|  | ||||
|     def __init__(self, verbose=0, dry_run=0, force=0): | ||||
|  | ||||
|         super().__init__(verbose, dry_run, force) | ||||
|  | ||||
|         # These executables are assumed to all be in the path. | ||||
|         # Borland doesn't seem to use any special registry settings to | ||||
|         # indicate their installation locations. | ||||
|  | ||||
|         self.cc = "bcc32.exe" | ||||
|         self.linker = "ilink32.exe" | ||||
|         self.lib = "tlib.exe" | ||||
|  | ||||
|         self.preprocess_options = None | ||||
|         self.compile_options = ['/tWM', '/O2', '/q', '/g0'] | ||||
|         self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0'] | ||||
|  | ||||
|         self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x'] | ||||
|         self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] | ||||
|         self.ldflags_static = [] | ||||
|         self.ldflags_exe = ['/Gn', '/q', '/x'] | ||||
|         self.ldflags_exe_debug = ['/Gn', '/q', '/x', '/r'] | ||||
|  | ||||
|     # -- Worker methods ------------------------------------------------ | ||||
|  | ||||
|     def compile(  # noqa: C901 | ||||
|         self, | ||||
|         sources, | ||||
|         output_dir=None, | ||||
|         macros=None, | ||||
|         include_dirs=None, | ||||
|         debug=0, | ||||
|         extra_preargs=None, | ||||
|         extra_postargs=None, | ||||
|         depends=None, | ||||
|     ): | ||||
|  | ||||
|         macros, objects, extra_postargs, pp_opts, build = self._setup_compile( | ||||
|             output_dir, macros, include_dirs, sources, depends, extra_postargs | ||||
|         ) | ||||
|         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 obj in objects: | ||||
|             try: | ||||
|                 src, ext = build[obj] | ||||
|             except KeyError: | ||||
|                 continue | ||||
|             # XXX why do the normpath here? | ||||
|             src = os.path.normpath(src) | ||||
|             obj = os.path.normpath(obj) | ||||
|             # XXX _setup_compile() did a mkpath() too but before the normpath. | ||||
|             # Is it possible to skip the normpath? | ||||
|             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", "-fo", obj, src]) | ||||
|                 except DistutilsExecError as 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 as msg: | ||||
|                 raise CompileError(msg) | ||||
|  | ||||
|         return objects | ||||
|  | ||||
|     # compile () | ||||
|  | ||||
|     def create_static_lib( | ||||
|         self, objects, output_libname, output_dir=None, debug=0, target_lang=None | ||||
|     ): | ||||
|  | ||||
|         (objects, output_dir) = self._fix_object_args(objects, output_dir) | ||||
|         output_filename = self.library_filename(output_libname, output_dir=output_dir) | ||||
|  | ||||
|         if self._need_link(objects, output_filename): | ||||
|             lib_args = [output_filename, '/u'] + objects | ||||
|             if debug: | ||||
|                 pass  # XXX what goes here? | ||||
|             try: | ||||
|                 self.spawn([self.lib] + lib_args) | ||||
|             except DistutilsExecError as msg: | ||||
|                 raise LibError(msg) | ||||
|         else: | ||||
|             log.debug("skipping %s (up-to-date)", output_filename) | ||||
|  | ||||
|     # create_static_lib () | ||||
|  | ||||
|     def link(  # noqa: C901 | ||||
|         self, | ||||
|         target_desc, | ||||
|         objects, | ||||
|         output_filename, | ||||
|         output_dir=None, | ||||
|         libraries=None, | ||||
|         library_dirs=None, | ||||
|         runtime_library_dirs=None, | ||||
|         export_symbols=None, | ||||
|         debug=0, | ||||
|         extra_preargs=None, | ||||
|         extra_postargs=None, | ||||
|         build_temp=None, | ||||
|         target_lang=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 | ||||
|         ) | ||||
|  | ||||
|         if runtime_library_dirs: | ||||
|             log.warning( | ||||
|                 "I don't know what to do with 'runtime_library_dirs': %s", | ||||
|                 str(runtime_library_dirs), | ||||
|             ) | ||||
|  | ||||
|         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: | ||||
|                     ld_args = self.ldflags_exe_debug[:] | ||||
|                 else: | ||||
|                     ld_args = self.ldflags_exe[:] | ||||
|             else: | ||||
|                 startup_obj = 'c0d32' | ||||
|                 if debug: | ||||
|                     ld_args = self.ldflags_shared_debug[:] | ||||
|                 else: | ||||
|                     ld_args = self.ldflags_shared[:] | ||||
|  | ||||
|             # 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('  {}=_{}'.format(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 ell in library_dirs: | ||||
|                 ld_args.append("/L%s" % os.path.normpath(ell)) | ||||
|             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 | ||||
|                 else: | ||||
|                     # full name which prefers bcpp_xxx.lib over xxx.lib | ||||
|                     ld_args.append(libfile) | ||||
|  | ||||
|             # some default libraries | ||||
|             ld_args.append('import32') | ||||
|             ld_args.append('cw32mt') | ||||
|  | ||||
|             # def file for export symbols | ||||
|             ld_args.extend([',', def_file]) | ||||
|             # add resource files | ||||
|             ld_args.append(',') | ||||
|             ld_args.extend(resources) | ||||
|  | ||||
|             if extra_preargs: | ||||
|                 ld_args[:0] = extra_preargs | ||||
|             if extra_postargs: | ||||
|                 ld_args.extend(extra_postargs) | ||||
|  | ||||
|             self.mkpath(os.path.dirname(output_filename)) | ||||
|             try: | ||||
|                 self.spawn([self.linker] + ld_args) | ||||
|             except DistutilsExecError as msg: | ||||
|                 raise LinkError(msg) | ||||
|  | ||||
|         else: | ||||
|             log.debug("skipping %s (up-to-date)", output_filename) | ||||
|  | ||||
|     # link () | ||||
|  | ||||
|     # -- Miscellaneous methods ----------------------------------------- | ||||
|  | ||||
|     def find_library_file(self, dirs, lib, debug=0): | ||||
|         # List of effective library names to try, in order of preference: | ||||
|         # xxx_bcpp.lib is better than xxx.lib | ||||
|         # and xxx_d.lib is better than xxx.lib if debug is set | ||||
|         # | ||||
|         # The "_bcpp" suffix is to handle a Python installation for people | ||||
|         # with multiple compilers (primarily Distutils hackers, I suspect | ||||
|         # ;-).  The idea is they'd have one static library for each | ||||
|         # compiler they care about, since (almost?) every Windows compiler | ||||
|         # seems to have a different format for static libraries. | ||||
|         if debug: | ||||
|             dlib = lib + "_d" | ||||
|             try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib) | ||||
|         else: | ||||
|             try_names = (lib + "_bcpp", lib) | ||||
|  | ||||
|         for dir in dirs: | ||||
|             for name in try_names: | ||||
|                 libfile = os.path.join(dir, self.library_filename(name)) | ||||
|                 if os.path.exists(libfile): | ||||
|                     return libfile | ||||
|         else: | ||||
|             # Oops, didn't find it in *any* of 'dirs' | ||||
|             return None | ||||
|  | ||||
|     # overwrite the one from CCompiler to support rc and res-files | ||||
|     def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): | ||||
|         if output_dir is None: | ||||
|             output_dir = '' | ||||
|         obj_names = [] | ||||
|         for src_name in source_filenames: | ||||
|             # use normcase to make sure '.rc' is really '.rc' and not '.RC' | ||||
|             (base, ext) = os.path.splitext(os.path.normcase(src_name)) | ||||
|             if ext not in (self.src_extensions + ['.rc', '.res']): | ||||
|                 raise UnknownFileError( | ||||
|                     "unknown file type '{}' (from '{}')".format(ext, src_name) | ||||
|                 ) | ||||
|             if strip_dir: | ||||
|                 base = os.path.basename(base) | ||||
|             if ext == '.res': | ||||
|                 # these can go unchanged | ||||
|                 obj_names.append(os.path.join(output_dir, base + ext)) | ||||
|             elif ext == '.rc': | ||||
|                 # these need to be compiled to .res-files | ||||
|                 obj_names.append(os.path.join(output_dir, base + '.res')) | ||||
|             else: | ||||
|                 obj_names.append(os.path.join(output_dir, base + self.obj_extension)) | ||||
|         return obj_names | ||||
|  | ||||
|     # object_filenames () | ||||
|  | ||||
|     def preprocess( | ||||
|         self, | ||||
|         source, | ||||
|         output_file=None, | ||||
|         macros=None, | ||||
|         include_dirs=None, | ||||
|         extra_preargs=None, | ||||
|         extra_postargs=None, | ||||
|     ): | ||||
|  | ||||
|         (_, macros, include_dirs) = self._fix_compile_args(None, macros, include_dirs) | ||||
|         pp_opts = gen_preprocess_options(macros, include_dirs) | ||||
|         pp_args = ['cpp32.exe'] + pp_opts | ||||
|         if output_file is not None: | ||||
|             pp_args.append('-o' + output_file) | ||||
|         if extra_preargs: | ||||
|             pp_args[:0] = extra_preargs | ||||
|         if extra_postargs: | ||||
|             pp_args.extend(extra_postargs) | ||||
|         pp_args.append(source) | ||||
|  | ||||
|         # We need to preprocess: either we're being forced to, or the | ||||
|         # source file is newer than the target (or the target doesn't | ||||
|         # exist). | ||||
|         if self.force or output_file is None or newer(source, output_file): | ||||
|             if output_file: | ||||
|                 self.mkpath(os.path.dirname(output_file)) | ||||
|             try: | ||||
|                 self.spawn(pp_args) | ||||
|             except DistutilsExecError as msg: | ||||
|                 print(msg) | ||||
|                 raise CompileError(msg) | ||||
|  | ||||
|     # preprocess() | ||||
		Reference in New Issue
	
	Block a user
	 klein panic
					klein panic