distutils ccompiler contains ccompiler an abstract base class that defines the interface for the distutils compiler abstraction model import sys os re from distutils errors import distutilsmoduleerror distutilsplatformerror from distutils util import splitquoted class ccompiler compilertype is a class attribute that identifies this class it keeps code that wants to know what kind of compiler it s dealing with from having to import all possible compiler classes just to do an isinstance in concrete ccompiler subclasses compilertype should really really be one of the keys of the compilerclass dictionary see below used by the newcompiler factory function s of new compiler interface classes are responsible for updating compilerclass compilertype none xxx things not handled by this compiler abstraction model client can t provide additional options for a compiler e g warning optimization debugging flags perhaps this should be the domain of concrete compiler abstraction classes unixccompiler msvccompiler etc or perhaps the base class should have methods for the common ones can t completely override the include or library searchg path ie no cc i idir1 idir2 or cc l ldir1 ldir2 i m not sure how widely supported this is even by unix compilers much less on other platforms and i m even less sure how useful it is maybe for crosscompiling but support for that is a ways off and anyways cross compilers probably have a dedicated binary with the right paths compiled in i hope can t do really freaky things with the library listlibrary dirs e g ldir1 lfoo ldir2 lfoo to link against different versions of libfoo a in different locations i think this is useless without the ability to null out the library search path anyways subclasses that rely on the standard filename generation methods implemented below should override these see the comment near those methods objectfilenames et al for details srcextensions none list of strings objextension none string staticlibextension none sharedlibextension none string staticlibformat none format string sharedlibformat none prob same as staticlibformat exeextension none string default language settings languagemap is used to detect a source file or extension target language checking source filenames languageorder is used to detect the language precedence when deciding what language to use when mixing source types for example if some extension has two files with c extension and one with cpp it is still linked as c languagemap c c cc c cpp c cxx c m objc languageorder c objc c def initself verbose0 dryrun0 force0 self dryrun dryrun self force force self verbose verbose outputdir a common output directory for object library shared object and shared library files self outputdir none macros a list of macro definitions or undefinitions a macro definition is a 2tuple name value where the value is either a string or none no explicit value a macro undefinition is a 1tuple name self macros includedirs a list of directories to search for include files self includedirs libraries a list of libraries to include in any link library names not filenames eg foo not libfoo a self libraries librarydirs a list of directories to search for libraries self librarydirs runtimelibrarydirs a list of directories to search for shared librariesobjects at runtime self runtimelibrarydirs objects a list of object files or similar such as explicitly named library files to include on any link self objects for key in self executables keys self setexecutablekey self executableskey def setexecutablesself kwargs note that some ccompiler implementation classes will define class attributes cpp cc etc with hardcoded executable names this is appropriate when a compiler class is for exactly one compileros combination eg msvccompiler other compiler classes unixccompiler in particular are driven by information discovered at runtime since there are many different ways to do basically the same things with unix c compilers for key in kwargs if key not in self executables raise valueerrorunknown executable s for class s key self class name self setexecutablekey kwargskey def setexecutableself key value if isinstancevalue str setattrself key splitquotedvalue else setattrself key value def findmacroself name i 0 for defn in self macros if defn0 name return i i 1 return none def checkmacrodefinitionsself definitions for defn in definitions if not isinstancedefn tuple and lendefn in 1 2 and isinstance defn1 str or defn1 is none and isinstance defn0 str raise typeerrorinvalid macro definition s defn must be tuple string string string or string none bookkeeping methods def definemacroself name valuenone delete from the list of macro definitionsundefinitions if already there so that this one will take precedence i self findmacro name if i is not none del self macrosi self macros appendname value def undefinemacroself name delete from the list of macro definitionsundefinitions if already there so that this one will take precedence i self findmacro name if i is not none del self macrosi undefn name self macros appendundefn def addincludedirself dir self includedirs appenddir def setincludedirsself dirs self includedirs dirs private utility methods here for the convenience of subclasses helper method to prep compiler in subclass compile methods def fixcompileargsself outputdir macros includedirs if outputdir is none outputdir self outputdir elif not isinstanceoutputdir str raise typeerror outputdir must be a string or none if macros is none macros self macros elif isinstancemacros list macros macros self macros or else raise typeerror macros if supplied must be a list of tuples if includedirs is none includedirs self includedirs elif isinstanceincludedirs list tuple includedirs listincludedirs self includedirs or else raise typeerror includedirs if supplied must be a list of strings return outputdir macros includedirs worker methods must be implemented by subclasses def preprocessself source outputfilenone macrosnone includedirsnone extrapreargsnone extrapostargsnone pass miscellaneous methods these are all used by the genliboptions function there is no appropriate default implementation so subclasses should implement all of these def librarydiroptionself dir return the compiler option to add dir to the list of directories searched for libraries raise notimplementederror def runtimelibrarydiroptionself dir return the compiler option to add dir to the list of directories searched for runtime libraries raise notimplementederror def libraryoptionself lib return the compiler option to add lib to the list of libraries linked into the shared library or executable raise notimplementederror def findlibraryfile self dirs lib debug0 search the specified list of directories for a static or shared library file lib and return the full path to that file if debug true look for a debugging version if that makes sense on the current platform return none if lib wasn t found in any of the specified directories raise notimplementederror utility methods def spawnself cmd raise notimplementederror map a sys platformos name posix nt to the default compiler type for that platform keys are interpreted as re match patterns order is important platform mappings are preferred over os names defaultcompilers platform string mappings on a cygwin built python we can use gcc like an ordinary unixish compiler cygwin unix os name mappings posix unix nt msvc def getdefaultcompilerosnamenone platformnone if osname is none osname os name if platform is none platform sys platform for pattern compiler in defaultcompilers if re matchpattern platform is not none or re matchpattern osname is not none return compiler default to unix compiler return unix map compiler types to modulename classname pairs ie where to find the code that implements an interface to this compiler the module is assumed to be in the distutils package compilerclass unix unixccompiler unixccompiler standard unixstyle compiler msvc msvccompiler msvccompiler microsoft visual c cygwin cygwinccompiler cygwinccompiler cygwin port of gnu c compiler for win32 mingw32 cygwinccompiler mingw32ccompiler mingw32 port of gnu c compiler for win32 bcpp bcppcompiler bcppcompiler borland c compiler def newcompilerplatnone compilernone verbose0 dryrun0 force0 if plat is none plat os name try if compiler is none compiler getdefaultcompilerplat modulename classname longdescription compilerclasscompiler except keyerror msg don t know how to compile cc code on platform s plat if compiler is not none msg msg with s compiler compiler raise distutilsplatformerrormsg try modulename distutils modulename import modulename module sys modulesmodulename klass varsmoduleclassname except importerror raise raise distutilsmoduleerror can t compile cc code unable to load module s modulename except keyerror raise distutilsmoduleerror can t compile cc code unable to find class s in module s classname modulename xxx the none is necessary to preserve backwards compatibility with classes that expect verbose to be the first positional argument return klassnone dryrun force def genpreprocessoptionsmacros includedirs xxx it would be nice mainly aesthetic and so we don t generate stupidlooking command lines to go over macros and eliminate redundant definitionsundefinitions ie ensure that only the latest mention of a particular macro winds up on the command line i don t think it s essential though since most all unix c compilers only pay attention to the latest d or u mention of a macro on their command line similar situation for includedirs i m punting on both for now anyways weeding out redundancies like this should probably be the province of ccompiler since the data structures used are inherited from it and therefore common to all ccompiler classes ppopts for macro in macros if not isinstancemacro tuple and 1 lenmacro 2 raise typeerror bad macro definition s each element of macros list must be a 1 or 2tuple macro if lenmacro 1 undefine this macro ppopts appendus macro0 elif lenmacro 2 if macro1 is none define with no explicit value ppopts appendds macro0 else xxx don t need to be clever about quoting the macro value here because we re going to avoid the shell at all costs when we spawn the command ppopts appenddss macro for dir in includedirs ppopts appendis dir return ppopts abstract base class to define the interface that must be implemented by real compiler classes also has some utility methods used by several compiler classes the basic idea behind a compiler abstraction class is that each instance can be used for all the compile link steps in building a single project thus attributes common to all of those compile and link steps include directories macros to define libraries to link against etc are attributes of the compiler instance to allow for variability in how individual files are treated most of those attributes may be varied on a per compilation or per link basis compiler_type is a class attribute that identifies this class it keeps code that wants to know what kind of compiler it s dealing with from having to import all possible compiler classes just to do an isinstance in concrete ccompiler subclasses compiler_type should really really be one of the keys of the compiler_class dictionary see below used by the new_compiler factory function s of new compiler interface classes are responsible for updating compiler_class xxx things not handled by this compiler abstraction model client can t provide additional options for a compiler e g warning optimization debugging flags perhaps this should be the domain of concrete compiler abstraction classes unixccompiler msvccompiler etc or perhaps the base class should have methods for the common ones can t completely override the include or library searchg path ie no cc i idir1 idir2 or cc l ldir1 ldir2 i m not sure how widely supported this is even by unix compilers much less on other platforms and i m even less sure how useful it is maybe for cross compiling but support for that is a ways off and anyways cross compilers probably have a dedicated binary with the right paths compiled in i hope can t do really freaky things with the library list library dirs e g ldir1 lfoo ldir2 lfoo to link against different versions of libfoo a in different locations i think this is useless without the ability to null out the library search path anyways subclasses that rely on the standard filename generation methods implemented below should override these see the comment near those methods object_filenames et al for details list of strings string string format string prob same as static_lib_format string default language settings language_map is used to detect a source file or extension target language checking source filenames language_order is used to detect the language precedence when deciding what language to use when mixing source types for example if some extension has two files with c extension and one with cpp it is still linked as c output_dir a common output directory for object library shared object and shared library files macros a list of macro definitions or undefinitions a macro definition is a 2 tuple name value where the value is either a string or none no explicit value a macro undefinition is a 1 tuple name include_dirs a list of directories to search for include files libraries a list of libraries to include in any link library names not filenames eg foo not libfoo a library_dirs a list of directories to search for libraries runtime_library_dirs a list of directories to search for shared libraries objects at runtime objects a list of object files or similar such as explicitly named library files to include on any link define the executables and options for them that will be run to perform the various stages of compilation the exact set of executables that may be specified here depends on the compiler class via the executables class attribute but most will have compiler the c c compiler linker_so linker used to create shared objects and libraries linker_exe linker used to create binary executables archiver static library creator on platforms with a command line unix dos windows each of these is a string that will be split into executable name and optional list of arguments splitting the string is done similarly to how unix shells operate words are delimited by spaces but quotes and backslashes can override this see distutils util split_quoted note that some ccompiler implementation classes will define class attributes cpp cc etc with hard coded executable names this is appropriate when a compiler class is for exactly one compiler os combination eg msvccompiler other compiler classes unixccompiler in particular are driven by information discovered at run time since there are many different ways to do basically the same things with unix c compilers ensures that every element of definitions is a valid macro definition ie either name value 2 tuple or a name tuple do nothing if all definitions are ok raise typeerror otherwise bookkeeping methods define a preprocessor macro for all compilations driven by this compiler object the optional parameter value should be a string if it is not supplied then the macro will be defined without an explicit value and the exact outcome depends on the compiler used xxx true does ansi say anything about this delete from the list of macro definitions undefinitions if already there so that this one will take precedence undefine a preprocessor macro for all compilations driven by this compiler object if the same macro is defined by define_macro and undefined by undefine_macro the last call takes precedence including multiple redefinitions or undefinitions if the macro is redefined undefined on a per compilation basis ie in the call to compile then that takes precedence delete from the list of macro definitions undefinitions if already there so that this one will take precedence add dir to the list of directories that will be searched for header files the compiler is instructed to search directories in the order in which they are supplied by successive calls to add_include_dir set the list of directories that will be searched to dirs a list of strings overrides any preceding calls to add_include_dir subsequence calls to add_include_dir add to the list passed to set_include_dirs this does not affect any list of standard include directories that the compiler may search by default private utility methods here for the convenience of subclasses helper method to prep compiler in subclass compile methods typecheck and fix up some of the arguments to the compile method and return fixed up values specifically if output_dir is none replaces it with self output_dir ensures that macros is a list and augments it with self macros ensures that include_dirs is a list and augments it with self include_dirs guarantees that the returned values are of the correct type i e for output_dir either string or none and for macros and include_dirs either list or none worker methods must be implemented by subclasses preprocess a single c c source file named in source output will be written to file named output_file or stdout if output_file not supplied macros is a list of macro definitions as for compile which will augment the macros set with define_macro and undefine_macro include_dirs is a list of directory names that will be added to the default list raises preprocesserror on failure miscellaneous methods these are all used by the gen_lib_options function there is no appropriate default implementation so subclasses should implement all of these def library_dir_option self dir return the compiler option to add dir to the list of directories searched for libraries raise notimplementederror def runtime_library_dir_option self dir return the compiler option to add dir to the list of directories searched for runtime libraries raise notimplementederror def library_option self lib return the compiler option to add lib to the list of libraries linked into the shared library or executable raise notimplementederror def find_library_file self dirs lib debug 0 search the specified list of directories for a static or shared library file lib and return the full path to that file if debug true look for a debugging version if that makes sense on the current platform return none if lib wasn t found in any of the specified directories raise notimplementederror utility methods map a sys platform os name posix nt to the default compiler type for that platform keys are interpreted as re match patterns order is important platform mappings are preferred over os names platform string mappings on a cygwin built python we can use gcc like an ordinary unixish compiler os name mappings determine the default compiler to use for the given platform osname should be one of the standard python os names i e the ones returned by os name and platform the common value returned by sys platform for the platform in question the default values are os name and sys platform in case the parameters are not given default to unix compiler map compiler types to module_name class_name pairs ie where to find the code that implements an interface to this compiler the module is assumed to be in the distutils package generate an instance of some ccompiler subclass for the supplied platform compiler combination plat defaults to os name eg posix nt and compiler defaults to the default compiler for that platform currently only posix and nt are supported and the default compilers are traditional unix interface unixccompiler class and visual c msvccompiler class note that it s perfectly possible to ask for a unix compiler object under windows and a microsoft compiler object under unix if you supply a value for compiler plat is ignored xxx the none is necessary to preserve backwards compatibility with classes that expect verbose to be the first positional argument generate c pre processor options d u i as used by at least two types of compilers the typical unix compiler and visual c macros is the usual thing a list of 1 or 2 tuples where name means undefine u macro name and name value means define d macro name to value include_dirs is just a list of directory names to be added to the header file search path i returns a list of command line options suitable for either unix compilers or visual c xxx it would be nice mainly aesthetic and so we don t generate stupid looking command lines to go over macros and eliminate redundant definitions undefinitions ie ensure that only the latest mention of a particular macro winds up on the command line i don t think it s essential though since most all unix c compilers only pay attention to the latest d or u mention of a macro on their command line similar situation for include_dirs i m punting on both for now anyways weeding out redundancies like this should probably be the province of ccompiler since the data structures used are inherited from it and therefore common to all ccompiler classes undefine this macro define with no explicit value xxx don t need to be clever about quoting the macro value here because we re going to avoid the shell at all costs when we spawn the command
import sys, os, re
from distutils.errors import (
    DistutilsModuleError, DistutilsPlatformError,
)
from distutils.util import split_quoted

class CCompiler:
    

    
    
    
    
    
    
    
    
    compiler_type = None

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


    
    
    
    src_extensions = None               
    obj_extension = None                
    static_lib_extension = None
    shared_lib_extension = None         
    static_lib_format = None            
    shared_lib_format = None            
    exe_extension = None                

    
    
    
    
    
    
    language_map = {".c"   : "c",
                    ".cc"  : "c++",
                    ".cpp" : "c++",
                    ".cxx" : "c++",
                    ".m"   : "objc",
                   }
    language_order = ["c++", "objc", "c"]

    def __init__(self, verbose=0, dry_run=0, force=0):
        self.dry_run = dry_run
        self.force = force
        self.verbose = verbose

        
        
        self.output_dir = None

        
        
        
        
        self.macros = []

        
        self.include_dirs = []

        
        
        self.libraries = []

        
        self.library_dirs = []

        
        
        self.runtime_library_dirs = []

        
        
        self.objects = []

        for key in self.executables.keys():
            self.set_executable(key, self.executables[key])

    def set_executables(self, **kwargs):
        

        
        
        
        
        
        
        

        for key in kwargs:
            if key not in self.executables:
                raise ValueError("unknown executable '%s' for class %s" %
                      (key, self.__class__.__name__))
            self.set_executable(key, kwargs[key])

    def set_executable(self, key, value):
        if isinstance(value, str):
            setattr(self, key, split_quoted(value))
        else:
            setattr(self, key, value)

    def _find_macro(self, name):
        i = 0
        for defn in self.macros:
            if defn[0] == name:
                return i
            i += 1
        return None

    def _check_macro_definitions(self, definitions):
        
        for defn in definitions:
            if not (isinstance(defn, tuple) and
                    (len(defn) in (1, 2) and
                      (isinstance (defn[1], str) or defn[1] is None)) and
                    isinstance (defn[0], str)):
                raise TypeError(("invalid macro definition '%s': " % defn) + \
                      "must be tuple (string,), (string, string), or " + \
                      "(string, None)")


    

    def define_macro(self, name, value=None):
        
        
        
        i = self._find_macro (name)
        if i is not None:
            del self.macros[i]

        self.macros.append((name, value))

    def undefine_macro(self, name):
        
        
        
        i = self._find_macro (name)
        if i is not None:
            del self.macros[i]

        undefn = (name,)
        self.macros.append(undefn)

    def add_include_dir(self, dir):
        
        self.include_dirs.append(dir)

    def set_include_dirs(self, dirs):
        
        self.include_dirs = dirs[:]


    
    

    

    def _fix_compile_args(self, output_dir, macros, include_dirs):
        
        if output_dir is None:
            output_dir = self.output_dir
        elif not isinstance(output_dir, str):
            raise TypeError("'output_dir' must be a string or None")

        if macros is None:
            macros = self.macros
        elif isinstance(macros, list):
            macros = macros + (self.macros or [])
        else:
            raise TypeError("'macros' (if supplied) must be a list of tuples")

        if include_dirs is None:
            include_dirs = self.include_dirs
        elif isinstance(include_dirs, (list, tuple)):
            include_dirs = list(include_dirs) + (self.include_dirs or [])
        else:
            raise TypeError(
                  "'include_dirs' (if supplied) must be a list of strings")

        return output_dir, macros, include_dirs


    
    

    def preprocess(self, source, output_file=None, macros=None,
                   include_dirs=None, extra_preargs=None, extra_postargs=None):
        
        pass


    
    
    
    





























    

    def spawn(self, cmd):
        raise NotImplementedError






