Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
ccompiler.py1253 linesDownload Raw Back to _distutils
1"""distutils.ccompiler2 3Contains CCompiler, an abstract base class that defines the interface4for the Distutils compiler abstraction model."""5 6import os7import re8import sys9import warnings10 11from ._itertools import always_iterable12from ._log import log13from ._modified import newer_group14from .dir_util import mkpath15from .errors import (16    CompileError,17    DistutilsModuleError,18    DistutilsPlatformError,19    LinkError,20    UnknownFileError,21)22from .file_util import move_file23from .spawn import spawn24from .util import execute, split_quoted25 26 27class CCompiler:28    """Abstract base class to define the interface that must be implemented29    by real compiler classes.  Also has some utility methods used by30    several compiler classes.31 32    The basic idea behind a compiler abstraction class is that each33    instance can be used for all the compile/link steps in building a34    single project.  Thus, attributes common to all of those compile and35    link steps -- include directories, macros to define, libraries to link36    against, etc. -- are attributes of the compiler instance.  To allow for37    variability in how individual files are treated, most of those38    attributes may be varied on a per-compilation or per-link basis.39    """40 41    # 'compiler_type' is a class attribute that identifies this class.  It42    # keeps code that wants to know what kind of compiler it's dealing with43    # from having to import all possible compiler classes just to do an44    # 'isinstance'.  In concrete CCompiler subclasses, 'compiler_type'45    # should really, really be one of the keys of the 'compiler_class'46    # dictionary (see below -- used by the 'new_compiler()' factory47    # function) -- authors of new compiler interface classes are48    # responsible for updating 'compiler_class'!49    compiler_type = None50 51    # XXX things not handled by this compiler abstraction model:52    #   * client can't provide additional options for a compiler,53    #     e.g. warning, optimization, debugging flags.  Perhaps this54    #     should be the domain of concrete compiler abstraction classes55    #     (UnixCCompiler, MSVCCompiler, etc.) -- or perhaps the base56    #     class should have methods for the common ones.57    #   * can't completely override the include or library searchg58    #     path, ie. no "cc -I -Idir1 -Idir2" or "cc -L -Ldir1 -Ldir2".59    #     I'm not sure how widely supported this is even by Unix60    #     compilers, much less on other platforms.  And I'm even less61    #     sure how useful it is; maybe for cross-compiling, but62    #     support for that is a ways off.  (And anyways, cross63    #     compilers probably have a dedicated binary with the64    #     right paths compiled in.  I hope.)65    #   * can't do really freaky things with the library list/library66    #     dirs, e.g. "-Ldir1 -lfoo -Ldir2 -lfoo" to link against67    #     different versions of libfoo.a in different locations.  I68    #     think this is useless without the ability to null out the69    #     library search path anyways.70 71    # Subclasses that rely on the standard filename generation methods72    # implemented below should override these; see the comment near73    # those methods ('object_filenames()' et. al.) for details:74    src_extensions = None  # list of strings75    obj_extension = None  # string76    static_lib_extension = None77    shared_lib_extension = None  # string78    static_lib_format = None  # format string79    shared_lib_format = None  # prob. same as static_lib_format80    exe_extension = None  # string81 82    # Default language settings. language_map is used to detect a source83    # file or Extension target language, checking source filenames.84    # language_order is used to detect the language precedence, when deciding85    # what language to use when mixing source types. For example, if some86    # extension has two files with ".c" extension, and one with ".cpp", it87    # is still linked as c++.88    language_map = {89        ".c": "c",90        ".cc": "c++",91        ".cpp": "c++",92        ".cxx": "c++",93        ".m": "objc",94    }95    language_order = ["c++", "objc", "c"]96 97    include_dirs = []98    """99    include dirs specific to this compiler class100    """101 102    library_dirs = []103    """104    library dirs specific to this compiler class105    """106 107    def __init__(self, verbose=0, dry_run=0, force=0):108        self.dry_run = dry_run109        self.force = force110        self.verbose = verbose111 112        # 'output_dir': a common output directory for object, library,113        # shared object, and shared library files114        self.output_dir = None115 116        # 'macros': a list of macro definitions (or undefinitions).  A117        # macro definition is a 2-tuple (name, value), where the value is118        # either a string or None (no explicit value).  A macro119        # undefinition is a 1-tuple (name,).120        self.macros = []121 122        # 'include_dirs': a list of directories to search for include files123        self.include_dirs = []124 125        # 'libraries': a list of libraries to include in any link126        # (library names, not filenames: eg. "foo" not "libfoo.a")127        self.libraries = []128 129        # 'library_dirs': a list of directories to search for libraries130        self.library_dirs = []131 132        # 'runtime_library_dirs': a list of directories to search for133        # shared libraries/objects at runtime134        self.runtime_library_dirs = []135 136        # 'objects': a list of object files (or similar, such as explicitly137        # named library files) to include on any link138        self.objects = []139 140        for key in self.executables.keys():141            self.set_executable(key, self.executables[key])142 143    def set_executables(self, **kwargs):144        """Define the executables (and options for them) that will be run145        to perform the various stages of compilation.  The exact set of146        executables that may be specified here depends on the compiler147        class (via the 'executables' class attribute), but most will have:148          compiler      the C/C++ compiler149          linker_so     linker used to create shared objects and libraries150          linker_exe    linker used to create binary executables151          archiver      static library creator152 153        On platforms with a command-line (Unix, DOS/Windows), each of these154        is a string that will be split into executable name and (optional)155        list of arguments.  (Splitting the string is done similarly to how156        Unix shells operate: words are delimited by spaces, but quotes and157        backslashes can override this.  See158        'distutils.util.split_quoted()'.)159        """160 161        # Note that some CCompiler implementation classes will define class162        # attributes 'cpp', 'cc', etc. with hard-coded executable names;163        # this is appropriate when a compiler class is for exactly one164        # compiler/OS combination (eg. MSVCCompiler).  Other compiler165        # classes (UnixCCompiler, in particular) are driven by information166        # discovered at run-time, since there are many different ways to do167        # basically the same things with Unix C compilers.168 169        for key in kwargs:170            if key not in self.executables:171                raise ValueError(172                    f"unknown executable '{key}' for class {self.__class__.__name__}"173                )174            self.set_executable(key, kwargs[key])175 176    def set_executable(self, key, value):177        if isinstance(value, str):178            setattr(self, key, split_quoted(value))179        else:180            setattr(self, key, value)181 182    def _find_macro(self, name):183        i = 0184        for defn in self.macros:185            if defn[0] == name:186                return i187            i += 1188        return None189 190    def _check_macro_definitions(self, definitions):191        """Ensures that every element of 'definitions' is a valid macro192        definition, ie. either (name,value) 2-tuple or a (name,) tuple.  Do193        nothing if all definitions are OK, raise TypeError otherwise.194        """195        for defn in definitions:196            if not (197                isinstance(defn, tuple)198                and (199                    len(defn) in (1, 2)200                    and (isinstance(defn[1], str) or defn[1] is None)201                )202                and isinstance(defn[0], str)203            ):204                raise TypeError(205                    ("invalid macro definition '%s': " % defn)206                    + "must be tuple (string,), (string, string), or "207                    + "(string, None)"208                )209 210    # -- Bookkeeping methods -------------------------------------------211 212    def define_macro(self, name, value=None):213        """Define a preprocessor macro for all compilations driven by this214        compiler object.  The optional parameter 'value' should be a215        string; if it is not supplied, then the macro will be defined216        without an explicit value and the exact outcome depends on the217        compiler used (XXX true? does ANSI say anything about this?)218        """219        # Delete from the list of macro definitions/undefinitions if220        # already there (so that this one will take precedence).221        i = self._find_macro(name)222        if i is not None:223            del self.macros[i]224 225        self.macros.append((name, value))226 227    def undefine_macro(self, name):228        """Undefine a preprocessor macro for all compilations driven by229        this compiler object.  If the same macro is defined by230        'define_macro()' and undefined by 'undefine_macro()' the last call231        takes precedence (including multiple redefinitions or232        undefinitions).  If the macro is redefined/undefined on a233        per-compilation basis (ie. in the call to 'compile()'), then that234        takes precedence.235        """236        # Delete from the list of macro definitions/undefinitions if237        # already there (so that this one will take precedence).238        i = self._find_macro(name)239        if i is not None:240            del self.macros[i]241 242        undefn = (name,)243        self.macros.append(undefn)244 245    def add_include_dir(self, dir):246        """Add 'dir' to the list of directories that will be searched for247        header files.  The compiler is instructed to search directories in248        the order in which they are supplied by successive calls to249        'add_include_dir()'.250        """251        self.include_dirs.append(dir)252 253    def set_include_dirs(self, dirs):254        """Set the list of directories that will be searched to 'dirs' (a255        list of strings).  Overrides any preceding calls to256        'add_include_dir()'; subsequence calls to 'add_include_dir()' add257        to the list passed to 'set_include_dirs()'.  This does not affect258        any list of standard include directories that the compiler may259        search by default.260        """261        self.include_dirs = dirs[:]262 263    def add_library(self, libname):264        """Add 'libname' to the list of libraries that will be included in265        all links driven by this compiler object.  Note that 'libname'266        should *not* be the name of a file containing a library, but the267        name of the library itself: the actual filename will be inferred by268        the linker, the compiler, or the compiler class (depending on the269        platform).270 271        The linker will be instructed to link against libraries in the272        order they were supplied to 'add_library()' and/or273        'set_libraries()'.  It is perfectly valid to duplicate library274        names; the linker will be instructed to link against libraries as275        many times as they are mentioned.276        """277        self.libraries.append(libname)278 279    def set_libraries(self, libnames):280        """Set the list of libraries to be included in all links driven by281        this compiler object to 'libnames' (a list of strings).  This does282        not affect any standard system libraries that the linker may283        include by default.284        """285        self.libraries = libnames[:]286 287    def add_library_dir(self, dir):288        """Add 'dir' to the list of directories that will be searched for289        libraries specified to 'add_library()' and 'set_libraries()'.  The290        linker will be instructed to search for libraries in the order they291        are supplied to 'add_library_dir()' and/or 'set_library_dirs()'.292        """293        self.library_dirs.append(dir)294 295    def set_library_dirs(self, dirs):296        """Set the list of library search directories to 'dirs' (a list of297        strings).  This does not affect any standard library search path298        that the linker may search by default.299        """300        self.library_dirs = dirs[:]301 302    def add_runtime_library_dir(self, dir):303        """Add 'dir' to the list of directories that will be searched for304        shared libraries at runtime.305        """306        self.runtime_library_dirs.append(dir)307 308    def set_runtime_library_dirs(self, dirs):309        """Set the list of directories to search for shared libraries at310        runtime to 'dirs' (a list of strings).  This does not affect any311        standard search path that the runtime linker may search by312        default.313        """314        self.runtime_library_dirs = dirs[:]315 316    def add_link_object(self, object):317        """Add 'object' to the list of object files (or analogues, such as318        explicitly named library files or the output of "resource319        compilers") to be included in every link driven by this compiler320        object.321        """322        self.objects.append(object)323 324    def set_link_objects(self, objects):325        """Set the list of object files (or analogues) to be included in326        every link to 'objects'.  This does not affect any standard object327        files that the linker may include by default (such as system328        libraries).329        """330        self.objects = objects[:]331 332    # -- Private utility methods --------------------------------------333    # (here for the convenience of subclasses)334 335    # Helper method to prep compiler in subclass compile() methods336 337    def _setup_compile(self, outdir, macros, incdirs, sources, depends, extra):338        """Process arguments and decide which source files to compile."""339        outdir, macros, incdirs = self._fix_compile_args(outdir, macros, incdirs)340 341        if extra is None:342            extra = []343 344        # Get the list of expected output (object) files345        objects = self.object_filenames(sources, strip_dir=0, output_dir=outdir)346        assert len(objects) == len(sources)347 348        pp_opts = gen_preprocess_options(macros, incdirs)349 350        build = {}351        for i in range(len(sources)):352            src = sources[i]353            obj = objects[i]354            ext = os.path.splitext(src)[1]355            self.mkpath(os.path.dirname(obj))356            build[obj] = (src, ext)357 358        return macros, objects, extra, pp_opts, build359 360    def _get_cc_args(self, pp_opts, debug, before):361        # works for unixccompiler, cygwinccompiler362        cc_args = pp_opts + ['-c']363        if debug:364            cc_args[:0] = ['-g']365        if before:366            cc_args[:0] = before367        return cc_args368 369    def _fix_compile_args(self, output_dir, macros, include_dirs):370        """Typecheck and fix-up some of the arguments to the 'compile()'371        method, and return fixed-up values.  Specifically: if 'output_dir'372        is None, replaces it with 'self.output_dir'; ensures that 'macros'373        is a list, and augments it with 'self.macros'; ensures that374        'include_dirs' is a list, and augments it with 'self.include_dirs'.375        Guarantees that the returned values are of the correct type,376        i.e. for 'output_dir' either string or None, and for 'macros' and377        'include_dirs' either list or None.378        """379        if output_dir is None:380            output_dir = self.output_dir381        elif not isinstance(output_dir, str):382            raise TypeError("'output_dir' must be a string or None")383 384        if macros is None:385            macros = list(self.macros)386        elif isinstance(macros, list):387            macros = macros + (self.macros or [])388        else:389            raise TypeError("'macros' (if supplied) must be a list of tuples")390 391        if include_dirs is None:392            include_dirs = list(self.include_dirs)393        elif isinstance(include_dirs, (list, tuple)):394            include_dirs = list(include_dirs) + (self.include_dirs or [])395        else:396            raise TypeError("'include_dirs' (if supplied) must be a list of strings")397 398        # add include dirs for class399        include_dirs += self.__class__.include_dirs400 401        return output_dir, macros, include_dirs402 403    def _prep_compile(self, sources, output_dir, depends=None):404        """Decide which source files must be recompiled.405 406        Determine the list of object files corresponding to 'sources',407        and figure out which ones really need to be recompiled.408        Return a list of all object files and a dictionary telling409        which source files can be skipped.410        """411        # Get the list of expected output (object) files412        objects = self.object_filenames(sources, output_dir=output_dir)413        assert len(objects) == len(sources)414 415        # Return an empty dict for the "which source files can be skipped"416        # return value to preserve API compatibility.417        return objects, {}418 419    def _fix_object_args(self, objects, output_dir):420        """Typecheck and fix up some arguments supplied to various methods.421        Specifically: ensure that 'objects' is a list; if output_dir is422        None, replace with self.output_dir.  Return fixed versions of423        'objects' and 'output_dir'.424        """425        if not isinstance(objects, (list, tuple)):426            raise TypeError("'objects' must be a list or tuple of strings")427        objects = list(objects)428 429        if output_dir is None:430            output_dir = self.output_dir431        elif not isinstance(output_dir, str):432            raise TypeError("'output_dir' must be a string or None")433 434        return (objects, output_dir)435 436    def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs):437        """Typecheck and fix up some of the arguments supplied to the438        'link_*' methods.  Specifically: ensure that all arguments are439        lists, and augment them with their permanent versions440        (eg. 'self.libraries' augments 'libraries').  Return a tuple with441        fixed versions of all arguments.442        """443        if libraries is None:444            libraries = list(self.libraries)445        elif isinstance(libraries, (list, tuple)):446            libraries = list(libraries) + (self.libraries or [])447        else:448            raise TypeError("'libraries' (if supplied) must be a list of strings")449 450        if library_dirs is None:451            library_dirs = list(self.library_dirs)452        elif isinstance(library_dirs, (list, tuple)):453            library_dirs = list(library_dirs) + (self.library_dirs or [])454        else:455            raise TypeError("'library_dirs' (if supplied) must be a list of strings")456 457        # add library dirs for class458        library_dirs += self.__class__.library_dirs459 460        if runtime_library_dirs is None:461            runtime_library_dirs = list(self.runtime_library_dirs)462        elif isinstance(runtime_library_dirs, (list, tuple)):463            runtime_library_dirs = list(runtime_library_dirs) + (464                self.runtime_library_dirs or []465            )466        else:467            raise TypeError(468                "'runtime_library_dirs' (if supplied) must be a list of strings"469            )470 471        return (libraries, library_dirs, runtime_library_dirs)472 473    def _need_link(self, objects, output_file):474        """Return true if we need to relink the files listed in 'objects'475        to recreate 'output_file'.476        """477        if self.force:478            return True479        else:480            if self.dry_run:481                newer = newer_group(objects, output_file, missing='newer')482            else:483                newer = newer_group(objects, output_file)484            return newer485 486    def detect_language(self, sources):487        """Detect the language of a given file, or list of files. Uses488        language_map, and language_order to do the job.489        """490        if not isinstance(sources, list):491            sources = [sources]492        lang = None493        index = len(self.language_order)494        for source in sources:495            base, ext = os.path.splitext(source)496            extlang = self.language_map.get(ext)497            try:498                extindex = self.language_order.index(extlang)499                if extindex < index:500                    lang = extlang501                    index = extindex502            except ValueError:503                pass504        return lang505 506    # -- Worker methods ------------------------------------------------507    # (must be implemented by subclasses)508 509    def preprocess(510        self,511        source,512        output_file=None,513        macros=None,514        include_dirs=None,515        extra_preargs=None,516        extra_postargs=None,517    ):518        """Preprocess a single C/C++ source file, named in 'source'.519        Output will be written to file named 'output_file', or stdout if520        'output_file' not supplied.  'macros' is a list of macro521        definitions as for 'compile()', which will augment the macros set522        with 'define_macro()' and 'undefine_macro()'.  'include_dirs' is a523        list of directory names that will be added to the default list.524 525        Raises PreprocessError on failure.526        """527        pass528 529    def compile(530        self,531        sources,532        output_dir=None,533        macros=None,534        include_dirs=None,535        debug=0,536        extra_preargs=None,537        extra_postargs=None,538        depends=None,539    ):540        """Compile one or more source files.541 542        'sources' must be a list of filenames, most likely C/C++543        files, but in reality anything that can be handled by a544        particular compiler and compiler class (eg. MSVCCompiler can545        handle resource files in 'sources').  Return a list of object546        filenames, one per source filename in 'sources'.  Depending on547        the implementation, not all source files will necessarily be548        compiled, but all corresponding object filenames will be549        returned.550 551        If 'output_dir' is given, object files will be put under it, while552        retaining their original path component.  That is, "foo/bar.c"553        normally compiles to "foo/bar.o" (for a Unix implementation); if554        'output_dir' is "build", then it would compile to555        "build/foo/bar.o".556 557        'macros', if given, must be a list of macro definitions.  A macro558        definition is either a (name, value) 2-tuple or a (name,) 1-tuple.559        The former defines a macro; if the value is None, the macro is560        defined without an explicit value.  The 1-tuple case undefines a561        macro.  Later definitions/redefinitions/ undefinitions take562        precedence.563 564        'include_dirs', if given, must be a list of strings, the565        directories to add to the default include file search path for this566        compilation only.567 568        'debug' is a boolean; if true, the compiler will be instructed to569        output debug symbols in (or alongside) the object file(s).570 571        'extra_preargs' and 'extra_postargs' are implementation- dependent.572        On platforms that have the notion of a command-line (e.g. Unix,573        DOS/Windows), they are most likely lists of strings: extra574        command-line arguments to prepend/append to the compiler command575        line.  On other platforms, consult the implementation class576        documentation.  In any event, they are intended as an escape hatch577        for those occasions when the abstract compiler framework doesn't578        cut the mustard.579 580        'depends', if given, is a list of filenames that all targets581        depend on.  If a source file is older than any file in582        depends, then the source file will be recompiled.  This583        supports dependency tracking, but only at a coarse584        granularity.585 586        Raises CompileError on failure.587        """588        # A concrete compiler class can either override this method589        # entirely or implement _compile().590        macros, objects, extra_postargs, pp_opts, build = self._setup_compile(591            output_dir, macros, include_dirs, sources, depends, extra_postargs592        )593        cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)594 595        for obj in objects:596            try:597                src, ext = build[obj]598            except KeyError:599                continue600            self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)601 602        # Return *all* object filenames, not just the ones we just built.603        return objects604 605    def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):606        """Compile 'src' to product 'obj'."""607        # A concrete compiler class that does not override compile()608        # should implement _compile().609        pass610 611    def create_static_lib(612        self, objects, output_libname, output_dir=None, debug=0, target_lang=None613    ):614        """Link a bunch of stuff together to create a static library file.615        The "bunch of stuff" consists of the list of object files supplied616        as 'objects', the extra object files supplied to617        'add_link_object()' and/or 'set_link_objects()', the libraries618        supplied to 'add_library()' and/or 'set_libraries()', and the619        libraries supplied as 'libraries' (if any).620 621        'output_libname' should be a library name, not a filename; the622        filename will be inferred from the library name.  'output_dir' is623        the directory where the library file will be put.624 625        'debug' is a boolean; if true, debugging information will be626        included in the library (note that on most platforms, it is the627        compile step where this matters: the 'debug' flag is included here628        just for consistency).629 630        'target_lang' is the target language for which the given objects631        are being compiled. This allows specific linkage time treatment of632        certain languages.633 634        Raises LibError on failure.635        """636        pass637 638    # values for target_desc parameter in link()639    SHARED_OBJECT = "shared_object"640    SHARED_LIBRARY = "shared_library"641    EXECUTABLE = "executable"642 643    def link(644        self,645        target_desc,646        objects,647        output_filename,648        output_dir=None,649        libraries=None,650        library_dirs=None,651        runtime_library_dirs=None,652        export_symbols=None,653        debug=0,654        extra_preargs=None,655        extra_postargs=None,656        build_temp=None,657        target_lang=None,658    ):659        """Link a bunch of stuff together to create an executable or660        shared library file.661 662        The "bunch of stuff" consists of the list of object files supplied663        as 'objects'.  'output_filename' should be a filename.  If664        'output_dir' is supplied, 'output_filename' is relative to it665        (i.e. 'output_filename' can provide directory components if666        needed).667 668        'libraries' is a list of libraries to link against.  These are669        library names, not filenames, since they're translated into670        filenames in a platform-specific way (eg. "foo" becomes "libfoo.a"671        on Unix and "foo.lib" on DOS/Windows).  However, they can include a672        directory component, which means the linker will look in that673        specific directory rather than searching all the normal locations.674 675        'library_dirs', if supplied, should be a list of directories to676        search for libraries that were specified as bare library names677        (ie. no directory component).  These are on top of the system678        default and those supplied to 'add_library_dir()' and/or679        'set_library_dirs()'.  'runtime_library_dirs' is a list of680        directories that will be embedded into the shared library and used681        to search for other shared libraries that *it* depends on at682        run-time.  (This may only be relevant on Unix.)683 684        'export_symbols' is a list of symbols that the shared library will685        export.  (This appears to be relevant only on Windows.)686 687        'debug' is as for 'compile()' and 'create_static_lib()', with the688        slight distinction that it actually matters on most platforms (as689        opposed to 'create_static_lib()', which includes a 'debug' flag690        mostly for form's sake).691 692        'extra_preargs' and 'extra_postargs' are as for 'compile()' (except693        of course that they supply command-line arguments for the694        particular linker being used).695 696        'target_lang' is the target language for which the given objects697        are being compiled. This allows specific linkage time treatment of698        certain languages.699 700        Raises LinkError on failure.701        """702        raise NotImplementedError703 704    # Old 'link_*()' methods, rewritten to use the new 'link()' method.705 706    def link_shared_lib(707        self,708        objects,709        output_libname,710        output_dir=None,711        libraries=None,712        library_dirs=None,713        runtime_library_dirs=None,714        export_symbols=None,715        debug=0,716        extra_preargs=None,717        extra_postargs=None,718        build_temp=None,719        target_lang=None,720    ):721        self.link(722            CCompiler.SHARED_LIBRARY,723            objects,724            self.library_filename(output_libname, lib_type='shared'),725            output_dir,726            libraries,727            library_dirs,728            runtime_library_dirs,729            export_symbols,730            debug,731            extra_preargs,732            extra_postargs,733            build_temp,734            target_lang,735        )736 737    def link_shared_object(738        self,739        objects,740        output_filename,741        output_dir=None,742        libraries=None,743        library_dirs=None,744        runtime_library_dirs=None,745        export_symbols=None,746        debug=0,747        extra_preargs=None,748        extra_postargs=None,749        build_temp=None,750        target_lang=None,751    ):752        self.link(753            CCompiler.SHARED_OBJECT,754            objects,755            output_filename,756            output_dir,757            libraries,758            library_dirs,759            runtime_library_dirs,760            export_symbols,761            debug,762            extra_preargs,763            extra_postargs,764            build_temp,765            target_lang,766        )767 768    def link_executable(769        self,770        objects,771        output_progname,772        output_dir=None,773        libraries=None,774        library_dirs=None,775        runtime_library_dirs=None,776        debug=0,777        extra_preargs=None,778        extra_postargs=None,779        target_lang=None,780    ):781        self.link(782            CCompiler.EXECUTABLE,783            objects,784            self.executable_filename(output_progname),785            output_dir,786            libraries,787            library_dirs,788            runtime_library_dirs,789            None,790            debug,791            extra_preargs,792            extra_postargs,793            None,794            target_lang,795        )796 797    # -- Miscellaneous methods -----------------------------------------798    # These are all used by the 'gen_lib_options() function; there is799    # no appropriate default implementation so subclasses should800    # implement all of these.801 802    def library_dir_option(self, dir):803        """Return the compiler option to add 'dir' to the list of804        directories searched for libraries.805        """806        raise NotImplementedError807 808    def runtime_library_dir_option(self, dir):809        """Return the compiler option to add 'dir' to the list of810        directories searched for runtime libraries.811        """812        raise NotImplementedError813 814    def library_option(self, lib):815        """Return the compiler option to add 'lib' to the list of libraries816        linked into the shared library or executable.817        """818        raise NotImplementedError819 820    def has_function(  # noqa: C901821        self,822        funcname,823        includes=None,824        include_dirs=None,825        libraries=None,826        library_dirs=None,827    ):828        """Return a boolean indicating whether funcname is provided as829        a symbol on the current platform.  The optional arguments can830        be used to augment the compilation environment.831 832        The libraries argument is a list of flags to be passed to the833        linker to make additional symbol definitions available for834        linking.835 836        The includes and include_dirs arguments are deprecated.837        Usually, supplying include files with function declarations838        will cause function detection to fail even in cases where the839        symbol is available for linking.840 841        """842        # this can't be included at module scope because it tries to843        # import math which might not be available at that point - maybe844        # the necessary logic should just be inlined?845        import tempfile846 847        if includes is None:848            includes = []849        else:850            warnings.warn("includes is deprecated", DeprecationWarning)851        if include_dirs is None:852            include_dirs = []853        else:854            warnings.warn("include_dirs is deprecated", DeprecationWarning)855        if libraries is None:856            libraries = []857        if library_dirs is None:858            library_dirs = []859        fd, fname = tempfile.mkstemp(".c", funcname, text=True)860        with os.fdopen(fd, "w", encoding='utf-8') as f:861            for incl in includes:862                f.write("""#include "%s"\n""" % incl)863            if not includes:864                # Use "char func(void);" as the prototype to follow865                # what autoconf does.  This prototype does not match866                # any well-known function the compiler might recognize867                # as a builtin, so this ends up as a true link test.868                # Without a fake prototype, the test would need to869                # know the exact argument types, and the has_function870                # interface does not provide that level of information.871                f.write(872                    """\873#ifdef __cplusplus874extern "C"875#endif876char %s(void);877"""878                    % funcname879                )880            f.write(881                """\882int main (int argc, char **argv) {883    %s();884    return 0;885}886"""887                % funcname888            )889 890        try:891            objects = self.compile([fname], include_dirs=include_dirs)892        except CompileError:893            return False894        finally:895            os.remove(fname)896 897        try:898            self.link_executable(899                objects, "a.out", libraries=libraries, library_dirs=library_dirs900            )901        except (LinkError, TypeError):902            return False903        else:904            os.remove(905                self.executable_filename("a.out", output_dir=self.output_dir or '')906            )907        finally:908            for fn in objects:909                os.remove(fn)910        return True911 912    def find_library_file(self, dirs, lib, debug=0):913        """Search the specified list of directories for a static or shared914        library file 'lib' and return the full path to that file.  If915        'debug' true, look for a debugging version (if that makes sense on916        the current platform).  Return None if 'lib' wasn't found in any of917        the specified directories.918        """919        raise NotImplementedError920 921    # -- Filename generation methods -----------------------------------922 923    # The default implementation of the filename generating methods are924    # prejudiced towards the Unix/DOS/Windows view of the world:925    #   * object files are named by replacing the source file extension926    #     (eg. .c/.cpp -> .o/.obj)927    #   * library files (shared or static) are named by plugging the928    #     library name and extension into a format string, eg.929    #     "lib%s.%s" % (lib_name, ".a") for Unix static libraries930    #   * executables are named by appending an extension (possibly931    #     empty) to the program name: eg. progname + ".exe" for932    #     Windows933    #934    # To reduce redundant code, these methods expect to find935    # several attributes in the current object (presumably defined936    # as class attributes):937    #   * src_extensions -938    #     list of C/C++ source file extensions, eg. ['.c', '.cpp']939    #   * obj_extension -940    #     object file extension, eg. '.o' or '.obj'941    #   * static_lib_extension -942    #     extension for static library files, eg. '.a' or '.lib'943    #   * shared_lib_extension -944    #     extension for shared library/object files, eg. '.so', '.dll'945    #   * static_lib_format -946    #     format string for generating static library filenames,947    #     eg. 'lib%s.%s' or '%s.%s'948    #   * shared_lib_format949    #     format string for generating shared library filenames950    #     (probably same as static_lib_format, since the extension951    #     is one of the intended parameters to the format string)952    #   * exe_extension -953    #     extension for executable files, eg. '' or '.exe'954 955    def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):956        if output_dir is None:957            output_dir = ''958        return list(959            self._make_out_path(output_dir, strip_dir, src_name)960            for src_name in source_filenames961        )962 963    @property964    def out_extensions(self):965        return dict.fromkeys(self.src_extensions, self.obj_extension)966 967    def _make_out_path(self, output_dir, strip_dir, src_name):968        base, ext = os.path.splitext(src_name)969        base = self._make_relative(base)970        try:971            new_ext = self.out_extensions[ext]972        except LookupError:973            raise UnknownFileError(f"unknown file type '{ext}' (from '{src_name}')")974        if strip_dir:975            base = os.path.basename(base)976        return os.path.join(output_dir, base + new_ext)977 978    @staticmethod979    def _make_relative(base):980        """981        In order to ensure that a filename always honors the982        indicated output_dir, make sure it's relative.983        Ref python/cpython#37775.984        """985        # Chop off the drive986        no_drive = os.path.splitdrive(base)[1]987        # If abs, chop off leading /988        return no_drive[os.path.isabs(no_drive) :]989 990    def shared_object_filename(self, basename, strip_dir=0, output_dir=''):991        assert output_dir is not None992        if strip_dir:993            basename = os.path.basename(basename)994        return os.path.join(output_dir, basename + self.shared_lib_extension)995 996    def executable_filename(self, basename, strip_dir=0, output_dir=''):997        assert output_dir is not None998        if strip_dir:999            basename = os.path.basename(basename)1000        return os.path.join(output_dir, basename + (self.exe_extension or ''))1001 1002    def library_filename(1003        self,1004        libname,1005        lib_type='static',1006        strip_dir=0,1007        output_dir='',  # or 'shared'1008    ):1009        assert output_dir is not None1010        expected = '"static", "shared", "dylib", "xcode_stub"'1011        if lib_type not in eval(expected):1012            raise ValueError(f"'lib_type' must be {expected}")1013        fmt = getattr(self, lib_type + "_lib_format")1014        ext = getattr(self, lib_type + "_lib_extension")1015 1016        dir, base = os.path.split(libname)1017        filename = fmt % (base, ext)1018        if strip_dir:1019            dir = ''1020 1021        return os.path.join(output_dir, dir, filename)1022 1023    # -- Utility methods -----------------------------------------------1024 1025    def announce(self, msg, level=1):1026        log.debug(msg)1027 1028    def debug_print(self, msg):1029        from distutils.debug import DEBUG1030 1031        if DEBUG:1032            print(msg)1033 1034    def warn(self, msg):1035        sys.stderr.write("warning: %s\n" % msg)1036 1037    def execute(self, func, args, msg=None, level=1):1038        execute(func, args, msg, self.dry_run)1039 1040    def spawn(self, cmd, **kwargs):1041        spawn(cmd, dry_run=self.dry_run, **kwargs)1042 1043    def move_file(self, src, dst):1044        return move_file(src, dst, dry_run=self.dry_run)1045 1046    def mkpath(self, name, mode=0o777):1047        mkpath(name, mode, dry_run=self.dry_run)1048 1049 1050# Map a sys.platform/os.name ('posix', 'nt') to the default compiler1051# type for that platform. Keys are interpreted as re match1052# patterns. Order is important; platform mappings are preferred over1053# OS names.1054_default_compilers = (1055    # Platform string mappings1056    # on a cygwin built python we can use gcc like an ordinary UNIXish1057    # compiler1058    ('cygwin.*', 'unix'),1059    ('zos', 'zos'),1060    # OS name mappings1061    ('posix', 'unix'),1062    ('nt', 'msvc'),1063)1064 1065 1066def get_default_compiler(osname=None, platform=None):1067    """Determine the default compiler to use for the given platform.1068 1069    osname should be one of the standard Python OS names (i.e. the1070    ones returned by os.name) and platform the common value1071    returned by sys.platform for the platform in question.1072 1073    The default values are os.name and sys.platform in case the1074    parameters are not given.1075    """1076    if osname is None:1077        osname = os.name1078    if platform is None:1079        platform = sys.platform1080    for pattern, compiler in _default_compilers:1081        if (1082            re.match(pattern, platform) is not None1083            or re.match(pattern, osname) is not None1084        ):1085            return compiler1086    # Default to Unix compiler1087    return 'unix'1088 1089 1090# Map compiler types to (module_name, class_name) pairs -- ie. where to1091# find the code that implements an interface to this compiler.  (The module1092# is assumed to be in the 'distutils' package.)1093compiler_class = {1094    'unix': ('unixccompiler', 'UnixCCompiler', "standard UNIX-style compiler"),1095    'msvc': ('_msvccompiler', 'MSVCCompiler', "Microsoft Visual C++"),1096    'cygwin': (1097        'cygwinccompiler',1098        'CygwinCCompiler',1099        "Cygwin port of GNU C Compiler for Win32",1100    ),1101    'mingw32': (1102        'cygwinccompiler',1103        'Mingw32CCompiler',1104        "Mingw32 port of GNU C Compiler for Win32",1105    ),1106    'bcpp': ('bcppcompiler', 'BCPPCompiler', "Borland C++ Compiler"),1107    'zos': ('zosccompiler', 'zOSCCompiler', 'IBM XL C/C++ Compilers'),1108}1109 1110 1111def show_compilers():1112    """Print list of available compilers (used by the "--help-compiler"1113    options to "build", "build_ext", "build_clib").1114    """1115    # XXX this "knows" that the compiler option it's describing is1116    # "--compiler", which just happens to be the case for the three1117    # commands that use it.1118    from distutils.fancy_getopt import FancyGetopt1119 1120    compilers = []1121    for compiler in compiler_class.keys():1122        compilers.append(("compiler=" + compiler, None, compiler_class[compiler][2]))1123    compilers.sort()1124    pretty_printer = FancyGetopt(compilers)1125    pretty_printer.print_help("List of available compilers:")1126 1127 1128def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):1129    """Generate an instance of some CCompiler subclass for the supplied1130    platform/compiler combination.  'plat' defaults to 'os.name'1131    (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler1132    for that platform.  Currently only 'posix' and 'nt' are supported, and1133    the default compilers are "traditional Unix interface" (UnixCCompiler1134    class) and Visual C++ (MSVCCompiler class).  Note that it's perfectly1135    possible to ask for a Unix compiler object under Windows, and a1136    Microsoft compiler object under Unix -- if you supply a value for1137    'compiler', 'plat' is ignored.1138    """1139    if plat is None:1140        plat = os.name1141 1142    try:1143        if compiler is None:1144            compiler = get_default_compiler(plat)1145 1146        (module_name, class_name, long_description) = compiler_class[compiler]1147    except KeyError:1148        msg = "don't know how to compile C/C++ code on platform '%s'" % plat1149        if compiler is not None:1150            msg = msg + " with '%s' compiler" % compiler1151        raise DistutilsPlatformError(msg)1152 1153    try:1154        module_name = "distutils." + module_name1155        __import__(module_name)1156        module = sys.modules[module_name]1157        klass = vars(module)[class_name]1158    except ImportError:1159        raise DistutilsModuleError(1160            "can't compile C/C++ code: unable to load module '%s'" % module_name1161        )1162    except KeyError:1163        raise DistutilsModuleError(1164            f"can't compile C/C++ code: unable to find class '{class_name}' "1165            f"in module '{module_name}'"1166        )1167 1168    # XXX The None is necessary to preserve backwards compatibility1169    # with classes that expect verbose to be the first positional1170    # argument.1171    return klass(None, dry_run, force)1172 1173 1174def gen_preprocess_options(macros, include_dirs):1175    """Generate C pre-processor options (-D, -U, -I) as used by at least1176    two types of compilers: the typical Unix compiler and Visual C++.1177    'macros' is the usual thing, a list of 1- or 2-tuples, where (name,)1178    means undefine (-U) macro 'name', and (name,value) means define (-D)1179    macro 'name' to 'value'.  'include_dirs' is just a list of directory1180    names to be added to the header file search path (-I).  Returns a list1181    of command-line options suitable for either Unix compilers or Visual1182    C++.1183    """1184    # XXX it would be nice (mainly aesthetic, and so we don't generate1185    # stupid-looking command lines) to go over 'macros' and eliminate1186    # redundant definitions/undefinitions (ie. ensure that only the1187    # latest mention of a particular macro winds up on the command1188    # line).  I don't think it's essential, though, since most (all?)1189    # Unix C compilers only pay attention to the latest -D or -U1190    # mention of a macro on their command line.  Similar situation for1191    # 'include_dirs'.  I'm punting on both for now.  Anyways, weeding out1192    # redundancies like this should probably be the province of1193    # CCompiler, since the data structures used are inherited from it1194    # and therefore common to all CCompiler classes.1195    pp_opts = []1196    for macro in macros:1197        if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2):1198            raise TypeError(1199                "bad macro definition '%s': "1200                "each element of 'macros' list must be a 1- or 2-tuple" % macro

Showing the first 1,200 of 1253 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai