Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
bcppcompiler.py398 linesDownload Raw Back to _distutils
1"""distutils.bcppcompiler2 3Contains BorlandCCompiler, an implementation of the abstract CCompiler class4for the Borland C++ compiler.5"""6 7# This implementation by Lyle Johnson, based on the original msvccompiler.py8# module and using the directions originally published by Gordon Williams.9 10# XXX looks like there's a LOT of overlap between these two classes:11# someone should sit down and factor out the common code as12# WindowsCCompiler!  --GPW13 14import os15import warnings16 17from ._log import log18from ._modified import newer19from .ccompiler import CCompiler, gen_preprocess_options20from .errors import (21    CompileError,22    DistutilsExecError,23    LibError,24    LinkError,25    UnknownFileError,26)27from .file_util import write_file28 29warnings.warn(30    "bcppcompiler is deprecated and slated to be removed "31    "in the future. Please discontinue use or file an issue "32    "with pypa/distutils describing your use case.",33    DeprecationWarning,34)35 36 37class BCPPCompiler(CCompiler):38    """Concrete class that implements an interface to the Borland C/C++39    compiler, as defined by the CCompiler abstract class.40    """41 42    compiler_type = 'bcpp'43 44    # Just set this so CCompiler's constructor doesn't barf.  We currently45    # don't use the 'set_executables()' bureaucracy provided by CCompiler,46    # as it really isn't necessary for this sort of single-compiler class.47    # Would be nice to have a consistent interface with UnixCCompiler,48    # though, so it's worth thinking about.49    executables = {}50 51    # Private class data (need to distinguish C from C++ source for compiler)52    _c_extensions = ['.c']53    _cpp_extensions = ['.cc', '.cpp', '.cxx']54 55    # Needed for the filename generation methods provided by the56    # base class, CCompiler.57    src_extensions = _c_extensions + _cpp_extensions58    obj_extension = '.obj'59    static_lib_extension = '.lib'60    shared_lib_extension = '.dll'61    static_lib_format = shared_lib_format = '%s%s'62    exe_extension = '.exe'63 64    def __init__(self, verbose=0, dry_run=0, force=0):65        super().__init__(verbose, dry_run, force)66 67        # These executables are assumed to all be in the path.68        # Borland doesn't seem to use any special registry settings to69        # indicate their installation locations.70 71        self.cc = "bcc32.exe"72        self.linker = "ilink32.exe"73        self.lib = "tlib.exe"74 75        self.preprocess_options = None76        self.compile_options = ['/tWM', '/O2', '/q', '/g0']77        self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0']78 79        self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x']80        self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']81        self.ldflags_static = []82        self.ldflags_exe = ['/Gn', '/q', '/x']83        self.ldflags_exe_debug = ['/Gn', '/q', '/x', '/r']84 85    # -- Worker methods ------------------------------------------------86 87    def compile(  # noqa: C90188        self,89        sources,90        output_dir=None,91        macros=None,92        include_dirs=None,93        debug=0,94        extra_preargs=None,95        extra_postargs=None,96        depends=None,97    ):98        macros, objects, extra_postargs, pp_opts, build = self._setup_compile(99            output_dir, macros, include_dirs, sources, depends, extra_postargs100        )101        compile_opts = extra_preargs or []102        compile_opts.append('-c')103        if debug:104            compile_opts.extend(self.compile_options_debug)105        else:106            compile_opts.extend(self.compile_options)107 108        for obj in objects:109            try:110                src, ext = build[obj]111            except KeyError:112                continue113            # XXX why do the normpath here?114            src = os.path.normpath(src)115            obj = os.path.normpath(obj)116            # XXX _setup_compile() did a mkpath() too but before the normpath.117            # Is it possible to skip the normpath?118            self.mkpath(os.path.dirname(obj))119 120            if ext == '.res':121                # This is already a binary file -- skip it.122                continue  # the 'for' loop123            if ext == '.rc':124                # This needs to be compiled to a .res file -- do it now.125                try:126                    self.spawn(["brcc32", "-fo", obj, src])127                except DistutilsExecError as msg:128                    raise CompileError(msg)129                continue  # the 'for' loop130 131            # The next two are both for the real compiler.132            if ext in self._c_extensions:133                input_opt = ""134            elif ext in self._cpp_extensions:135                input_opt = "-P"136            else:137                # Unknown file type -- no extra options.  The compiler138                # will probably fail, but let it just in case this is a139                # file the compiler recognizes even if we don't.140                input_opt = ""141 142            output_opt = "-o" + obj143 144            # Compiler command line syntax is: "bcc32 [options] file(s)".145            # Note that the source file names must appear at the end of146            # the command line.147            try:148                self.spawn(149                    [self.cc]150                    + compile_opts151                    + pp_opts152                    + [input_opt, output_opt]153                    + extra_postargs154                    + [src]155                )156            except DistutilsExecError as msg:157                raise CompileError(msg)158 159        return objects160 161    # compile ()162 163    def create_static_lib(164        self, objects, output_libname, output_dir=None, debug=0, target_lang=None165    ):166        (objects, output_dir) = self._fix_object_args(objects, output_dir)167        output_filename = self.library_filename(output_libname, output_dir=output_dir)168 169        if self._need_link(objects, output_filename):170            lib_args = [output_filename, '/u'] + objects171            if debug:172                pass  # XXX what goes here?173            try:174                self.spawn([self.lib] + lib_args)175            except DistutilsExecError as msg:176                raise LibError(msg)177        else:178            log.debug("skipping %s (up-to-date)", output_filename)179 180    # create_static_lib ()181 182    def link(  # noqa: C901183        self,184        target_desc,185        objects,186        output_filename,187        output_dir=None,188        libraries=None,189        library_dirs=None,190        runtime_library_dirs=None,191        export_symbols=None,192        debug=0,193        extra_preargs=None,194        extra_postargs=None,195        build_temp=None,196        target_lang=None,197    ):198        # XXX this ignores 'build_temp'!  should follow the lead of199        # msvccompiler.py200 201        (objects, output_dir) = self._fix_object_args(objects, output_dir)202        (libraries, library_dirs, runtime_library_dirs) = self._fix_lib_args(203            libraries, library_dirs, runtime_library_dirs204        )205 206        if runtime_library_dirs:207            log.warning(208                "I don't know what to do with 'runtime_library_dirs': %s",209                str(runtime_library_dirs),210            )211 212        if output_dir is not None:213            output_filename = os.path.join(output_dir, output_filename)214 215        if self._need_link(objects, output_filename):216            # Figure out linker args based on type of target.217            if target_desc == CCompiler.EXECUTABLE:218                startup_obj = 'c0w32'219                if debug:220                    ld_args = self.ldflags_exe_debug[:]221                else:222                    ld_args = self.ldflags_exe[:]223            else:224                startup_obj = 'c0d32'225                if debug:226                    ld_args = self.ldflags_shared_debug[:]227                else:228                    ld_args = self.ldflags_shared[:]229 230            # Create a temporary exports file for use by the linker231            if export_symbols is None:232                def_file = ''233            else:234                head, tail = os.path.split(output_filename)235                modname, ext = os.path.splitext(tail)236                temp_dir = os.path.dirname(objects[0])  # preserve tree structure237                def_file = os.path.join(temp_dir, '%s.def' % modname)238                contents = ['EXPORTS']239                for sym in export_symbols or []:240                    contents.append(f'  {sym}=_{sym}')241                self.execute(write_file, (def_file, contents), "writing %s" % def_file)242 243            # Borland C++ has problems with '/' in paths244            objects2 = map(os.path.normpath, objects)245            # split objects in .obj and .res files246            # Borland C++ needs them at different positions in the command line247            objects = [startup_obj]248            resources = []249            for file in objects2:250                (base, ext) = os.path.splitext(os.path.normcase(file))251                if ext == '.res':252                    resources.append(file)253                else:254                    objects.append(file)255 256            for ell in library_dirs:257                ld_args.append("/L%s" % os.path.normpath(ell))258            ld_args.append("/L.")  # we sometimes use relative paths259 260            # list of object files261            ld_args.extend(objects)262 263            # XXX the command-line syntax for Borland C++ is a bit wonky;264            # certain filenames are jammed together in one big string, but265            # comma-delimited.  This doesn't mesh too well with the266            # Unix-centric attitude (with a DOS/Windows quoting hack) of267            # 'spawn()', so constructing the argument list is a bit268            # awkward.  Note that doing the obvious thing and jamming all269            # the filenames and commas into one argument would be wrong,270            # because 'spawn()' would quote any filenames with spaces in271            # them.  Arghghh!.  Apparently it works fine as coded...272 273            # name of dll/exe file274            ld_args.extend([',', output_filename])275            # no map file and start libraries276            ld_args.append(',,')277 278            for lib in libraries:279                # see if we find it and if there is a bcpp specific lib280                # (xxx_bcpp.lib)281                libfile = self.find_library_file(library_dirs, lib, debug)282                if libfile is None:283                    ld_args.append(lib)284                    # probably a BCPP internal library -- don't warn285                else:286                    # full name which prefers bcpp_xxx.lib over xxx.lib287                    ld_args.append(libfile)288 289            # some default libraries290            ld_args.extend(('import32', 'cw32mt'))291 292            # def file for export symbols293            ld_args.extend([',', def_file])294            # add resource files295            ld_args.append(',')296            ld_args.extend(resources)297 298            if extra_preargs:299                ld_args[:0] = extra_preargs300            if extra_postargs:301                ld_args.extend(extra_postargs)302 303            self.mkpath(os.path.dirname(output_filename))304            try:305                self.spawn([self.linker] + ld_args)306            except DistutilsExecError as msg:307                raise LinkError(msg)308 309        else:310            log.debug("skipping %s (up-to-date)", output_filename)311 312    # link ()313 314    # -- Miscellaneous methods -----------------------------------------315 316    def find_library_file(self, dirs, lib, debug=0):317        # List of effective library names to try, in order of preference:318        # xxx_bcpp.lib is better than xxx.lib319        # and xxx_d.lib is better than xxx.lib if debug is set320        #321        # The "_bcpp" suffix is to handle a Python installation for people322        # with multiple compilers (primarily Distutils hackers, I suspect323        # ;-).  The idea is they'd have one static library for each324        # compiler they care about, since (almost?) every Windows compiler325        # seems to have a different format for static libraries.326        if debug:327            dlib = lib + "_d"328            try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib)329        else:330            try_names = (lib + "_bcpp", lib)331 332        for dir in dirs:333            for name in try_names:334                libfile = os.path.join(dir, self.library_filename(name))335                if os.path.exists(libfile):336                    return libfile337        else:338            # Oops, didn't find it in *any* of 'dirs'339            return None340 341    # overwrite the one from CCompiler to support rc and res-files342    def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):343        if output_dir is None:344            output_dir = ''345        obj_names = []346        for src_name in source_filenames:347            # use normcase to make sure '.rc' is really '.rc' and not '.RC'348            (base, ext) = os.path.splitext(os.path.normcase(src_name))349            if ext not in (self.src_extensions + ['.rc', '.res']):350                raise UnknownFileError(f"unknown file type '{ext}' (from '{src_name}')")351            if strip_dir:352                base = os.path.basename(base)353            if ext == '.res':354                # these can go unchanged355                obj_names.append(os.path.join(output_dir, base + ext))356            elif ext == '.rc':357                # these need to be compiled to .res-files358                obj_names.append(os.path.join(output_dir, base + '.res'))359            else:360                obj_names.append(os.path.join(output_dir, base + self.obj_extension))361        return obj_names362 363    # object_filenames ()364 365    def preprocess(366        self,367        source,368        output_file=None,369        macros=None,370        include_dirs=None,371        extra_preargs=None,372        extra_postargs=None,373    ):374        (_, macros, include_dirs) = self._fix_compile_args(None, macros, include_dirs)375        pp_opts = gen_preprocess_options(macros, include_dirs)376        pp_args = ['cpp32.exe'] + pp_opts377        if output_file is not None:378            pp_args.append('-o' + output_file)379        if extra_preargs:380            pp_args[:0] = extra_preargs381        if extra_postargs:382            pp_args.extend(extra_postargs)383        pp_args.append(source)384 385        # We need to preprocess: either we're being forced to, or the386        # source file is newer than the target (or the target doesn't387        # exist).388        if self.force or output_file is None or newer(source, output_file):389            if output_file:390                self.mkpath(os.path.dirname(output_file))391            try:392                self.spawn(pp_args)393            except DistutilsExecError as msg:394                print(msg)395                raise CompileError(msg)396 397    # preprocess()398 
codekingpro/portable-devtools · Team Ai