comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/mingw32ccompiler.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 """
2 Support code for building Python extensions on Windows.
3
4 # NT stuff
5 # 1. Make sure libpython<version>.a exists for gcc. If not, build it.
6 # 2. Force windows to use gcc (we're struggling with MSVC and g77 support)
7 # 3. Force windows to use g77
8
9 """
10 from __future__ import division, absolute_import, print_function
11
12 import os
13 import sys
14 import subprocess
15 import re
16
17 # Overwrite certain distutils.ccompiler functions:
18 import numpy.distutils.ccompiler
19
20 if sys.version_info[0] < 3:
21 from . import log
22 else:
23 from numpy.distutils import log
24 # NT stuff
25 # 1. Make sure libpython<version>.a exists for gcc. If not, build it.
26 # 2. Force windows to use gcc (we're struggling with MSVC and g77 support)
27 # --> this is done in numpy/distutils/ccompiler.py
28 # 3. Force windows to use g77
29
30 import distutils.cygwinccompiler
31 from distutils.version import StrictVersion
32 from numpy.distutils.ccompiler import gen_preprocess_options, gen_lib_options
33 from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
34
35 from distutils.unixccompiler import UnixCCompiler
36 from distutils.msvccompiler import get_build_version as get_build_msvc_version
37 from numpy.distutils.misc_util import msvc_runtime_library, get_build_architecture
38
39 # Useful to generate table of symbols from a dll
40 _START = re.compile(r'\[Ordinal/Name Pointer\] Table')
41 _TABLE = re.compile(r'^\s+\[([\s*[0-9]*)\] ([a-zA-Z0-9_]*)')
42
43 # the same as cygwin plus some additional parameters
44 class Mingw32CCompiler(distutils.cygwinccompiler.CygwinCCompiler):
45 """ A modified MingW32 compiler compatible with an MSVC built Python.
46
47 """
48
49 compiler_type = 'mingw32'
50
51 def __init__ (self,
52 verbose=0,
53 dry_run=0,
54 force=0):
55
56 distutils.cygwinccompiler.CygwinCCompiler.__init__ (self,
57 verbose, dry_run, force)
58
59 # we need to support 3.2 which doesn't match the standard
60 # get_versions methods regex
61 if self.gcc_version is None:
62 import re
63 p = subprocess.Popen(['gcc', '-dumpversion'], shell=True,
64 stdout=subprocess.PIPE)
65 out_string = p.stdout.read()
66 p.stdout.close()
67 result = re.search('(\d+\.\d+)', out_string)
68 if result:
69 self.gcc_version = StrictVersion(result.group(1))
70
71 # A real mingw32 doesn't need to specify a different entry point,
72 # but cygwin 2.91.57 in no-cygwin-mode needs it.
73 if self.gcc_version <= "2.91.57":
74 entry_point = '--entry _DllMain@12'
75 else:
76 entry_point = ''
77
78 if self.linker_dll == 'dllwrap':
79 # Commented out '--driver-name g++' part that fixes weird
80 # g++.exe: g++: No such file or directory
81 # error (mingw 1.0 in Enthon24 tree, gcc-3.4.5).
82 # If the --driver-name part is required for some environment
83 # then make the inclusion of this part specific to that environment.
84 self.linker = 'dllwrap' # --driver-name g++'
85 elif self.linker_dll == 'gcc':
86 self.linker = 'g++'
87
88 # **changes: eric jones 4/11/01
89 # 1. Check for import library on Windows. Build if it doesn't exist.
90
91 build_import_library()
92
93 # Check for custom msvc runtime library on Windows. Build if it doesn't exist.
94 msvcr_success = build_msvcr_library()
95 msvcr_dbg_success = build_msvcr_library(debug=True)
96 if msvcr_success or msvcr_dbg_success:
97 # add preprocessor statement for using customized msvcr lib
98 self.define_macro('NPY_MINGW_USE_CUSTOM_MSVCR')
99
100 # Define the MSVC version as hint for MinGW
101 msvcr_version = '0x%03i0' % int(msvc_runtime_library().lstrip('msvcr'))
102 self.define_macro('__MSVCRT_VERSION__', msvcr_version)
103
104 # **changes: eric jones 4/11/01
105 # 2. increased optimization and turned off all warnings
106 # 3. also added --driver-name g++
107 #self.set_executables(compiler='gcc -mno-cygwin -O2 -w',
108 # compiler_so='gcc -mno-cygwin -mdll -O2 -w',
109 # linker_exe='gcc -mno-cygwin',
110 # linker_so='%s --driver-name g++ -mno-cygwin -mdll -static %s'
111 # % (self.linker, entry_point))
112
113 # MS_WIN64 should be defined when building for amd64 on windows, but
114 # python headers define it only for MS compilers, which has all kind of
115 # bad consequences, like using Py_ModuleInit4 instead of
116 # Py_ModuleInit4_64, etc... So we add it here
117 if get_build_architecture() == 'AMD64':
118 if self.gcc_version < "4.0":
119 self.set_executables(
120 compiler='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0 -Wall',
121 compiler_so='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0 -Wall -Wstrict-prototypes',
122 linker_exe='gcc -g -mno-cygwin',
123 linker_so='gcc -g -mno-cygwin -shared')
124 else:
125 # gcc-4 series releases do not support -mno-cygwin option
126 self.set_executables(
127 compiler='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall',
128 compiler_so='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall -Wstrict-prototypes',
129 linker_exe='gcc -g',
130 linker_so='gcc -g -shared')
131 else:
132 if self.gcc_version <= "3.0.0":
133 self.set_executables(compiler='gcc -mno-cygwin -O2 -w',
134 compiler_so='gcc -mno-cygwin -mdll -O2 -w -Wstrict-prototypes',
135 linker_exe='g++ -mno-cygwin',
136 linker_so='%s -mno-cygwin -mdll -static %s'
137 % (self.linker, entry_point))
138 elif self.gcc_version < "4.0":
139 self.set_executables(compiler='gcc -mno-cygwin -O2 -Wall',
140 compiler_so='gcc -mno-cygwin -O2 -Wall -Wstrict-prototypes',
141 linker_exe='g++ -mno-cygwin',
142 linker_so='g++ -mno-cygwin -shared')
143 else:
144 # gcc-4 series releases do not support -mno-cygwin option
145 self.set_executables(compiler='gcc -O2 -Wall',
146 compiler_so='gcc -O2 -Wall -Wstrict-prototypes',
147 linker_exe='g++ ',
148 linker_so='g++ -shared')
149 # added for python2.3 support
150 # we can't pass it through set_executables because pre 2.2 would fail
151 self.compiler_cxx = ['g++']
152
153 # Maybe we should also append -mthreads, but then the finished
154 # dlls need another dll (mingwm10.dll see Mingw32 docs)
155 # (-mthreads: Support thread-safe exception handling on `Mingw32')
156
157 # no additional libraries needed
158 #self.dll_libraries=[]
159 return
160
161 # __init__ ()
162
163 def link(self,
164 target_desc,
165 objects,
166 output_filename,
167 output_dir,
168 libraries,
169 library_dirs,
170 runtime_library_dirs,
171 export_symbols = None,
172 debug=0,
173 extra_preargs=None,
174 extra_postargs=None,
175 build_temp=None,
176 target_lang=None):
177 # Include the appropiate MSVC runtime library if Python was built
178 # with MSVC >= 7.0 (MinGW standard is msvcrt)
179 runtime_library = msvc_runtime_library()
180 if runtime_library:
181 if not libraries:
182 libraries = []
183 libraries.append(runtime_library)
184 args = (self,
185 target_desc,
186 objects,
187 output_filename,
188 output_dir,
189 libraries,
190 library_dirs,
191 runtime_library_dirs,
192 None, #export_symbols, we do this in our def-file
193 debug,
194 extra_preargs,
195 extra_postargs,
196 build_temp,
197 target_lang)
198 if self.gcc_version < "3.0.0":
199 func = distutils.cygwinccompiler.CygwinCCompiler.link
200 else:
201 func = UnixCCompiler.link
202 func(*args[:func.__code__.co_argcount])
203 return
204
205 def object_filenames (self,
206 source_filenames,
207 strip_dir=0,
208 output_dir=''):
209 if output_dir is None: output_dir = ''
210 obj_names = []
211 for src_name in source_filenames:
212 # use normcase to make sure '.rc' is really '.rc' and not '.RC'
213 (base, ext) = os.path.splitext (os.path.normcase(src_name))
214
215 # added these lines to strip off windows drive letters
216 # without it, .o files are placed next to .c files
217 # instead of the build directory
218 drv, base = os.path.splitdrive(base)
219 if drv:
220 base = base[1:]
221
222 if ext not in (self.src_extensions + ['.rc', '.res']):
223 raise UnknownFileError(
224 "unknown file type '%s' (from '%s')" % \
225 (ext, src_name))
226 if strip_dir:
227 base = os.path.basename (base)
228 if ext == '.res' or ext == '.rc':
229 # these need to be compiled to object files
230 obj_names.append (os.path.join (output_dir,
231 base + ext + self.obj_extension))
232 else:
233 obj_names.append (os.path.join (output_dir,
234 base + self.obj_extension))
235 return obj_names
236
237 # object_filenames ()
238
239
240 def find_python_dll():
241 maj, min, micro = [int(i) for i in sys.version_info[:3]]
242 dllname = 'python%d%d.dll' % (maj, min)
243 print("Looking for %s" % dllname)
244
245 # We can't do much here:
246 # - find it in python main dir
247 # - in system32,
248 # - ortherwise (Sxs), I don't know how to get it.
249 lib_dirs = []
250 lib_dirs.append(sys.prefix)
251 lib_dirs.append(os.path.join(sys.prefix, 'lib'))
252 try:
253 lib_dirs.append(os.path.join(os.environ['SYSTEMROOT'], 'system32'))
254 except KeyError:
255 pass
256
257 for d in lib_dirs:
258 dll = os.path.join(d, dllname)
259 if os.path.exists(dll):
260 return dll
261
262 raise ValueError("%s not found in %s" % (dllname, lib_dirs))
263
264 def dump_table(dll):
265 st = subprocess.Popen(["objdump.exe", "-p", dll], stdout=subprocess.PIPE)
266 return st.stdout.readlines()
267
268 def generate_def(dll, dfile):
269 """Given a dll file location, get all its exported symbols and dump them
270 into the given def file.
271
272 The .def file will be overwritten"""
273 dump = dump_table(dll)
274 for i in range(len(dump)):
275 if _START.match(dump[i].decode()):
276 break
277 else:
278 raise ValueError("Symbol table not found")
279
280 syms = []
281 for j in range(i+1, len(dump)):
282 m = _TABLE.match(dump[j].decode())
283 if m:
284 syms.append((int(m.group(1).strip()), m.group(2)))
285 else:
286 break
287
288 if len(syms) == 0:
289 log.warn('No symbols found in %s' % dll)
290
291 d = open(dfile, 'w')
292 d.write('LIBRARY %s\n' % os.path.basename(dll))
293 d.write(';CODE PRELOAD MOVEABLE DISCARDABLE\n')
294 d.write(';DATA PRELOAD SINGLE\n')
295 d.write('\nEXPORTS\n')
296 for s in syms:
297 #d.write('@%d %s\n' % (s[0], s[1]))
298 d.write('%s\n' % s[1])
299 d.close()
300
301 def find_dll(dll_name):
302
303 arch = {'AMD64' : 'amd64',
304 'Intel' : 'x86'}[get_build_architecture()]
305
306 def _find_dll_in_winsxs(dll_name):
307 # Walk through the WinSxS directory to find the dll.
308 winsxs_path = os.path.join(os.environ['WINDIR'], 'winsxs')
309 if not os.path.exists(winsxs_path):
310 return None
311 for root, dirs, files in os.walk(winsxs_path):
312 if dll_name in files and arch in root:
313 return os.path.join(root, dll_name)
314 return None
315
316 def _find_dll_in_path(dll_name):
317 # First, look in the Python directory, then scan PATH for
318 # the given dll name.
319 for path in [sys.prefix] + os.environ['PATH'].split(';'):
320 filepath = os.path.join(path, dll_name)
321 if os.path.exists(filepath):
322 return os.path.abspath(filepath)
323
324 return _find_dll_in_winsxs(dll_name) or _find_dll_in_path(dll_name)
325
326 def build_msvcr_library(debug=False):
327 if os.name != 'nt':
328 return False
329
330 msvcr_name = msvc_runtime_library()
331
332 # Skip using a custom library for versions < MSVC 8.0
333 if int(msvcr_name.lstrip('msvcr')) < 80:
334 log.debug('Skip building msvcr library: custom functionality not present')
335 return False
336
337 if debug:
338 msvcr_name += 'd'
339
340 # Skip if custom library already exists
341 out_name = "lib%s.a" % msvcr_name
342 out_file = os.path.join(sys.prefix, 'libs', out_name)
343 if os.path.isfile(out_file):
344 log.debug('Skip building msvcr library: "%s" exists' % (out_file))
345 return True
346
347 # Find the msvcr dll
348 msvcr_dll_name = msvcr_name + '.dll'
349 dll_file = find_dll(msvcr_dll_name)
350 if not dll_file:
351 log.warn('Cannot build msvcr library: "%s" not found' % msvcr_dll_name)
352 return False
353
354 def_name = "lib%s.def" % msvcr_name
355 def_file = os.path.join(sys.prefix, 'libs', def_name)
356
357 log.info('Building msvcr library: "%s" (from %s)' \
358 % (out_file, dll_file))
359
360 # Generate a symbol definition file from the msvcr dll
361 generate_def(dll_file, def_file)
362
363 # Create a custom mingw library for the given symbol definitions
364 cmd = ['dlltool', '-d', def_file, '-l', out_file]
365 retcode = subprocess.call(cmd)
366
367 # Clean up symbol definitions
368 os.remove(def_file)
369
370 return (not retcode)
371
372 def build_import_library():
373 if os.name != 'nt':
374 return
375
376 arch = get_build_architecture()
377 if arch == 'AMD64':
378 return _build_import_library_amd64()
379 elif arch == 'Intel':
380 return _build_import_library_x86()
381 else:
382 raise ValueError("Unhandled arch %s" % arch)
383
384 def _build_import_library_amd64():
385 dll_file = find_python_dll()
386
387 out_name = "libpython%d%d.a" % tuple(sys.version_info[:2])
388 out_file = os.path.join(sys.prefix, 'libs', out_name)
389 if os.path.isfile(out_file):
390 log.debug('Skip building import library: "%s" exists' % (out_file))
391 return
392
393 def_name = "python%d%d.def" % tuple(sys.version_info[:2])
394 def_file = os.path.join(sys.prefix, 'libs', def_name)
395
396 log.info('Building import library (arch=AMD64): "%s" (from %s)' \
397 % (out_file, dll_file))
398
399 generate_def(dll_file, def_file)
400
401 cmd = ['dlltool', '-d', def_file, '-l', out_file]
402 subprocess.Popen(cmd)
403
404 def _build_import_library_x86():
405 """ Build the import libraries for Mingw32-gcc on Windows
406 """
407 lib_name = "python%d%d.lib" % tuple(sys.version_info[:2])
408 lib_file = os.path.join(sys.prefix, 'libs', lib_name)
409 out_name = "libpython%d%d.a" % tuple(sys.version_info[:2])
410 out_file = os.path.join(sys.prefix, 'libs', out_name)
411 if not os.path.isfile(lib_file):
412 log.warn('Cannot build import library: "%s" not found' % (lib_file))
413 return
414 if os.path.isfile(out_file):
415 log.debug('Skip building import library: "%s" exists' % (out_file))
416 return
417 log.info('Building import library (ARCH=x86): "%s"' % (out_file))
418
419 from numpy.distutils import lib2def
420
421 def_name = "python%d%d.def" % tuple(sys.version_info[:2])
422 def_file = os.path.join(sys.prefix, 'libs', def_name)
423 nm_cmd = '%s %s' % (lib2def.DEFAULT_NM, lib_file)
424 nm_output = lib2def.getnm(nm_cmd)
425 dlist, flist = lib2def.parse_nm(nm_output)
426 lib2def.output_def(dlist, flist, lib2def.DEF_HEADER, open(def_file, 'w'))
427
428 dll_name = "python%d%d.dll" % tuple(sys.version_info[:2])
429 args = (dll_name, def_file, out_file)
430 cmd = 'dlltool --dllname %s --def %s --output-lib %s' % args
431 status = os.system(cmd)
432 # for now, fail silently
433 if status:
434 log.warn('Failed to build import library for gcc. Linking will fail.')
435 #if not success:
436 # msg = "Couldn't find import library, and failed to build it."
437 # raise DistutilsPlatformError(msg)
438 return
439
440 #=====================================
441 # Dealing with Visual Studio MANIFESTS
442 #=====================================
443
444 # Functions to deal with visual studio manifests. Manifest are a mechanism to
445 # enforce strong DLL versioning on windows, and has nothing to do with
446 # distutils MANIFEST. manifests are XML files with version info, and used by
447 # the OS loader; they are necessary when linking against a DLL not in the
448 # system path; in particular, official python 2.6 binary is built against the
449 # MS runtime 9 (the one from VS 2008), which is not available on most windows
450 # systems; python 2.6 installer does install it in the Win SxS (Side by side)
451 # directory, but this requires the manifest for this to work. This is a big
452 # mess, thanks MS for a wonderful system.
453
454 # XXX: ideally, we should use exactly the same version as used by python. I
455 # submitted a patch to get this version, but it was only included for python
456 # 2.6.1 and above. So for versions below, we use a "best guess".
457 _MSVCRVER_TO_FULLVER = {}
458 if sys.platform == 'win32':
459 try:
460 import msvcrt
461 # I took one version in my SxS directory: no idea if it is the good
462 # one, and we can't retrieve it from python
463 _MSVCRVER_TO_FULLVER['80'] = "8.0.50727.42"
464 _MSVCRVER_TO_FULLVER['90'] = "9.0.21022.8"
465 # Value from msvcrt.CRT_ASSEMBLY_VERSION under Python 3.3.0 on Windows XP:
466 _MSVCRVER_TO_FULLVER['100'] = "10.0.30319.460"
467 if hasattr(msvcrt, "CRT_ASSEMBLY_VERSION"):
468 major, minor, rest = msvcrt.CRT_ASSEMBLY_VERSION.split(".", 2)
469 _MSVCRVER_TO_FULLVER[major + minor] = msvcrt.CRT_ASSEMBLY_VERSION
470 del major, minor, rest
471 except ImportError:
472 # If we are here, means python was not built with MSVC. Not sure what to do
473 # in that case: manifest building will fail, but it should not be used in
474 # that case anyway
475 log.warn('Cannot import msvcrt: using manifest will not be possible')
476
477 def msvc_manifest_xml(maj, min):
478 """Given a major and minor version of the MSVCR, returns the
479 corresponding XML file."""
480 try:
481 fullver = _MSVCRVER_TO_FULLVER[str(maj * 10 + min)]
482 except KeyError:
483 raise ValueError("Version %d,%d of MSVCRT not supported yet" \
484 % (maj, min))
485 # Don't be fooled, it looks like an XML, but it is not. In particular, it
486 # should not have any space before starting, and its size should be
487 # divisible by 4, most likely for alignement constraints when the xml is
488 # embedded in the binary...
489 # This template was copied directly from the python 2.6 binary (using
490 # strings.exe from mingw on python.exe).
491 template = """\
492 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
493 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
494 <security>
495 <requestedPrivileges>
496 <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
497 </requestedPrivileges>
498 </security>
499 </trustInfo>
500 <dependency>
501 <dependentAssembly>
502 <assemblyIdentity type="win32" name="Microsoft.VC%(maj)d%(min)d.CRT" version="%(fullver)s" processorArchitecture="*" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
503 </dependentAssembly>
504 </dependency>
505 </assembly>"""
506
507 return template % {'fullver': fullver, 'maj': maj, 'min': min}
508
509 def manifest_rc(name, type='dll'):
510 """Return the rc file used to generate the res file which will be embedded
511 as manifest for given manifest file name, of given type ('dll' or
512 'exe').
513
514 Parameters
515 ----------
516 name : str
517 name of the manifest file to embed
518 type : str {'dll', 'exe'}
519 type of the binary which will embed the manifest
520
521 """
522 if type == 'dll':
523 rctype = 2
524 elif type == 'exe':
525 rctype = 1
526 else:
527 raise ValueError("Type %s not supported" % type)
528
529 return """\
530 #include "winuser.h"
531 %d RT_MANIFEST %s""" % (rctype, name)
532
533 def check_embedded_msvcr_match_linked(msver):
534 """msver is the ms runtime version used for the MANIFEST."""
535 # check msvcr major version are the same for linking and
536 # embedding
537 msvcv = msvc_runtime_library()
538 if msvcv:
539 assert msvcv.startswith("msvcr"), msvcv
540 # Dealing with something like "mscvr90" or "mscvr100", the last
541 # last digit is the minor release, want int("9") or int("10"):
542 maj = int(msvcv[5:-1])
543 if not maj == int(msver):
544 raise ValueError(
545 "Discrepancy between linked msvcr " \
546 "(%d) and the one about to be embedded " \
547 "(%d)" % (int(msver), maj))
548
549 def configtest_name(config):
550 base = os.path.basename(config._gen_temp_sourcefile("yo", [], "c"))
551 return os.path.splitext(base)[0]
552
553 def manifest_name(config):
554 # Get configest name (including suffix)
555 root = configtest_name(config)
556 exext = config.compiler.exe_extension
557 return root + exext + ".manifest"
558
559 def rc_name(config):
560 # Get configest name (including suffix)
561 root = configtest_name(config)
562 return root + ".rc"
563
564 def generate_manifest(config):
565 msver = get_build_msvc_version()
566 if msver is not None:
567 if msver >= 8:
568 check_embedded_msvcr_match_linked(msver)
569 ma = int(msver)
570 mi = int((msver - ma) * 10)
571 # Write the manifest file
572 manxml = msvc_manifest_xml(ma, mi)
573 man = open(manifest_name(config), "w")
574 config.temp_files.append(manifest_name(config))
575 man.write(manxml)
576 man.close()
577 # # Write the rc file
578 # manrc = manifest_rc(manifest_name(self), "exe")
579 # rc = open(rc_name(self), "w")
580 # self.temp_files.append(manrc)
581 # rc.write(manrc)
582 # rc.close()