_default_compilers = (

    

    
    
    ('cygwin.*', 'unix'),

    
    ('posix', 'unix'),
    ('nt', 'msvc'),

    )

def get_default_compiler(osname=None, platform=None):
    
    if osname is None:
        osname = os.name
    if platform is None:
        platform = sys.platform
    for pattern, compiler in _default_compilers:
        if re.match(pattern, platform) is not None or \
           re.match(pattern, osname) is not None:
            return compiler
    
    return 'unix'




compiler_class = { 'unix':    ('unixccompiler', 'UnixCCompiler',
                               "standard UNIX-style compiler"),
                   'msvc':    ('_msvccompiler', 'MSVCCompiler',
                               "Microsoft Visual C++"),
                   'cygwin':  ('cygwinccompiler', 'CygwinCCompiler',
                               "Cygwin port of GNU C Compiler for Win32"),
                   'mingw32': ('cygwinccompiler', 'Mingw32CCompiler',
                               "Mingw32 port of GNU C Compiler for Win32"),
                   'bcpp':    ('bcppcompiler', 'BCPPCompiler',
                               "Borland C++ Compiler"),
                 }


def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
    
    if plat is None:
        plat = os.name

    try:
        if compiler is None:
            compiler = get_default_compiler(plat)

        (module_name, class_name, long_description) = compiler_class[compiler]
    except KeyError:
        msg = "don't know how to compile C/C++ code on platform '%s'" % plat
        if compiler is not None:
            msg = msg + " with '%s' compiler" % compiler
        raise DistutilsPlatformError(msg)

    try:
        module_name = "distutils." + module_name
        __import__ (module_name)
        module = sys.modules[module_name]
        klass = vars(module)[class_name]
    except ImportError:
        raise
        raise DistutilsModuleError(
              "can't compile C/C++ code: unable to load module '%s'" % \
              module_name)
    except KeyError:
        raise DistutilsModuleError(
               "can't compile C/C++ code: unable to find class '%s' "
               "in module '%s'" % (class_name, module_name))

    
    
    
    return klass(None, dry_run, force)


def gen_preprocess_options(macros, include_dirs):
    
    
    
    
    
    
    
    
    
    
    
    
    pp_opts = []
    for macro in macros:
        if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2):
            raise TypeError(
                  "bad macro definition '%s': "
                  "each element of 'macros' list must be a 1- or 2-tuple"
                  % macro)

        if len(macro) == 1:        
            pp_opts.append("-U%s" % macro[0])
        elif len(macro) == 2:
            if macro[1] is None:    
                pp_opts.append("-D%s" % macro[0])
            else:
                
                
                
                pp_opts.append("-D%s=%s" % macro)

    for dir in include_dirs:
        pp_opts.append("-I%s" % dir)
    return pp_opts