Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/distutils/ccompiler.py
7757 views
1
import os
2
import re
3
import sys
4
import shlex
5
import time
6
import subprocess
7
from copy import copy
8
from distutils import ccompiler
9
from distutils.ccompiler import (
10
compiler_class, gen_lib_options, get_default_compiler, new_compiler,
11
CCompiler
12
)
13
from distutils.errors import (
14
DistutilsExecError, DistutilsModuleError, DistutilsPlatformError,
15
CompileError, UnknownFileError
16
)
17
from distutils.sysconfig import customize_compiler
18
from distutils.version import LooseVersion
19
20
from numpy.distutils import log
21
from numpy.distutils.exec_command import (
22
filepath_from_subprocess_output, forward_bytes_to_stdout
23
)
24
from numpy.distutils.misc_util import cyg2win32, is_sequence, mingw32, \
25
get_num_build_jobs, \
26
_commandline_dep_string, \
27
sanitize_cxx_flags
28
29
# globals for parallel build management
30
import threading
31
32
_job_semaphore = None
33
_global_lock = threading.Lock()
34
_processing_files = set()
35
36
37
def _needs_build(obj, cc_args, extra_postargs, pp_opts):
38
"""
39
Check if an objects needs to be rebuild based on its dependencies
40
41
Parameters
42
----------
43
obj : str
44
object file
45
46
Returns
47
-------
48
bool
49
"""
50
# defined in unixcompiler.py
51
dep_file = obj + '.d'
52
if not os.path.exists(dep_file):
53
return True
54
55
# dep_file is a makefile containing 'object: dependencies'
56
# formatted like posix shell (spaces escaped, \ line continuations)
57
# the last line contains the compiler commandline arguments as some
58
# projects may compile an extension multiple times with different
59
# arguments
60
with open(dep_file, "r") as f:
61
lines = f.readlines()
62
63
cmdline =_commandline_dep_string(cc_args, extra_postargs, pp_opts)
64
last_cmdline = lines[-1]
65
if last_cmdline != cmdline:
66
return True
67
68
contents = ''.join(lines[:-1])
69
deps = [x for x in shlex.split(contents, posix=True)
70
if x != "\n" and not x.endswith(":")]
71
72
try:
73
t_obj = os.stat(obj).st_mtime
74
75
# check if any of the dependencies is newer than the object
76
# the dependencies includes the source used to create the object
77
for f in deps:
78
if os.stat(f).st_mtime > t_obj:
79
return True
80
except OSError:
81
# no object counts as newer (shouldn't happen if dep_file exists)
82
return True
83
84
return False
85
86
87
def replace_method(klass, method_name, func):
88
# Py3k does not have unbound method anymore, MethodType does not work
89
m = lambda self, *args, **kw: func(self, *args, **kw)
90
setattr(klass, method_name, m)
91
92
93
######################################################################
94
## Method that subclasses may redefine. But don't call this method,
95
## it i private to CCompiler class and may return unexpected
96
## results if used elsewhere. So, you have been warned..
97
98
def CCompiler_find_executables(self):
99
"""
100
Does nothing here, but is called by the get_version method and can be
101
overridden by subclasses. In particular it is redefined in the `FCompiler`
102
class where more documentation can be found.
103
104
"""
105
pass
106
107
108
replace_method(CCompiler, 'find_executables', CCompiler_find_executables)
109
110
111
# Using customized CCompiler.spawn.
112
def CCompiler_spawn(self, cmd, display=None, env=None):
113
"""
114
Execute a command in a sub-process.
115
116
Parameters
117
----------
118
cmd : str
119
The command to execute.
120
display : str or sequence of str, optional
121
The text to add to the log file kept by `numpy.distutils`.
122
If not given, `display` is equal to `cmd`.
123
env: a dictionary for environment variables, optional
124
125
Returns
126
-------
127
None
128
129
Raises
130
------
131
DistutilsExecError
132
If the command failed, i.e. the exit status was not 0.
133
134
"""
135
env = env if env is not None else dict(os.environ)
136
if display is None:
137
display = cmd
138
if is_sequence(display):
139
display = ' '.join(list(display))
140
log.info(display)
141
try:
142
if self.verbose:
143
subprocess.check_output(cmd, env=env)
144
else:
145
subprocess.check_output(cmd, stderr=subprocess.STDOUT, env=env)
146
except subprocess.CalledProcessError as exc:
147
o = exc.output
148
s = exc.returncode
149
except OSError as e:
150
# OSError doesn't have the same hooks for the exception
151
# output, but exec_command() historically would use an
152
# empty string for EnvironmentError (base class for
153
# OSError)
154
# o = b''
155
# still that would make the end-user lost in translation!
156
o = f"\n\n{e}\n\n\n"
157
try:
158
o = o.encode(sys.stdout.encoding)
159
except AttributeError:
160
o = o.encode('utf8')
161
# status previously used by exec_command() for parent
162
# of OSError
163
s = 127
164
else:
165
# use a convenience return here so that any kind of
166
# caught exception will execute the default code after the
167
# try / except block, which handles various exceptions
168
return None
169
170
if is_sequence(cmd):
171
cmd = ' '.join(list(cmd))
172
173
if self.verbose:
174
forward_bytes_to_stdout(o)
175
176
if re.search(b'Too many open files', o):
177
msg = '\nTry rerunning setup command until build succeeds.'
178
else:
179
msg = ''
180
raise DistutilsExecError('Command "%s" failed with exit status %d%s' %
181
(cmd, s, msg))
182
183
replace_method(CCompiler, 'spawn', CCompiler_spawn)
184
185
def CCompiler_object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
186
"""
187
Return the name of the object files for the given source files.
188
189
Parameters
190
----------
191
source_filenames : list of str
192
The list of paths to source files. Paths can be either relative or
193
absolute, this is handled transparently.
194
strip_dir : bool, optional
195
Whether to strip the directory from the returned paths. If True,
196
the file name prepended by `output_dir` is returned. Default is False.
197
output_dir : str, optional
198
If given, this path is prepended to the returned paths to the
199
object files.
200
201
Returns
202
-------
203
obj_names : list of str
204
The list of paths to the object files corresponding to the source
205
files in `source_filenames`.
206
207
"""
208
if output_dir is None:
209
output_dir = ''
210
obj_names = []
211
for src_name in source_filenames:
212
base, ext = os.path.splitext(os.path.normpath(src_name))
213
base = os.path.splitdrive(base)[1] # Chop off the drive
214
base = base[os.path.isabs(base):] # If abs, chop off leading /
215
if base.startswith('..'):
216
# Resolve starting relative path components, middle ones
217
# (if any) have been handled by os.path.normpath above.
218
i = base.rfind('..')+2
219
d = base[:i]
220
d = os.path.basename(os.path.abspath(d))
221
base = d + base[i:]
222
if ext not in self.src_extensions:
223
raise UnknownFileError("unknown file type '%s' (from '%s')" % (ext, src_name))
224
if strip_dir:
225
base = os.path.basename(base)
226
obj_name = os.path.join(output_dir, base + self.obj_extension)
227
obj_names.append(obj_name)
228
return obj_names
229
230
replace_method(CCompiler, 'object_filenames', CCompiler_object_filenames)
231
232
def CCompiler_compile(self, sources, output_dir=None, macros=None,
233
include_dirs=None, debug=0, extra_preargs=None,
234
extra_postargs=None, depends=None):
235
"""
236
Compile one or more source files.
237
238
Please refer to the Python distutils API reference for more details.
239
240
Parameters
241
----------
242
sources : list of str
243
A list of filenames
244
output_dir : str, optional
245
Path to the output directory.
246
macros : list of tuples
247
A list of macro definitions.
248
include_dirs : list of str, optional
249
The directories to add to the default include file search path for
250
this compilation only.
251
debug : bool, optional
252
Whether or not to output debug symbols in or alongside the object
253
file(s).
254
extra_preargs, extra_postargs : ?
255
Extra pre- and post-arguments.
256
depends : list of str, optional
257
A list of file names that all targets depend on.
258
259
Returns
260
-------
261
objects : list of str
262
A list of object file names, one per source file `sources`.
263
264
Raises
265
------
266
CompileError
267
If compilation fails.
268
269
"""
270
global _job_semaphore
271
272
jobs = get_num_build_jobs()
273
274
# setup semaphore to not exceed number of compile jobs when parallelized at
275
# extension level (python >= 3.5)
276
with _global_lock:
277
if _job_semaphore is None:
278
_job_semaphore = threading.Semaphore(jobs)
279
280
if not sources:
281
return []
282
from numpy.distutils.fcompiler import (FCompiler, is_f_file,
283
has_f90_header)
284
if isinstance(self, FCompiler):
285
display = []
286
for fc in ['f77', 'f90', 'fix']:
287
fcomp = getattr(self, 'compiler_'+fc)
288
if fcomp is None:
289
continue
290
display.append("Fortran %s compiler: %s" % (fc, ' '.join(fcomp)))
291
display = '\n'.join(display)
292
else:
293
ccomp = self.compiler_so
294
display = "C compiler: %s\n" % (' '.join(ccomp),)
295
log.info(display)
296
macros, objects, extra_postargs, pp_opts, build = \
297
self._setup_compile(output_dir, macros, include_dirs, sources,
298
depends, extra_postargs)
299
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
300
display = "compile options: '%s'" % (' '.join(cc_args))
301
if extra_postargs:
302
display += "\nextra options: '%s'" % (' '.join(extra_postargs))
303
log.info(display)
304
305
def single_compile(args):
306
obj, (src, ext) = args
307
if not _needs_build(obj, cc_args, extra_postargs, pp_opts):
308
return
309
310
# check if we are currently already processing the same object
311
# happens when using the same source in multiple extensions
312
while True:
313
# need explicit lock as there is no atomic check and add with GIL
314
with _global_lock:
315
# file not being worked on, start working
316
if obj not in _processing_files:
317
_processing_files.add(obj)
318
break
319
# wait for the processing to end
320
time.sleep(0.1)
321
322
try:
323
# retrieve slot from our #job semaphore and build
324
with _job_semaphore:
325
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
326
finally:
327
# register being done processing
328
with _global_lock:
329
_processing_files.remove(obj)
330
331
332
if isinstance(self, FCompiler):
333
objects_to_build = list(build.keys())
334
f77_objects, other_objects = [], []
335
for obj in objects:
336
if obj in objects_to_build:
337
src, ext = build[obj]
338
if self.compiler_type=='absoft':
339
obj = cyg2win32(obj)
340
src = cyg2win32(src)
341
if is_f_file(src) and not has_f90_header(src):
342
f77_objects.append((obj, (src, ext)))
343
else:
344
other_objects.append((obj, (src, ext)))
345
346
# f77 objects can be built in parallel
347
build_items = f77_objects
348
# build f90 modules serial, module files are generated during
349
# compilation and may be used by files later in the list so the
350
# ordering is important
351
for o in other_objects:
352
single_compile(o)
353
else:
354
build_items = build.items()
355
356
if len(build) > 1 and jobs > 1:
357
# build parallel
358
from concurrent.futures import ThreadPoolExecutor
359
with ThreadPoolExecutor(jobs) as pool:
360
pool.map(single_compile, build_items)
361
else:
362
# build serial
363
for o in build_items:
364
single_compile(o)
365
366
# Return *all* object filenames, not just the ones we just built.
367
return objects
368
369
replace_method(CCompiler, 'compile', CCompiler_compile)
370
371
def CCompiler_customize_cmd(self, cmd, ignore=()):
372
"""
373
Customize compiler using distutils command.
374
375
Parameters
376
----------
377
cmd : class instance
378
An instance inheriting from `distutils.cmd.Command`.
379
ignore : sequence of str, optional
380
List of `CCompiler` commands (without ``'set_'``) that should not be
381
altered. Strings that are checked for are:
382
``('include_dirs', 'define', 'undef', 'libraries', 'library_dirs',
383
'rpath', 'link_objects')``.
384
385
Returns
386
-------
387
None
388
389
"""
390
log.info('customize %s using %s' % (self.__class__.__name__,
391
cmd.__class__.__name__))
392
393
if hasattr(self, 'compiler') and 'clang' in self.compiler[0]:
394
# clang defaults to a non-strict floating error point model.
395
# Since NumPy and most Python libs give warnings for these, override:
396
self.compiler.append('-ftrapping-math')
397
self.compiler_so.append('-ftrapping-math')
398
399
def allow(attr):
400
return getattr(cmd, attr, None) is not None and attr not in ignore
401
402
if allow('include_dirs'):
403
self.set_include_dirs(cmd.include_dirs)
404
if allow('define'):
405
for (name, value) in cmd.define:
406
self.define_macro(name, value)
407
if allow('undef'):
408
for macro in cmd.undef:
409
self.undefine_macro(macro)
410
if allow('libraries'):
411
self.set_libraries(self.libraries + cmd.libraries)
412
if allow('library_dirs'):
413
self.set_library_dirs(self.library_dirs + cmd.library_dirs)
414
if allow('rpath'):
415
self.set_runtime_library_dirs(cmd.rpath)
416
if allow('link_objects'):
417
self.set_link_objects(cmd.link_objects)
418
419
replace_method(CCompiler, 'customize_cmd', CCompiler_customize_cmd)
420
421
def _compiler_to_string(compiler):
422
props = []
423
mx = 0
424
keys = list(compiler.executables.keys())
425
for key in ['version', 'libraries', 'library_dirs',
426
'object_switch', 'compile_switch',
427
'include_dirs', 'define', 'undef', 'rpath', 'link_objects']:
428
if key not in keys:
429
keys.append(key)
430
for key in keys:
431
if hasattr(compiler, key):
432
v = getattr(compiler, key)
433
mx = max(mx, len(key))
434
props.append((key, repr(v)))
435
fmt = '%-' + repr(mx+1) + 's = %s'
436
lines = [fmt % prop for prop in props]
437
return '\n'.join(lines)
438
439
def CCompiler_show_customization(self):
440
"""
441
Print the compiler customizations to stdout.
442
443
Parameters
444
----------
445
None
446
447
Returns
448
-------
449
None
450
451
Notes
452
-----
453
Printing is only done if the distutils log threshold is < 2.
454
455
"""
456
try:
457
self.get_version()
458
except Exception:
459
pass
460
if log._global_log.threshold<2:
461
print('*'*80)
462
print(self.__class__)
463
print(_compiler_to_string(self))
464
print('*'*80)
465
466
replace_method(CCompiler, 'show_customization', CCompiler_show_customization)
467
468
def CCompiler_customize(self, dist, need_cxx=0):
469
"""
470
Do any platform-specific customization of a compiler instance.
471
472
This method calls `distutils.sysconfig.customize_compiler` for
473
platform-specific customization, as well as optionally remove a flag
474
to suppress spurious warnings in case C++ code is being compiled.
475
476
Parameters
477
----------
478
dist : object
479
This parameter is not used for anything.
480
need_cxx : bool, optional
481
Whether or not C++ has to be compiled. If so (True), the
482
``"-Wstrict-prototypes"`` option is removed to prevent spurious
483
warnings. Default is False.
484
485
Returns
486
-------
487
None
488
489
Notes
490
-----
491
All the default options used by distutils can be extracted with::
492
493
from distutils import sysconfig
494
sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS',
495
'CCSHARED', 'LDSHARED', 'SO')
496
497
"""
498
# See FCompiler.customize for suggested usage.
499
log.info('customize %s' % (self.__class__.__name__))
500
customize_compiler(self)
501
if need_cxx:
502
# In general, distutils uses -Wstrict-prototypes, but this option is
503
# not valid for C++ code, only for C. Remove it if it's there to
504
# avoid a spurious warning on every compilation.
505
try:
506
self.compiler_so.remove('-Wstrict-prototypes')
507
except (AttributeError, ValueError):
508
pass
509
510
if hasattr(self, 'compiler') and 'cc' in self.compiler[0]:
511
if not self.compiler_cxx:
512
if self.compiler[0].startswith('gcc'):
513
a, b = 'gcc', 'g++'
514
else:
515
a, b = 'cc', 'c++'
516
self.compiler_cxx = [self.compiler[0].replace(a, b)]\
517
+ self.compiler[1:]
518
else:
519
if hasattr(self, 'compiler'):
520
log.warn("#### %s #######" % (self.compiler,))
521
if not hasattr(self, 'compiler_cxx'):
522
log.warn('Missing compiler_cxx fix for ' + self.__class__.__name__)
523
524
525
# check if compiler supports gcc style automatic dependencies
526
# run on every extension so skip for known good compilers
527
if hasattr(self, 'compiler') and ('gcc' in self.compiler[0] or
528
'g++' in self.compiler[0] or
529
'clang' in self.compiler[0]):
530
self._auto_depends = True
531
elif os.name == 'posix':
532
import tempfile
533
import shutil
534
tmpdir = tempfile.mkdtemp()
535
try:
536
fn = os.path.join(tmpdir, "file.c")
537
with open(fn, "w") as f:
538
f.write("int a;\n")
539
self.compile([fn], output_dir=tmpdir,
540
extra_preargs=['-MMD', '-MF', fn + '.d'])
541
self._auto_depends = True
542
except CompileError:
543
self._auto_depends = False
544
finally:
545
shutil.rmtree(tmpdir)
546
547
return
548
549
replace_method(CCompiler, 'customize', CCompiler_customize)
550
551
def simple_version_match(pat=r'[-.\d]+', ignore='', start=''):
552
"""
553
Simple matching of version numbers, for use in CCompiler and FCompiler.
554
555
Parameters
556
----------
557
pat : str, optional
558
A regular expression matching version numbers.
559
Default is ``r'[-.\\d]+'``.
560
ignore : str, optional
561
A regular expression matching patterns to skip.
562
Default is ``''``, in which case nothing is skipped.
563
start : str, optional
564
A regular expression matching the start of where to start looking
565
for version numbers.
566
Default is ``''``, in which case searching is started at the
567
beginning of the version string given to `matcher`.
568
569
Returns
570
-------
571
matcher : callable
572
A function that is appropriate to use as the ``.version_match``
573
attribute of a `CCompiler` class. `matcher` takes a single parameter,
574
a version string.
575
576
"""
577
def matcher(self, version_string):
578
# version string may appear in the second line, so getting rid
579
# of new lines:
580
version_string = version_string.replace('\n', ' ')
581
pos = 0
582
if start:
583
m = re.match(start, version_string)
584
if not m:
585
return None
586
pos = m.end()
587
while True:
588
m = re.search(pat, version_string[pos:])
589
if not m:
590
return None
591
if ignore and re.match(ignore, m.group(0)):
592
pos = m.end()
593
continue
594
break
595
return m.group(0)
596
return matcher
597
598
def CCompiler_get_version(self, force=False, ok_status=[0]):
599
"""
600
Return compiler version, or None if compiler is not available.
601
602
Parameters
603
----------
604
force : bool, optional
605
If True, force a new determination of the version, even if the
606
compiler already has a version attribute. Default is False.
607
ok_status : list of int, optional
608
The list of status values returned by the version look-up process
609
for which a version string is returned. If the status value is not
610
in `ok_status`, None is returned. Default is ``[0]``.
611
612
Returns
613
-------
614
version : str or None
615
Version string, in the format of `distutils.version.LooseVersion`.
616
617
"""
618
if not force and hasattr(self, 'version'):
619
return self.version
620
self.find_executables()
621
try:
622
version_cmd = self.version_cmd
623
except AttributeError:
624
return None
625
if not version_cmd or not version_cmd[0]:
626
return None
627
try:
628
matcher = self.version_match
629
except AttributeError:
630
try:
631
pat = self.version_pattern
632
except AttributeError:
633
return None
634
def matcher(version_string):
635
m = re.match(pat, version_string)
636
if not m:
637
return None
638
version = m.group('version')
639
return version
640
641
try:
642
output = subprocess.check_output(version_cmd, stderr=subprocess.STDOUT)
643
except subprocess.CalledProcessError as exc:
644
output = exc.output
645
status = exc.returncode
646
except OSError:
647
# match the historical returns for a parent
648
# exception class caught by exec_command()
649
status = 127
650
output = b''
651
else:
652
# output isn't actually a filepath but we do this
653
# for now to match previous distutils behavior
654
output = filepath_from_subprocess_output(output)
655
status = 0
656
657
version = None
658
if status in ok_status:
659
version = matcher(output)
660
if version:
661
version = LooseVersion(version)
662
self.version = version
663
return version
664
665
replace_method(CCompiler, 'get_version', CCompiler_get_version)
666
667
def CCompiler_cxx_compiler(self):
668
"""
669
Return the C++ compiler.
670
671
Parameters
672
----------
673
None
674
675
Returns
676
-------
677
cxx : class instance
678
The C++ compiler, as a `CCompiler` instance.
679
680
"""
681
if self.compiler_type in ('msvc', 'intelw', 'intelemw'):
682
return self
683
684
cxx = copy(self)
685
cxx.compiler_cxx = cxx.compiler_cxx
686
cxx.compiler_so = [cxx.compiler_cxx[0]] + \
687
sanitize_cxx_flags(cxx.compiler_so[1:])
688
if sys.platform.startswith('aix') and 'ld_so_aix' in cxx.linker_so[0]:
689
# AIX needs the ld_so_aix script included with Python
690
cxx.linker_so = [cxx.linker_so[0], cxx.compiler_cxx[0]] \
691
+ cxx.linker_so[2:]
692
else:
693
cxx.linker_so = [cxx.compiler_cxx[0]] + cxx.linker_so[1:]
694
return cxx
695
696
replace_method(CCompiler, 'cxx_compiler', CCompiler_cxx_compiler)
697
698
compiler_class['intel'] = ('intelccompiler', 'IntelCCompiler',
699
"Intel C Compiler for 32-bit applications")
700
compiler_class['intele'] = ('intelccompiler', 'IntelItaniumCCompiler',
701
"Intel C Itanium Compiler for Itanium-based applications")
702
compiler_class['intelem'] = ('intelccompiler', 'IntelEM64TCCompiler',
703
"Intel C Compiler for 64-bit applications")
704
compiler_class['intelw'] = ('intelccompiler', 'IntelCCompilerW',
705
"Intel C Compiler for 32-bit applications on Windows")
706
compiler_class['intelemw'] = ('intelccompiler', 'IntelEM64TCCompilerW',
707
"Intel C Compiler for 64-bit applications on Windows")
708
compiler_class['pathcc'] = ('pathccompiler', 'PathScaleCCompiler',
709
"PathScale Compiler for SiCortex-based applications")
710
compiler_class['arm'] = ('armccompiler', 'ArmCCompiler',
711
"Arm C Compiler")
712
713
ccompiler._default_compilers += (('linux.*', 'intel'),
714
('linux.*', 'intele'),
715
('linux.*', 'intelem'),
716
('linux.*', 'pathcc'),
717
('nt', 'intelw'),
718
('nt', 'intelemw'))
719
720
if sys.platform == 'win32':
721
compiler_class['mingw32'] = ('mingw32ccompiler', 'Mingw32CCompiler',
722
"Mingw32 port of GNU C Compiler for Win32"\
723
"(for MSC built Python)")
724
if mingw32():
725
# On windows platforms, we want to default to mingw32 (gcc)
726
# because msvc can't build blitz stuff.
727
log.info('Setting mingw32 as default compiler for nt.')
728
ccompiler._default_compilers = (('nt', 'mingw32'),) \
729
+ ccompiler._default_compilers
730
731
732
_distutils_new_compiler = new_compiler
733
def new_compiler (plat=None,
734
compiler=None,
735
verbose=None,
736
dry_run=0,
737
force=0):
738
# Try first C compilers from numpy.distutils.
739
if verbose is None:
740
verbose = log.get_threshold() <= log.INFO
741
if plat is None:
742
plat = os.name
743
try:
744
if compiler is None:
745
compiler = get_default_compiler(plat)
746
(module_name, class_name, long_description) = compiler_class[compiler]
747
except KeyError:
748
msg = "don't know how to compile C/C++ code on platform '%s'" % plat
749
if compiler is not None:
750
msg = msg + " with '%s' compiler" % compiler
751
raise DistutilsPlatformError(msg)
752
module_name = "numpy.distutils." + module_name
753
try:
754
__import__ (module_name)
755
except ImportError as e:
756
msg = str(e)
757
log.info('%s in numpy.distutils; trying from distutils',
758
str(msg))
759
module_name = module_name[6:]
760
try:
761
__import__(module_name)
762
except ImportError as e:
763
msg = str(e)
764
raise DistutilsModuleError("can't compile C/C++ code: unable to load module '%s'" % \
765
module_name)
766
try:
767
module = sys.modules[module_name]
768
klass = vars(module)[class_name]
769
except KeyError:
770
raise DistutilsModuleError(("can't compile C/C++ code: unable to find class '%s' " +
771
"in module '%s'") % (class_name, module_name))
772
compiler = klass(None, dry_run, force)
773
compiler.verbose = verbose
774
log.debug('new_compiler returns %s' % (klass))
775
return compiler
776
777
ccompiler.new_compiler = new_compiler
778
779
_distutils_gen_lib_options = gen_lib_options
780
def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
781
# the version of this function provided by CPython allows the following
782
# to return lists, which are unpacked automatically:
783
# - compiler.runtime_library_dir_option
784
# our version extends the behavior to:
785
# - compiler.library_dir_option
786
# - compiler.library_option
787
# - compiler.find_library_file
788
r = _distutils_gen_lib_options(compiler, library_dirs,
789
runtime_library_dirs, libraries)
790
lib_opts = []
791
for i in r:
792
if is_sequence(i):
793
lib_opts.extend(list(i))
794
else:
795
lib_opts.append(i)
796
return lib_opts
797
ccompiler.gen_lib_options = gen_lib_options
798
799
# Also fix up the various compiler modules, which do
800
# from distutils.ccompiler import gen_lib_options
801
# Don't bother with mwerks, as we don't support Classic Mac.
802
for _cc in ['msvc9', 'msvc', '_msvc', 'bcpp', 'cygwinc', 'emxc', 'unixc']:
803
_m = sys.modules.get('distutils.' + _cc + 'compiler')
804
if _m is not None:
805
setattr(_m, 'gen_lib_options', gen_lib_options)
806
807
808