1*cda5da8dSAndroid Build Coastguard Worker"""distutils.extension 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerProvides the Extension class, used to describe C/C++ extension 4*cda5da8dSAndroid Build Coastguard Workermodules in setup scripts.""" 5*cda5da8dSAndroid Build Coastguard Worker 6*cda5da8dSAndroid Build Coastguard Workerimport os 7*cda5da8dSAndroid Build Coastguard Workerimport re 8*cda5da8dSAndroid Build Coastguard Workerimport warnings 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard Worker# This class is really only used by the "build_ext" command, so it might 11*cda5da8dSAndroid Build Coastguard Worker# make sense to put it in distutils.command.build_ext. However, that 12*cda5da8dSAndroid Build Coastguard Worker# module is already big enough, and I want to make this class a bit more 13*cda5da8dSAndroid Build Coastguard Worker# complex to simplify some common cases ("foo" module in "foo.c") and do 14*cda5da8dSAndroid Build Coastguard Worker# better error-checking ("foo.c" actually exists). 15*cda5da8dSAndroid Build Coastguard Worker# 16*cda5da8dSAndroid Build Coastguard Worker# Also, putting this in build_ext.py means every setup script would have to 17*cda5da8dSAndroid Build Coastguard Worker# import that large-ish module (indirectly, through distutils.core) in 18*cda5da8dSAndroid Build Coastguard Worker# order to do anything. 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard Workerclass Extension: 21*cda5da8dSAndroid Build Coastguard Worker """Just a collection of attributes that describes an extension 22*cda5da8dSAndroid Build Coastguard Worker module and everything needed to build it (hopefully in a portable 23*cda5da8dSAndroid Build Coastguard Worker way, but there are hooks that let you be as unportable as you need). 24*cda5da8dSAndroid Build Coastguard Worker 25*cda5da8dSAndroid Build Coastguard Worker Instance attributes: 26*cda5da8dSAndroid Build Coastguard Worker name : string 27*cda5da8dSAndroid Build Coastguard Worker the full name of the extension, including any packages -- ie. 28*cda5da8dSAndroid Build Coastguard Worker *not* a filename or pathname, but Python dotted name 29*cda5da8dSAndroid Build Coastguard Worker sources : [string] 30*cda5da8dSAndroid Build Coastguard Worker list of source filenames, relative to the distribution root 31*cda5da8dSAndroid Build Coastguard Worker (where the setup script lives), in Unix form (slash-separated) 32*cda5da8dSAndroid Build Coastguard Worker for portability. Source files may be C, C++, SWIG (.i), 33*cda5da8dSAndroid Build Coastguard Worker platform-specific resource files, or whatever else is recognized 34*cda5da8dSAndroid Build Coastguard Worker by the "build_ext" command as source for a Python extension. 35*cda5da8dSAndroid Build Coastguard Worker include_dirs : [string] 36*cda5da8dSAndroid Build Coastguard Worker list of directories to search for C/C++ header files (in Unix 37*cda5da8dSAndroid Build Coastguard Worker form for portability) 38*cda5da8dSAndroid Build Coastguard Worker define_macros : [(name : string, value : string|None)] 39*cda5da8dSAndroid Build Coastguard Worker list of macros to define; each macro is defined using a 2-tuple, 40*cda5da8dSAndroid Build Coastguard Worker where 'value' is either the string to define it to or None to 41*cda5da8dSAndroid Build Coastguard Worker define it without a particular value (equivalent of "#define 42*cda5da8dSAndroid Build Coastguard Worker FOO" in source or -DFOO on Unix C compiler command line) 43*cda5da8dSAndroid Build Coastguard Worker undef_macros : [string] 44*cda5da8dSAndroid Build Coastguard Worker list of macros to undefine explicitly 45*cda5da8dSAndroid Build Coastguard Worker library_dirs : [string] 46*cda5da8dSAndroid Build Coastguard Worker list of directories to search for C/C++ libraries at link time 47*cda5da8dSAndroid Build Coastguard Worker libraries : [string] 48*cda5da8dSAndroid Build Coastguard Worker list of library names (not filenames or paths) to link against 49*cda5da8dSAndroid Build Coastguard Worker runtime_library_dirs : [string] 50*cda5da8dSAndroid Build Coastguard Worker list of directories to search for C/C++ libraries at run time 51*cda5da8dSAndroid Build Coastguard Worker (for shared extensions, this is when the extension is loaded) 52*cda5da8dSAndroid Build Coastguard Worker extra_objects : [string] 53*cda5da8dSAndroid Build Coastguard Worker list of extra files to link with (eg. object files not implied 54*cda5da8dSAndroid Build Coastguard Worker by 'sources', static library that must be explicitly specified, 55*cda5da8dSAndroid Build Coastguard Worker binary resource files, etc.) 56*cda5da8dSAndroid Build Coastguard Worker extra_compile_args : [string] 57*cda5da8dSAndroid Build Coastguard Worker any extra platform- and compiler-specific information to use 58*cda5da8dSAndroid Build Coastguard Worker when compiling the source files in 'sources'. For platforms and 59*cda5da8dSAndroid Build Coastguard Worker compilers where "command line" makes sense, this is typically a 60*cda5da8dSAndroid Build Coastguard Worker list of command-line arguments, but for other platforms it could 61*cda5da8dSAndroid Build Coastguard Worker be anything. 62*cda5da8dSAndroid Build Coastguard Worker extra_link_args : [string] 63*cda5da8dSAndroid Build Coastguard Worker any extra platform- and compiler-specific information to use 64*cda5da8dSAndroid Build Coastguard Worker when linking object files together to create the extension (or 65*cda5da8dSAndroid Build Coastguard Worker to create a new static Python interpreter). Similar 66*cda5da8dSAndroid Build Coastguard Worker interpretation as for 'extra_compile_args'. 67*cda5da8dSAndroid Build Coastguard Worker export_symbols : [string] 68*cda5da8dSAndroid Build Coastguard Worker list of symbols to be exported from a shared extension. Not 69*cda5da8dSAndroid Build Coastguard Worker used on all platforms, and not generally necessary for Python 70*cda5da8dSAndroid Build Coastguard Worker extensions, which typically export exactly one symbol: "init" + 71*cda5da8dSAndroid Build Coastguard Worker extension_name. 72*cda5da8dSAndroid Build Coastguard Worker swig_opts : [string] 73*cda5da8dSAndroid Build Coastguard Worker any extra options to pass to SWIG if a source file has the .i 74*cda5da8dSAndroid Build Coastguard Worker extension. 75*cda5da8dSAndroid Build Coastguard Worker depends : [string] 76*cda5da8dSAndroid Build Coastguard Worker list of files that the extension depends on 77*cda5da8dSAndroid Build Coastguard Worker language : string 78*cda5da8dSAndroid Build Coastguard Worker extension language (i.e. "c", "c++", "objc"). Will be detected 79*cda5da8dSAndroid Build Coastguard Worker from the source extensions if not provided. 80*cda5da8dSAndroid Build Coastguard Worker optional : boolean 81*cda5da8dSAndroid Build Coastguard Worker specifies that a build failure in the extension should not abort the 82*cda5da8dSAndroid Build Coastguard Worker build process, but simply not install the failing extension. 83*cda5da8dSAndroid Build Coastguard Worker """ 84*cda5da8dSAndroid Build Coastguard Worker 85*cda5da8dSAndroid Build Coastguard Worker # When adding arguments to this constructor, be sure to update 86*cda5da8dSAndroid Build Coastguard Worker # setup_keywords in core.py. 87*cda5da8dSAndroid Build Coastguard Worker def __init__(self, name, sources, 88*cda5da8dSAndroid Build Coastguard Worker include_dirs=None, 89*cda5da8dSAndroid Build Coastguard Worker define_macros=None, 90*cda5da8dSAndroid Build Coastguard Worker undef_macros=None, 91*cda5da8dSAndroid Build Coastguard Worker library_dirs=None, 92*cda5da8dSAndroid Build Coastguard Worker libraries=None, 93*cda5da8dSAndroid Build Coastguard Worker runtime_library_dirs=None, 94*cda5da8dSAndroid Build Coastguard Worker extra_objects=None, 95*cda5da8dSAndroid Build Coastguard Worker extra_compile_args=None, 96*cda5da8dSAndroid Build Coastguard Worker extra_link_args=None, 97*cda5da8dSAndroid Build Coastguard Worker export_symbols=None, 98*cda5da8dSAndroid Build Coastguard Worker swig_opts = None, 99*cda5da8dSAndroid Build Coastguard Worker depends=None, 100*cda5da8dSAndroid Build Coastguard Worker language=None, 101*cda5da8dSAndroid Build Coastguard Worker optional=None, 102*cda5da8dSAndroid Build Coastguard Worker **kw # To catch unknown keywords 103*cda5da8dSAndroid Build Coastguard Worker ): 104*cda5da8dSAndroid Build Coastguard Worker if not isinstance(name, str): 105*cda5da8dSAndroid Build Coastguard Worker raise AssertionError("'name' must be a string") 106*cda5da8dSAndroid Build Coastguard Worker if not (isinstance(sources, list) and 107*cda5da8dSAndroid Build Coastguard Worker all(isinstance(v, str) for v in sources)): 108*cda5da8dSAndroid Build Coastguard Worker raise AssertionError("'sources' must be a list of strings") 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Worker self.name = name 111*cda5da8dSAndroid Build Coastguard Worker self.sources = sources 112*cda5da8dSAndroid Build Coastguard Worker self.include_dirs = include_dirs or [] 113*cda5da8dSAndroid Build Coastguard Worker self.define_macros = define_macros or [] 114*cda5da8dSAndroid Build Coastguard Worker self.undef_macros = undef_macros or [] 115*cda5da8dSAndroid Build Coastguard Worker self.library_dirs = library_dirs or [] 116*cda5da8dSAndroid Build Coastguard Worker self.libraries = libraries or [] 117*cda5da8dSAndroid Build Coastguard Worker self.runtime_library_dirs = runtime_library_dirs or [] 118*cda5da8dSAndroid Build Coastguard Worker self.extra_objects = extra_objects or [] 119*cda5da8dSAndroid Build Coastguard Worker self.extra_compile_args = extra_compile_args or [] 120*cda5da8dSAndroid Build Coastguard Worker self.extra_link_args = extra_link_args or [] 121*cda5da8dSAndroid Build Coastguard Worker self.export_symbols = export_symbols or [] 122*cda5da8dSAndroid Build Coastguard Worker self.swig_opts = swig_opts or [] 123*cda5da8dSAndroid Build Coastguard Worker self.depends = depends or [] 124*cda5da8dSAndroid Build Coastguard Worker self.language = language 125*cda5da8dSAndroid Build Coastguard Worker self.optional = optional 126*cda5da8dSAndroid Build Coastguard Worker 127*cda5da8dSAndroid Build Coastguard Worker # If there are unknown keyword options, warn about them 128*cda5da8dSAndroid Build Coastguard Worker if len(kw) > 0: 129*cda5da8dSAndroid Build Coastguard Worker options = [repr(option) for option in kw] 130*cda5da8dSAndroid Build Coastguard Worker options = ', '.join(sorted(options)) 131*cda5da8dSAndroid Build Coastguard Worker msg = "Unknown Extension options: %s" % options 132*cda5da8dSAndroid Build Coastguard Worker warnings.warn(msg) 133*cda5da8dSAndroid Build Coastguard Worker 134*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 135*cda5da8dSAndroid Build Coastguard Worker return '<%s.%s(%r) at %#x>' % ( 136*cda5da8dSAndroid Build Coastguard Worker self.__class__.__module__, 137*cda5da8dSAndroid Build Coastguard Worker self.__class__.__qualname__, 138*cda5da8dSAndroid Build Coastguard Worker self.name, 139*cda5da8dSAndroid Build Coastguard Worker id(self)) 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Workerdef read_setup_file(filename): 143*cda5da8dSAndroid Build Coastguard Worker """Reads a Setup file and returns Extension instances.""" 144*cda5da8dSAndroid Build Coastguard Worker from distutils.sysconfig import (parse_makefile, expand_makefile_vars, 145*cda5da8dSAndroid Build Coastguard Worker _variable_rx) 146*cda5da8dSAndroid Build Coastguard Worker 147*cda5da8dSAndroid Build Coastguard Worker from distutils.text_file import TextFile 148*cda5da8dSAndroid Build Coastguard Worker from distutils.util import split_quoted 149*cda5da8dSAndroid Build Coastguard Worker 150*cda5da8dSAndroid Build Coastguard Worker # First pass over the file to gather "VAR = VALUE" assignments. 151*cda5da8dSAndroid Build Coastguard Worker vars = parse_makefile(filename) 152*cda5da8dSAndroid Build Coastguard Worker 153*cda5da8dSAndroid Build Coastguard Worker # Second pass to gobble up the real content: lines of the form 154*cda5da8dSAndroid Build Coastguard Worker # <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...] 155*cda5da8dSAndroid Build Coastguard Worker file = TextFile(filename, 156*cda5da8dSAndroid Build Coastguard Worker strip_comments=1, skip_blanks=1, join_lines=1, 157*cda5da8dSAndroid Build Coastguard Worker lstrip_ws=1, rstrip_ws=1) 158*cda5da8dSAndroid Build Coastguard Worker try: 159*cda5da8dSAndroid Build Coastguard Worker extensions = [] 160*cda5da8dSAndroid Build Coastguard Worker 161*cda5da8dSAndroid Build Coastguard Worker while True: 162*cda5da8dSAndroid Build Coastguard Worker line = file.readline() 163*cda5da8dSAndroid Build Coastguard Worker if line is None: # eof 164*cda5da8dSAndroid Build Coastguard Worker break 165*cda5da8dSAndroid Build Coastguard Worker if re.match(_variable_rx, line): # VAR=VALUE, handled in first pass 166*cda5da8dSAndroid Build Coastguard Worker continue 167*cda5da8dSAndroid Build Coastguard Worker 168*cda5da8dSAndroid Build Coastguard Worker if line[0] == line[-1] == "*": 169*cda5da8dSAndroid Build Coastguard Worker file.warn("'%s' lines not handled yet" % line) 170*cda5da8dSAndroid Build Coastguard Worker continue 171*cda5da8dSAndroid Build Coastguard Worker 172*cda5da8dSAndroid Build Coastguard Worker line = expand_makefile_vars(line, vars) 173*cda5da8dSAndroid Build Coastguard Worker words = split_quoted(line) 174*cda5da8dSAndroid Build Coastguard Worker 175*cda5da8dSAndroid Build Coastguard Worker # NB. this parses a slightly different syntax than the old 176*cda5da8dSAndroid Build Coastguard Worker # makesetup script: here, there must be exactly one extension per 177*cda5da8dSAndroid Build Coastguard Worker # line, and it must be the first word of the line. I have no idea 178*cda5da8dSAndroid Build Coastguard Worker # why the old syntax supported multiple extensions per line, as 179*cda5da8dSAndroid Build Coastguard Worker # they all wind up being the same. 180*cda5da8dSAndroid Build Coastguard Worker 181*cda5da8dSAndroid Build Coastguard Worker module = words[0] 182*cda5da8dSAndroid Build Coastguard Worker ext = Extension(module, []) 183*cda5da8dSAndroid Build Coastguard Worker append_next_word = None 184*cda5da8dSAndroid Build Coastguard Worker 185*cda5da8dSAndroid Build Coastguard Worker for word in words[1:]: 186*cda5da8dSAndroid Build Coastguard Worker if append_next_word is not None: 187*cda5da8dSAndroid Build Coastguard Worker append_next_word.append(word) 188*cda5da8dSAndroid Build Coastguard Worker append_next_word = None 189*cda5da8dSAndroid Build Coastguard Worker continue 190*cda5da8dSAndroid Build Coastguard Worker 191*cda5da8dSAndroid Build Coastguard Worker suffix = os.path.splitext(word)[1] 192*cda5da8dSAndroid Build Coastguard Worker switch = word[0:2] ; value = word[2:] 193*cda5da8dSAndroid Build Coastguard Worker 194*cda5da8dSAndroid Build Coastguard Worker if suffix in (".c", ".cc", ".cpp", ".cxx", ".c++", ".m", ".mm"): 195*cda5da8dSAndroid Build Coastguard Worker # hmm, should we do something about C vs. C++ sources? 196*cda5da8dSAndroid Build Coastguard Worker # or leave it up to the CCompiler implementation to 197*cda5da8dSAndroid Build Coastguard Worker # worry about? 198*cda5da8dSAndroid Build Coastguard Worker ext.sources.append(word) 199*cda5da8dSAndroid Build Coastguard Worker elif switch == "-I": 200*cda5da8dSAndroid Build Coastguard Worker ext.include_dirs.append(value) 201*cda5da8dSAndroid Build Coastguard Worker elif switch == "-D": 202*cda5da8dSAndroid Build Coastguard Worker equals = value.find("=") 203*cda5da8dSAndroid Build Coastguard Worker if equals == -1: # bare "-DFOO" -- no value 204*cda5da8dSAndroid Build Coastguard Worker ext.define_macros.append((value, None)) 205*cda5da8dSAndroid Build Coastguard Worker else: # "-DFOO=blah" 206*cda5da8dSAndroid Build Coastguard Worker ext.define_macros.append((value[0:equals], 207*cda5da8dSAndroid Build Coastguard Worker value[equals+2:])) 208*cda5da8dSAndroid Build Coastguard Worker elif switch == "-U": 209*cda5da8dSAndroid Build Coastguard Worker ext.undef_macros.append(value) 210*cda5da8dSAndroid Build Coastguard Worker elif switch == "-C": # only here 'cause makesetup has it! 211*cda5da8dSAndroid Build Coastguard Worker ext.extra_compile_args.append(word) 212*cda5da8dSAndroid Build Coastguard Worker elif switch == "-l": 213*cda5da8dSAndroid Build Coastguard Worker ext.libraries.append(value) 214*cda5da8dSAndroid Build Coastguard Worker elif switch == "-L": 215*cda5da8dSAndroid Build Coastguard Worker ext.library_dirs.append(value) 216*cda5da8dSAndroid Build Coastguard Worker elif switch == "-R": 217*cda5da8dSAndroid Build Coastguard Worker ext.runtime_library_dirs.append(value) 218*cda5da8dSAndroid Build Coastguard Worker elif word == "-rpath": 219*cda5da8dSAndroid Build Coastguard Worker append_next_word = ext.runtime_library_dirs 220*cda5da8dSAndroid Build Coastguard Worker elif word == "-Xlinker": 221*cda5da8dSAndroid Build Coastguard Worker append_next_word = ext.extra_link_args 222*cda5da8dSAndroid Build Coastguard Worker elif word == "-Xcompiler": 223*cda5da8dSAndroid Build Coastguard Worker append_next_word = ext.extra_compile_args 224*cda5da8dSAndroid Build Coastguard Worker elif switch == "-u": 225*cda5da8dSAndroid Build Coastguard Worker ext.extra_link_args.append(word) 226*cda5da8dSAndroid Build Coastguard Worker if not value: 227*cda5da8dSAndroid Build Coastguard Worker append_next_word = ext.extra_link_args 228*cda5da8dSAndroid Build Coastguard Worker elif suffix in (".a", ".so", ".sl", ".o", ".dylib"): 229*cda5da8dSAndroid Build Coastguard Worker # NB. a really faithful emulation of makesetup would 230*cda5da8dSAndroid Build Coastguard Worker # append a .o file to extra_objects only if it 231*cda5da8dSAndroid Build Coastguard Worker # had a slash in it; otherwise, it would s/.o/.c/ 232*cda5da8dSAndroid Build Coastguard Worker # and append it to sources. Hmmmm. 233*cda5da8dSAndroid Build Coastguard Worker ext.extra_objects.append(word) 234*cda5da8dSAndroid Build Coastguard Worker else: 235*cda5da8dSAndroid Build Coastguard Worker file.warn("unrecognized argument '%s'" % word) 236*cda5da8dSAndroid Build Coastguard Worker 237*cda5da8dSAndroid Build Coastguard Worker extensions.append(ext) 238*cda5da8dSAndroid Build Coastguard Worker finally: 239*cda5da8dSAndroid Build Coastguard Worker file.close() 240*cda5da8dSAndroid Build Coastguard Worker 241*cda5da8dSAndroid Build Coastguard Worker return extensions 242