comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/command/build_clib.py @ 87:2a2c65a20a8b

Add Python libs and headers
author Chris Cannam
date Wed, 25 Feb 2015 14:05:22 +0000
parents
children
comparison
equal deleted inserted replaced
86:413a9d26189e 87:2a2c65a20a8b
1 """ Modified version of build_clib that handles fortran source files.
2 """
3 from __future__ import division, absolute_import, print_function
4
5 import os
6 from glob import glob
7 import shutil
8 from distutils.command.build_clib import build_clib as old_build_clib
9 from distutils.errors import DistutilsSetupError, DistutilsError, \
10 DistutilsFileError
11
12 from numpy.distutils import log
13 from distutils.dep_util import newer_group
14 from numpy.distutils.misc_util import filter_sources, has_f_sources,\
15 has_cxx_sources, all_strings, get_lib_source_files, is_sequence, \
16 get_numpy_include_dirs
17
18 # Fix Python distutils bug sf #1718574:
19 _l = old_build_clib.user_options
20 for _i in range(len(_l)):
21 if _l[_i][0] in ['build-clib', 'build-temp']:
22 _l[_i] = (_l[_i][0]+'=',)+_l[_i][1:]
23 #
24
25 class build_clib(old_build_clib):
26
27 description = "build C/C++/F libraries used by Python extensions"
28
29 user_options = old_build_clib.user_options + [
30 ('fcompiler=', None,
31 "specify the Fortran compiler type"),
32 ('inplace', 'i', 'Build in-place'),
33 ]
34
35 boolean_options = old_build_clib.boolean_options + ['inplace']
36
37 def initialize_options(self):
38 old_build_clib.initialize_options(self)
39 self.fcompiler = None
40 self.inplace = 0
41 return
42
43 def have_f_sources(self):
44 for (lib_name, build_info) in self.libraries:
45 if has_f_sources(build_info.get('sources', [])):
46 return True
47 return False
48
49 def have_cxx_sources(self):
50 for (lib_name, build_info) in self.libraries:
51 if has_cxx_sources(build_info.get('sources', [])):
52 return True
53 return False
54
55 def run(self):
56 if not self.libraries:
57 return
58
59 # Make sure that library sources are complete.
60 languages = []
61
62 # Make sure that extension sources are complete.
63 self.run_command('build_src')
64
65 for (lib_name, build_info) in self.libraries:
66 l = build_info.get('language', None)
67 if l and l not in languages: languages.append(l)
68
69 from distutils.ccompiler import new_compiler
70 self.compiler = new_compiler(compiler=self.compiler,
71 dry_run=self.dry_run,
72 force=self.force)
73 self.compiler.customize(self.distribution,
74 need_cxx=self.have_cxx_sources())
75
76 libraries = self.libraries
77 self.libraries = None
78 self.compiler.customize_cmd(self)
79 self.libraries = libraries
80
81 self.compiler.show_customization()
82
83 if self.have_f_sources():
84 from numpy.distutils.fcompiler import new_fcompiler
85 self._f_compiler = new_fcompiler(compiler=self.fcompiler,
86 verbose=self.verbose,
87 dry_run=self.dry_run,
88 force=self.force,
89 requiref90='f90' in languages,
90 c_compiler=self.compiler)
91 if self._f_compiler is not None:
92 self._f_compiler.customize(self.distribution)
93
94 libraries = self.libraries
95 self.libraries = None
96 self._f_compiler.customize_cmd(self)
97 self.libraries = libraries
98
99 self._f_compiler.show_customization()
100 else:
101 self._f_compiler = None
102
103 self.build_libraries(self.libraries)
104
105 if self.inplace:
106 for l in self.distribution.installed_libraries:
107 libname = self.compiler.library_filename(l.name)
108 source = os.path.join(self.build_clib, libname)
109 target = os.path.join(l.target_dir, libname)
110 self.mkpath(l.target_dir)
111 shutil.copy(source, target)
112
113 def get_source_files(self):
114 self.check_library_list(self.libraries)
115 filenames = []
116 for lib in self.libraries:
117 filenames.extend(get_lib_source_files(lib))
118 return filenames
119
120 def build_libraries(self, libraries):
121 for (lib_name, build_info) in libraries:
122 self.build_a_library(build_info, lib_name, libraries)
123
124 def build_a_library(self, build_info, lib_name, libraries):
125 # default compilers
126 compiler = self.compiler
127 fcompiler = self._f_compiler
128
129 sources = build_info.get('sources')
130 if sources is None or not is_sequence(sources):
131 raise DistutilsSetupError(("in 'libraries' option (library '%s'), " +
132 "'sources' must be present and must be " +
133 "a list of source filenames") % lib_name)
134 sources = list(sources)
135
136 c_sources, cxx_sources, f_sources, fmodule_sources \
137 = filter_sources(sources)
138 requiref90 = not not fmodule_sources or \
139 build_info.get('language', 'c')=='f90'
140
141 # save source type information so that build_ext can use it.
142 source_languages = []
143 if c_sources: source_languages.append('c')
144 if cxx_sources: source_languages.append('c++')
145 if requiref90: source_languages.append('f90')
146 elif f_sources: source_languages.append('f77')
147 build_info['source_languages'] = source_languages
148
149 lib_file = compiler.library_filename(lib_name,
150 output_dir=self.build_clib)
151 depends = sources + build_info.get('depends', [])
152 if not (self.force or newer_group(depends, lib_file, 'newer')):
153 log.debug("skipping '%s' library (up-to-date)", lib_name)
154 return
155 else:
156 log.info("building '%s' library", lib_name)
157
158 config_fc = build_info.get('config_fc', {})
159 if fcompiler is not None and config_fc:
160 log.info('using additional config_fc from setup script '\
161 'for fortran compiler: %s' \
162 % (config_fc,))
163 from numpy.distutils.fcompiler import new_fcompiler
164 fcompiler = new_fcompiler(compiler=fcompiler.compiler_type,
165 verbose=self.verbose,
166 dry_run=self.dry_run,
167 force=self.force,
168 requiref90=requiref90,
169 c_compiler=self.compiler)
170 if fcompiler is not None:
171 dist = self.distribution
172 base_config_fc = dist.get_option_dict('config_fc').copy()
173 base_config_fc.update(config_fc)
174 fcompiler.customize(base_config_fc)
175
176 # check availability of Fortran compilers
177 if (f_sources or fmodule_sources) and fcompiler is None:
178 raise DistutilsError("library %s has Fortran sources"\
179 " but no Fortran compiler found" % (lib_name))
180
181 if fcompiler is not None:
182 fcompiler.extra_f77_compile_args = build_info.get('extra_f77_compile_args') or []
183 fcompiler.extra_f90_compile_args = build_info.get('extra_f90_compile_args') or []
184
185 macros = build_info.get('macros')
186 include_dirs = build_info.get('include_dirs')
187 if include_dirs is None:
188 include_dirs = []
189 extra_postargs = build_info.get('extra_compiler_args') or []
190
191 include_dirs.extend(get_numpy_include_dirs())
192 # where compiled F90 module files are:
193 module_dirs = build_info.get('module_dirs') or []
194 module_build_dir = os.path.dirname(lib_file)
195 if requiref90: self.mkpath(module_build_dir)
196
197 if compiler.compiler_type=='msvc':
198 # this hack works around the msvc compiler attributes
199 # problem, msvc uses its own convention :(
200 c_sources += cxx_sources
201 cxx_sources = []
202
203 objects = []
204 if c_sources:
205 log.info("compiling C sources")
206 objects = compiler.compile(c_sources,
207 output_dir=self.build_temp,
208 macros=macros,
209 include_dirs=include_dirs,
210 debug=self.debug,
211 extra_postargs=extra_postargs)
212
213 if cxx_sources:
214 log.info("compiling C++ sources")
215 cxx_compiler = compiler.cxx_compiler()
216 cxx_objects = cxx_compiler.compile(cxx_sources,
217 output_dir=self.build_temp,
218 macros=macros,
219 include_dirs=include_dirs,
220 debug=self.debug,
221 extra_postargs=extra_postargs)
222 objects.extend(cxx_objects)
223
224 if f_sources or fmodule_sources:
225 extra_postargs = []
226 f_objects = []
227
228 if requiref90:
229 if fcompiler.module_dir_switch is None:
230 existing_modules = glob('*.mod')
231 extra_postargs += fcompiler.module_options(\
232 module_dirs, module_build_dir)
233
234 if fmodule_sources:
235 log.info("compiling Fortran 90 module sources")
236 f_objects += fcompiler.compile(fmodule_sources,
237 output_dir=self.build_temp,
238 macros=macros,
239 include_dirs=include_dirs,
240 debug=self.debug,
241 extra_postargs=extra_postargs)
242
243 if requiref90 and self._f_compiler.module_dir_switch is None:
244 # move new compiled F90 module files to module_build_dir
245 for f in glob('*.mod'):
246 if f in existing_modules:
247 continue
248 t = os.path.join(module_build_dir, f)
249 if os.path.abspath(f)==os.path.abspath(t):
250 continue
251 if os.path.isfile(t):
252 os.remove(t)
253 try:
254 self.move_file(f, module_build_dir)
255 except DistutilsFileError:
256 log.warn('failed to move %r to %r' \
257 % (f, module_build_dir))
258
259 if f_sources:
260 log.info("compiling Fortran sources")
261 f_objects += fcompiler.compile(f_sources,
262 output_dir=self.build_temp,
263 macros=macros,
264 include_dirs=include_dirs,
265 debug=self.debug,
266 extra_postargs=extra_postargs)
267 else:
268 f_objects = []
269
270 objects.extend(f_objects)
271
272 # assume that default linker is suitable for
273 # linking Fortran object files
274 compiler.create_static_lib(objects, lib_name,
275 output_dir=self.build_clib,
276 debug=self.debug)
277
278 # fix library dependencies
279 clib_libraries = build_info.get('libraries', [])
280 for lname, binfo in libraries:
281 if lname in clib_libraries:
282 clib_libraries.extend(binfo[1].get('libraries', []))
283 if clib_libraries:
284 build_info['libraries'] = clib_libraries