build_ext.py revision 48697d931bb86ddd114a42ccb89adb6374aef4ff
1"""distutils.command.build_ext 2 3Implements the Distutils 'build_ext' command, for building extension 4modules (currently limited to C extensions, should accomodate C++ 5extensions ASAP).""" 6 7# created 1999/08/09, Greg Ward 8 9__rcsid__ = "$Id$" 10 11import sys, os, string, re 12from types import * 13from distutils.core import Command 14from distutils.ccompiler import new_compiler 15from distutils.sysconfig import INCLUDEPY, SO, exec_prefix 16from distutils.errors import * 17 18 19# An extension name is just a dot-separated list of Python NAMEs (ie. 20# the same as a fully-qualified module name). 21extension_name_re = re.compile \ 22 (r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$') 23 24 25class BuildExt (Command): 26 27 # XXX thoughts on how to deal with complex command-line options like 28 # these, i.e. how to make it so fancy_getopt can suck them off the 29 # command line and make it look like setup.py defined the appropriate 30 # lists of tuples of what-have-you. 31 # - each command needs a callback to process its command-line options 32 # - Command.__init__() needs access to its share of the whole 33 # command line (must ultimately come from 34 # Distribution.parse_command_line()) 35 # - it then calls the current command class' option-parsing 36 # callback to deal with weird options like -D, which have to 37 # parse the option text and churn out some custom data 38 # structure 39 # - that data structure (in this case, a list of 2-tuples) 40 # will then be present in the command object by the time 41 # we get to set_final_options() (i.e. the constructor 42 # takes care of both command-line and client options 43 # in between set_default_options() and set_final_options()) 44 45 options = [('build-dir=', 'd', 46 "directory for compiled extension modules"), 47 ('include-dirs=', 'I', 48 "list of directories to search for header files"), 49 ('define=', 'D', 50 "C preprocessor macros to define"), 51 ('undef=', 'U', 52 "C preprocessor macros to undefine"), 53 ('libs=', 'l', 54 "external C libraries to link with"), 55 ('library-dirs=', 'L', 56 "directories to search for external C libraries"), 57 ('rpath=', 'R', 58 "directories to search for shared C libraries at runtime"), 59 ('link-objects=', 'O', 60 "extra explicit link objects to include in the link"), 61 ] 62 63 64 def set_default_options (self): 65 self.extensions = None 66 self.build_dir = None 67 self.package = None 68 69 self.include_dirs = None 70 self.define = None 71 self.undef = None 72 self.libs = None 73 self.library_dirs = None 74 self.rpath = None 75 self.link_objects = None 76 77 78 def set_final_options (self): 79 self.set_undefined_options ('build', ('build_platlib', 'build_dir')) 80 81 if self.package is None: 82 self.package = self.distribution.ext_package 83 84 self.extensions = self.distribution.ext_modules 85 86 87 # Make sure Python's include directories (for Python.h, config.h, 88 # etc.) are in the include search path. We have to roll our own 89 # "exec include dir", because the Makefile parsed by sysconfig 90 # doesn't have it (sigh). 91 py_include = INCLUDEPY # prefix + "include" + "python" + ver 92 exec_py_include = os.path.join (exec_prefix, 'include', 93 'python' + sys.version[0:3]) 94 if self.include_dirs is None: 95 self.include_dirs = self.distribution.include_dirs or [] 96 if type (self.include_dirs) is StringType: 97 self.include_dirs = string.split (self.include_dirs, 98 os.pathsep) 99 100 self.include_dirs.insert (0, py_include) 101 if exec_py_include != py_include: 102 self.include_dirs.insert (0, exec_py_include) 103 104 105 def run (self): 106 107 # 'self.extensions', as supplied by setup.py, is a list of 2-tuples. 108 # Each tuple is simple: 109 # (ext_name, build_info) 110 # build_info is a dictionary containing everything specific to 111 # building this extension. (Info pertaining to all extensions 112 # should be handled by general distutils options passed from 113 # setup.py down to right here, but that's not taken care of yet.) 114 115 if not self.extensions: 116 return 117 118 # First, sanity-check the 'self.extensions' list 119 self.check_extensions_list (self.extensions) 120 121 # Setup the CCompiler object that we'll use to do all the 122 # compiling and linking 123 self.compiler = new_compiler (plat=os.environ.get ('PLAT'), 124 verbose=self.verbose, 125 dry_run=self.dry_run, 126 force=self.force) 127 if self.include_dirs is not None: 128 self.compiler.set_include_dirs (self.include_dirs) 129 if self.define is not None: 130 # 'define' option is a list of (name,value) tuples 131 for (name,value) in self.define: 132 self.compiler.define_macro (name, value) 133 if self.undef is not None: 134 for macro in self.undef: 135 self.compiler.undefine_macro (macro) 136 if self.libs is not None: 137 self.compiler.set_libraries (self.libs) 138 if self.library_dirs is not None: 139 self.compiler.set_library_dirs (self.library_dirs) 140 if self.rpath is not None: 141 self.compiler.set_runtime_library_dirs (self.rpath) 142 if self.link_objects is not None: 143 self.compiler.set_link_objects (self.link_objects) 144 145 # Now the real loop over extensions 146 self.build_extensions (self.extensions) 147 148 149 150 def check_extensions_list (self, extensions): 151 152 if type (extensions) is not ListType: 153 raise DistutilsValueError, \ 154 "'ext_modules' option must be a list of tuples" 155 156 for ext in extensions: 157 if type (ext) is not TupleType and len (ext) != 2: 158 raise DistutilsValueError, \ 159 "each element of 'ext_modules' option must be a 2-tuple" 160 161 if not (type (ext[0]) is StringType and 162 extension_name_re.match (ext[0])): 163 raise DistutilsValueError, \ 164 "first element of each tuple in 'ext_modules' " + \ 165 "must be the extension name (a string)" 166 167 if type (ext[1]) is not DictionaryType: 168 raise DistutilsValueError, \ 169 "second element of each tuple in 'ext_modules' " + \ 170 "must be a dictionary" 171 172 # end sanity-check for 173 174 # check_extensions_list () 175 176 177 def get_source_files (self): 178 179 filenames = [] 180 181 # Wouldn't it be neat if we knew the names of header files too... 182 for (extension_name, build_info) in self.extensions: 183 sources = build_info.get ('sources') 184 if type (sources) in (ListType, TupleType): 185 filenames.extend (sources) 186 187 return filenames 188 189 190 def build_extensions (self, extensions): 191 192 for (extension_name, build_info) in extensions: 193 sources = build_info.get ('sources') 194 if sources is None or type (sources) not in (ListType, TupleType): 195 raise DistutilsValueError, \ 196 "in ext_modules option, 'sources' must be present " + \ 197 "and must be a list of source filenames" 198 sources = list (sources) 199 200 # First step: compile the source code to object files. This 201 # drops the object files in the current directory, regardless 202 # of where the source is (may be a bad thing, but that's how a 203 # Makefile.pre.in-based system does it, so at least there's a 204 # precedent!) 205 macros = build_info.get ('macros') 206 include_dirs = build_info.get ('include_dirs') 207 self.compiler.compile (sources, 208 macros=macros, 209 include_dirs=include_dirs) 210 211 # Now link the object files together into a "shared object" -- 212 # of course, first we have to figure out all the other things 213 # that go into the mix. 214 objects = self.compiler.object_filenames (sources) 215 extra_objects = build_info.get ('extra_objects') 216 if extra_objects: 217 objects.extend (extra_objects) 218 libraries = build_info.get ('libraries') 219 library_dirs = build_info.get ('library_dirs') 220 extra_args = build_info.get ('extra_link_args') or [] 221 if self.compiler.compiler_type == 'msvc': 222 def_file = build_info.get ('def_file') 223 if def_file is None: 224 source_dir = os.path.dirname (sources[0]) 225 ext_base = (string.split (extension_name, '.'))[-1] 226 def_file = os.path.join (source_dir, "%s.def" % ext_base) 227 if not os.path.exists (def_file): 228 self.warn ("file '%s' not found: " % def_file + 229 "might have problems building DLL") 230 def_file = None 231 232 if def_file is not None: 233 extra_args.append ('/DEF:' + def_file) 234 235 ext_filename = self.extension_filename \ 236 (extension_name, self.package) 237 ext_filename = os.path.join (self.build_dir, ext_filename) 238 dest_dir = os.path.dirname (ext_filename) 239 self.mkpath (dest_dir) 240 self.compiler.link_shared_object (objects, ext_filename, 241 libraries=libraries, 242 library_dirs=library_dirs, 243 extra_postargs=extra_args) 244 245 # build_extensions () 246 247 248 def extension_filename (self, ext_name, package=None): 249 if package: 250 ext_name = package + '.' + ext_name 251 ext_path = string.split (ext_name, '.') 252 return apply (os.path.join, ext_path) + SO 253 254# class BuildExt 255