1
# Author: Lisandro Dalcin
2
# Contact: dalcinl@gmail.com
5
Support for building mpi4py with distutils.
8
# -----------------------------------------------------------------------------
11
if sys.version[:3] == '3.0':
12
from distutils import version
13
version.cmp = lambda a, b : (a > b) - (a < b)
17
# -----------------------------------------------------------------------------
19
import sys, os, platform, re
20
from distutils import sysconfig
21
from distutils.util import convert_path
22
from distutils.util import split_quoted
23
from distutils.spawn import find_executable
24
from distutils import log
26
def fix_config_vars(names, values):
28
if sys.platform == 'darwin':
29
if 'ARCHFLAGS' in os.environ:
30
ARCHFLAGS = os.environ['ARCHFLAGS']
31
for i, flag in enumerate(list(values)):
32
flag, count = re.subn('-arch\s+\w+', ' ', flag)
33
if count and ARCHFLAGS:
34
flag = flag + ' ' + ARCHFLAGS
36
if 'SDKROOT' in os.environ:
37
SDKROOT = os.environ['SDKROOT']
38
for i, flag in enumerate(list(values)):
39
flag, count = re.subn('-isysroot [^ \t]*', ' ', flag)
41
flag = flag + ' ' + '-isysroot ' + SDKROOT
45
def get_config_vars(*names):
46
# Core Python configuration
47
values = sysconfig.get_config_vars(*names)
48
# Do any distutils flags fixup right now
49
values = fix_config_vars(names, values)
52
def fix_compiler_cmd(cc, mpicc):
53
if not mpicc: return cc
54
if not cc: return mpicc
55
from os.path import basename
58
while basename(cc[i]) == 'env':
65
def fix_linker_cmd(ld, mpild):
66
if not mpild: return ld
67
if not ld: return mpild
68
from os.path import basename
71
if (sys.platform.startswith('aix') and
72
basename(ld[i]) == 'ld_so_aix'):
74
while basename(ld[i]) == 'env':
81
def split_linker_cmd(ld):
82
from os.path import basename
85
if (sys.platform.startswith('aix') and
86
basename(pyld[i]) == 'ld_so_aix'):
88
while basename(ld[i]) == 'env':
93
ld, flags = ' '.join(ld[:p]), ' '.join(ld[p:])
96
from distutils.unixccompiler import UnixCCompiler
97
rpath_option_orig = UnixCCompiler.runtime_library_dir_option
98
def rpath_option(compiler, dir):
99
option = rpath_option_orig(compiler, dir)
100
if sys.platform.startswith('linux'):
101
if option.startswith('-R'):
102
option = option.replace('-R', '-Wl,-rpath,', 1)
103
elif option.startswith('-Wl,-R,'):
104
option = option.replace('-Wl,-R,', '-Wl,-rpath,', 1)
106
UnixCCompiler.runtime_library_dir_option = rpath_option
108
def customize_compiler(compiler, lang=None,
109
mpicc=None, mpicxx=None, mpild=None,
113
if compiler.compiler_type == 'unix':
114
# Distutils configuration, actually obtained by parsing
115
# :file:{prefix}/lib[32|64]/python{X}.{Y}/config/Makefile
116
(cc, cxx, ccshared, ld,
117
basecflags, opt) = get_config_vars (
118
'CC', 'CXX', 'CCSHARED', 'LDSHARED',
120
cc = cc .replace('-pthread', '')
121
cxx = cxx .replace('-pthread', '')
122
ld = ld .replace('-pthread', '')
123
ld, ldshared = split_linker_cmd(ld)
124
basecflags, opt = basecflags or '', opt or ''
125
ccshared = ccshared or ''
126
ldshared = ldshared or ''
127
# Compiler command overriding
128
if not mpild and (mpicc or mpicxx):
134
mpild = mpicc or mpicxx
136
cc = fix_compiler_cmd(cc, mpicc)
138
cxx = fix_compiler_cmd(cxx, mpicxx)
140
ld = fix_linker_cmd(ld, mpild)
141
# Environment handling
142
cppflags = cflags = cxxflags = ldflags = ''
143
CPPFLAGS = environ.get('CPPFLAGS', '')
144
CFLAGS = environ.get('CFLAGS', '')
145
CXXFLAGS = environ.get('CXXFLAGS', '')
146
LDFLAGS = environ.get('LDFLAGS', '')
148
cppflags = cppflags + ' ' + CPPFLAGS
149
cflags = cflags + ' ' + CPPFLAGS
150
cxxflags = cxxflags + ' ' + CPPFLAGS
151
ldflags = ldflags + ' ' + CPPFLAGS
153
cflags = cflags + ' ' + CFLAGS
154
ldflags = ldflags + ' ' + CFLAGS
156
cxxflags = cxxflags + ' ' + CXXFLAGS
157
ldflags = ldflags + ' ' + CXXFLAGS
159
ldflags = ldflags + ' ' + LDFLAGS
160
basecflags = environ.get('BASECFLAGS', basecflags)
161
opt = environ.get('OPT', opt )
162
ccshared = environ.get('CCSHARED', ccshared)
163
ldshared = environ.get('LDSHARED', ldshared)
164
cflags = ' '.join((basecflags, opt, cflags))
165
cxxflags = ' '.join((basecflags, opt, cxxflags))
166
cxxflags = cxxflags.replace('-Wstrict-prototypes', '')
167
# Distutils compiler setup
168
cpp = os.environ.get('CPP') or (cc + ' -E')
169
cc_so = cc + ' ' + ccshared
170
cxx_so = cxx + ' ' + ccshared
171
ld_so = ld + ' ' + ldshared
172
compiler.set_executables(
173
preprocessor = cpp + ' ' + cppflags,
174
compiler = cc + ' ' + cflags,
175
compiler_so = cc_so + ' ' + cflags,
176
compiler_cxx = cxx_so + ' ' + cxxflags,
177
linker_so = ld_so + ' ' + ldflags,
178
linker_exe = ld + ' ' + ldflags,
180
try: compiler.compiler_cxx.remove('-Wstrict-prototypes')
182
if compiler.compiler_type == 'mingw32':
183
compiler.set_executables(
184
preprocessor = 'gcc -mno-cygwin -E',
186
if compiler.compiler_type in ('unix', 'cygwin', 'mingw32'):
188
def find_cmd_pos(cmd):
190
if os.path.basename(cmd[pos]) == "env":
192
while '=' in cmd[pos]:
195
i = find_cmd_pos(compiler.compiler_so)
196
j = find_cmd_pos(compiler.compiler_cxx)
197
compiler.compiler_so[i] = compiler.compiler_cxx[j]
198
try: compiler.compiler_so.remove('-Wstrict-prototypes')
200
if compiler.compiler_type == 'msvc':
201
if not compiler.initialized:
202
compiler.initialize()
203
compiler.ldflags_shared.append('/MANIFEST')
204
compiler.ldflags_shared_debug.append('/MANIFEST')
206
# -----------------------------------------------------------------------------
209
from mpiconfig import Config
211
from conf.mpiconfig import Config
213
def configuration(command_obj, verbose=True):
215
config.setup(command_obj)
217
if config.section and config.filename:
218
log.info("MPI configuration: [%s] from '%s'",
219
config.section, ','.join(config.filename))
223
def configure_compiler(compiler, config, lang=None):
225
mpicc = config.get('mpicc')
226
mpicxx = config.get('mpicxx')
227
mpild = config.get('mpild')
228
customize_compiler(compiler, lang,
229
mpicc=mpicc, mpicxx=mpicxx, mpild=mpild)
231
for k, v in config.get('define_macros', []):
232
compiler.define_macro(k, v)
233
for v in config.get('undef_macros', []):
234
compiler.undefine_macro(v)
235
for v in config.get('include_dirs', []):
236
compiler.add_include_dir(v)
237
for v in config.get('libraries', []):
238
compiler.add_library(v)
239
for v in config.get('library_dirs', []):
240
compiler.add_library_dir(v)
241
for v in config.get('runtime_library_dirs', []):
242
compiler.add_runtime_library_dir(v)
243
for v in config.get('extra_objects', []):
244
compiler.add_link_object(v)
245
if compiler.compiler_type in \
246
('unix', 'intel', 'cygwin', 'mingw32'):
247
cc_args = config.get('extra_compile_args', [])
248
ld_args = config.get('extra_link_args', [])
249
compiler.compiler += cc_args
250
compiler.compiler_so += cc_args
251
compiler.compiler_cxx += cc_args
252
compiler.linker_so += ld_args
253
compiler.linker_exe += ld_args
256
# -----------------------------------------------------------------------------
259
from mpiscanner import Scanner
262
from conf.mpiscanner import Scanner
264
class Scanner(object):
265
def parse_file(self, *args):
266
raise NotImplementedError(
267
"You forgot to grab 'mpiscanner.py'")
269
class ConfigureMPI(object):
272
SOURCES = [os.path.join('include', 'mpi4py', 'mpi.pxi')]
274
CONFIG_H = 'config.h'
275
MISSING_H = 'missing.h'
277
def __init__(self, config_cmd):
278
self.scanner = Scanner()
279
for filename in self.SOURCES:
280
fullname = os.path.join(self.SRCDIR, filename)
281
self.scanner.parse_file(fullname)
282
self.config_cmd = config_cmd
286
for name, code in self.scanner.itertests():
287
log.info("checking for '%s' ..." % name)
288
body = self.gen_one(results, code)
289
ok = self.run_one(body)
291
log.info("**** failed check for '%s'" % name)
292
results.append((name, ok))
295
def dump(self, results):
296
destdir = self.DESTDIR
297
config_h = os.path.join(destdir, self.CONFIG_H)
298
missing_h = os.path.join(destdir, self.MISSING_H)
299
log.info("writing '%s'", config_h)
300
self.scanner.dump_config_h(config_h, results)
301
log.info("writing '%s'", missing_h)
302
self.scanner.dump_missing_h(missing_h, None)
304
def gen_one(self, results, code):
306
configtest_h = "_configtest.h"
307
self.config_cmd.temp_files.insert(0, configtest_h)
308
fh = open(configtest_h, "w")
310
sep = "/* " + ('-'*72)+ " */\n"
312
self.scanner.dump_config_h(fh, results)
314
self.scanner.dump_missing_h(fh, results)
319
body = ['#include "%s"' % configtest_h,
320
'int main(int argc, char **argv) {',
324
body = '\n'.join(body) + '\n'
327
def run_one(self, body, lang='c'):
328
ok = self.config_cmd.try_link(body, headers=['mpi.h'], lang=lang)
331
# -----------------------------------------------------------------------------
336
"MPI linker command, "
337
"overridden by environment variable 'MPILD' "
338
"(defaults to 'mpicc' or 'mpicxx' if any is available)"),
341
"MPI F77 compiler command, "
342
"overridden by environment variable 'MPIF77' "
343
"(defaults to 'mpif77' if available)"),
346
"MPI F90 compiler command, "
347
"overridden by environment variable 'MPIF90' "
348
"(defaults to 'mpif90' if available)"),
351
"MPI F95 compiler command, "
352
"overridden by environment variable 'MPIF95' "
353
"(defaults to 'mpif95' if available)"),
356
"MPI C++ compiler command, "
357
"overridden by environment variable 'MPICXX' "
358
"(defaults to 'mpicxx', 'mpiCC', or 'mpic++' if any is available)"),
361
"MPI C compiler command, "
362
"overridden by environment variables 'MPICC' "
363
"(defaults to 'mpicc' if available)"),
366
"specify a configuration section, "
367
"and an optional list of configuration files "
368
+ "(e.g. --mpi=section,file1" + os.path.pathsep + "file2), " +
369
"to look for MPI includes/libraries, "
370
"overridden by environment variable 'MPICFG' "
371
"(defaults to section 'mpi' in configuration file 'mpi.cfg')"),
374
"exhaustive test for checking missing MPI constants/types/functions"),
378
def cmd_get_mpi_options(cmd_opts):
380
for (option, _, _) in cmd_opts:
381
if option[-1] == '=':
383
option = option.replace('-','_')
384
optlist.append(option)
387
def cmd_initialize_mpi_options(cmd):
388
mpiopts = cmd_get_mpi_options(cmd_mpi_opts)
390
setattr(cmd, op, None)
392
def cmd_set_undefined_mpi_options(cmd, basecmd):
393
mpiopts = cmd_get_mpi_options(cmd_mpi_opts)
394
optlist = tuple(zip(mpiopts, mpiopts))
395
cmd.set_undefined_options(basecmd, *optlist)
397
# -----------------------------------------------------------------------------
399
from distutils.core import setup as fcn_setup
400
from distutils.core import Distribution as cls_Distribution
401
from distutils.core import Extension as cls_Extension
402
from distutils.core import Command
404
from distutils.command import config as cmd_config
405
from distutils.command import build as cmd_build
406
from distutils.command import install as cmd_install
407
from distutils.command import sdist as cmd_sdist
408
from distutils.command import clean as cmd_clean
410
from distutils.command import build_py as cmd_build_py
411
from distutils.command import build_clib as cmd_build_clib
412
from distutils.command import build_ext as cmd_build_ext
413
from distutils.command import install_data as cmd_install_data
414
from distutils.command import install_lib as cmd_install_lib
416
from distutils.errors import DistutilsError
417
from distutils.errors import DistutilsSetupError
418
from distutils.errors import DistutilsPlatformError
419
from distutils.errors import DistutilsOptionError
420
from distutils.errors import CCompilerError
422
# -----------------------------------------------------------------------------
424
# Distribution class supporting a 'executables' keyword
426
class Distribution(cls_Distribution):
428
def __init__ (self, attrs=None):
429
# support for pkg data
430
self.package_data = {}
434
self.obsoletes = None
435
# supports 'executables' keyword
436
self.executables = None
437
cls_Distribution.__init__(self, attrs)
439
def has_executables(self):
440
return self.executables and len(self.executables) > 0
443
return (cls_Distribution.is_pure(self) and
444
not self.has_executables())
448
class Extension(cls_Extension):
449
def __init__ (self, **kw):
450
optional = kw.pop('optional', None)
451
configure = kw.pop('configure', None)
452
cls_Extension.__init__(self, **kw)
453
self.optional = optional
454
self.configure = configure
458
class Library(Extension):
459
def __init__ (self, **kw):
460
kind = kw.pop('kind', "static")
461
package = kw.pop('package', None)
462
dest_dir = kw.pop('dest_dir', None)
463
Extension.__init__(self, **kw)
465
self.package = package
466
self.dest_dir = dest_dir
470
class Executable(Extension):
471
def __init__ (self, **kw):
472
package = kw.pop('package', None)
473
dest_dir = kw.pop('dest_dir', None)
474
Extension.__init__(self, **kw)
475
self.package = package
476
self.dest_dir = dest_dir
481
if 'distclass' not in attrs:
482
attrs['distclass'] = Distribution
483
if 'cmdclass' not in attrs:
484
attrs['cmdclass'] = {}
485
cmdclass = attrs['cmdclass']
486
for cmd in (config, build, install,
489
build_clib, build_ext, build_exe,
490
install_lib, install_data, install_exe,
492
if cmd.__name__ not in cmdclass:
493
cmdclass[cmd.__name__] = cmd
494
return fcn_setup(**attrs)
496
# -----------------------------------------------------------------------------
498
# A minimalistic MPI program :-)
501
int main(int argc, char **argv)
504
ierr = MPI_Init(&argc, &argv);
506
ierr = MPI_Finalize();
512
class config(cmd_config.config):
514
user_options = cmd_config.config.user_options + cmd_mpi_opts
516
def initialize_options (self):
517
cmd_config.config.initialize_options(self)
518
cmd_initialize_mpi_options(self)
521
def finalize_options (self):
522
cmd_config.config.finalize_options(self)
526
def _clean(self, *a, **kw):
527
if sys.platform.startswith('win'):
528
for fn in ('_configtest.exe.manifest', ):
529
if os.path.exists(fn):
530
self.temp_files.append(fn)
531
cmd_config.config._clean(self, *a, **kw)
533
def check_header (self, header, headers=None, include_dirs=None):
534
if headers is None: headers = []
535
log.info("checking for header '%s' ..." % header)
536
body = "int main(int n, char**v) { return 0; }"
537
ok = self.try_compile(body, list(headers) + [header], include_dirs)
538
log.info(ok and 'success!' or 'failure.')
541
def check_macro (self, macro, headers=None, include_dirs=None):
542
log.info("checking for macro '%s' ..." % macro)
543
body = ("#ifndef %s\n"
544
"#error macro '%s' not defined\n"
545
"#endif\n") % (macro, macro)
546
body += "int main(int n, char**v) { return 0; }\n"
547
ok = self.try_compile(body, headers, include_dirs)
550
def check_library (self, library, library_dirs=None,
551
headers=None, include_dirs=None,
552
other_libraries=[], lang="c"):
553
log.info("checking for library '%s' ..." % library)
554
body = "int main(int n, char**v) { return 0; }"
555
ok = self.try_link(body, headers, include_dirs,
556
[library]+other_libraries, library_dirs,
560
def check_function (self, function,
561
headers=None, include_dirs=None,
562
libraries=None, library_dirs=None,
563
decl=0, call=0, lang="c"):
564
log.info("checking for function '%s' ..." % function)
567
if call: proto = "int %s (void);"
568
else: proto = "int %s;"
571
"#ifdef __cplusplus",
574
body.append(proto % function)
575
body.append( "int main (int n, char**v) {")
577
body.append(" (void)%s();" % function)
579
body.append(" %s;" % function)
580
body.append( " return 0;")
582
body = "\n".join(body) + "\n"
583
ok = self.try_link(body, headers, include_dirs,
584
libraries, library_dirs, lang=lang)
587
def check_symbol (self, symbol, type="int",
588
headers=None, include_dirs=None,
589
libraries=None, library_dirs=None,
591
log.info("checking for symbol '%s' ..." % symbol)
594
body.append("%s %s;" % (type, symbol))
595
body.append("int main (int n, char**v) {")
596
body.append(" %s v; v = %s;" % (type, symbol))
597
body.append(" return 0;")
599
body = "\n".join(body) + "\n"
600
ok = self.try_link(body, headers, include_dirs,
601
libraries, library_dirs, lang=lang)
604
check_hdr = check_header
605
check_lib = check_library
606
check_func = check_function
607
check_sym = check_symbol
611
config = configuration(self, verbose=True)
612
# test MPI C compiler
613
self.compiler = getattr(
614
self.compiler, 'compiler_type', self.compiler)
615
self._check_compiler()
616
configure_compiler(self.compiler, config, lang='c')
617
self.try_link(ConfigTest, headers=['mpi.h'], lang='c')
618
# test MPI C++ compiler
619
self.compiler = getattr(
620
self.compiler, 'compiler_type', self.compiler)
621
self._check_compiler()
622
configure_compiler(self.compiler, config, lang='c++')
623
self.try_link(ConfigTest, headers=['mpi.h'], lang='c++')
626
class build(cmd_build.build):
628
user_options = cmd_build.build.user_options + cmd_mpi_opts
630
def initialize_options(self):
631
cmd_build.build.initialize_options(self)
632
cmd_initialize_mpi_options(self)
634
def finalize_options(self):
635
cmd_build.build.finalize_options(self)
636
config_cmd = self.get_finalized_command('config')
637
if isinstance(config_cmd, config):
638
cmd_set_undefined_mpi_options(self, 'config')
640
def has_executables (self):
641
return self.distribution.has_executables()
644
[('build_src', lambda *args: True)] + \
645
cmd_build.build.sub_commands + \
646
[('build_exe', has_executables),
650
class build_src(Command):
651
description = "build C sources from Cython files"
654
"forcibly build everything (ignore file timestamps)"),
656
boolean_options = ['force']
657
def initialize_options(self):
659
def finalize_options(self):
660
self.set_undefined_options('build',
667
class build_py(cmd_build_py.build_py):
669
if sys.version[:3] < '2.4':
671
def initialize_options(self):
672
self.package_data = None
673
cmd_build_py.build_py.initialize_options(self)
675
def finalize_options (self):
676
cmd_build_py.build_py.finalize_options(self)
677
self.package_data = self.distribution.package_data
678
self.data_files = self.get_data_files()
681
cmd_build_py.build_py.run(self)
683
self.build_package_data()
685
def get_data_files (self):
686
"""Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
688
if not self.packages:
690
for package in self.packages:
691
# Locate package source directory
692
src_dir = self.get_package_dir(package)
694
# Compute package build directory
695
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
697
# Length of path to strip from found files
698
plen = len(src_dir)+1
700
# Strip directory from globbed filenames
702
file[plen:] for file in self.find_data_files(package, src_dir)
704
data.append((package, src_dir, build_dir, filenames))
707
def find_data_files (self, package, src_dir):
708
"""Return filenames for package's data files in 'src_dir'"""
709
from glob import glob
710
globs = (self.package_data.get('', [])
711
+ self.package_data.get(package, []))
713
for pattern in globs:
714
# Each pattern has to be converted to a platform-specific path
715
filelist = glob(os.path.join(src_dir, convert_path(pattern)))
716
# Files that match more than one pattern are only added once
717
files.extend([fn for fn in filelist if fn not in files])
720
def get_package_dir (self, package):
721
"""Return the directory, relative to the top of the source
722
distribution, where package 'package' should be found
723
(at least according to the 'package_dir' option, if any)."""
725
path = string.split(package, '.')
727
if not self.package_dir:
729
return os.path.join(*path)
736
pdir = self.package_dir[string.join(path, '.')]
738
tail.insert(0, path[-1])
742
return os.path.join(*tail)
744
pdir = self.package_dir.get('')
749
return os.path.join(*tail)
753
def build_package_data (self):
754
"""Copy data files into build directory"""
756
for package, src_dir, build_dir, filenames in self.data_files:
757
for filename in filenames:
758
target = os.path.join(build_dir, filename)
759
self.mkpath(os.path.dirname(target))
760
self.copy_file(os.path.join(src_dir, filename), target,
764
# Command class to build libraries
766
class build_clib(cmd_build_clib.build_clib):
769
('build-clib-a=', 's',
770
"directory to build C/C++ static libraries to"),
771
('build-clib-so=', 's',
772
"directory to build C/C++ shared libraries to"),
775
user_options += cmd_build_clib.build_clib.user_options + cmd_mpi_opts
777
def initialize_options (self):
778
self.libraries = None
779
self.libraries_a = []
780
self.libraries_so = []
782
self.library_dirs = None
784
self.link_objects = None
786
self.build_lib = None
787
self.build_clib_a = None
788
self.build_clib_so = None
789
cmd_build_clib.build_clib.initialize_options(self)
790
cmd_initialize_mpi_options(self)
792
def finalize_options (self):
793
cmd_build_clib.build_clib.finalize_options(self)
794
build_cmd = self.get_finalized_command('build')
795
if isinstance(build_cmd, build):
796
cmd_set_undefined_mpi_options(self, 'build')
798
self.set_undefined_options('build',
799
('build_lib', 'build_lib'),
800
('build_lib', 'build_clib_a'),
801
('build_lib', 'build_clib_so'))
804
libraries = self.libraries[:]
806
self.check_library_list (libraries)
807
for i, lib in enumerate(libraries):
808
if isinstance(lib, Library):
809
if lib.kind == "static":
810
self.libraries_a.append(lib)
812
self.libraries_so.append(lib)
814
self.libraries.append(lib)
816
def check_library_list (self, libraries):
817
ListType, TupleType = type([]), type(())
818
if not isinstance(libraries, ListType):
819
raise DistutilsSetupError(
820
"'libraries' option must be a list of "
821
"Library instances or 2-tuples")
822
for lib in libraries:
824
if isinstance(lib, Library):
826
build_info = lib.__dict__
827
elif isinstance(lib, TupleType) and len(lib) == 2:
828
lib_name, build_info = lib
830
raise DistutilsSetupError(
831
"each element of 'libraries' option must be an "
832
"Library instance or 2-tuple")
834
if not isinstance(lib_name, str):
835
raise DistutilsSetupError(
836
"first element of each tuple in 'libraries' "
837
"must be a string (the library name)")
838
if '/' in lib_name or (os.sep != '/' and os.sep in lib_name):
839
raise DistutilsSetupError(
840
"bad library name '%s': "
841
"may not contain directory separators" % lib[0])
842
if not isinstance(build_info, dict):
843
raise DistutilsSetupError(
844
"second element of each tuple in 'libraries' "
845
"must be a dictionary (build info)")
846
lib_type = build_info.get('kind', 'static')
847
if lib_type not in ('static', 'shared', 'dylib'):
848
raise DistutilsSetupError(
849
"in 'kind' option (library '%s'), "
850
"'kind' must be one of "
851
" \"static\", \"shared\", \"dylib\"" % lib_name)
852
sources = build_info.get('sources')
853
if (sources is None or
854
type(sources) not in (ListType, TupleType)):
855
raise DistutilsSetupError(
856
"in 'libraries' option (library '%s'), "
857
"'sources' must be present and must be "
858
"a list of source filenames" % lib_name)
859
depends = build_info.get('depends')
860
if (depends is not None and
861
type(depends) not in (ListType, TupleType)):
862
raise DistutilsSetupError(
863
"in 'libraries' option (library '%s'), "
864
"'depends' must be a list "
865
"of source filenames" % lib_name)
868
cmd_build_clib.build_clib.run(self)
869
if (not self.libraries_a and
870
not self.libraries_so):
873
from distutils.ccompiler import new_compiler
874
self.compiler = new_compiler(compiler=self.compiler,
875
dry_run=self.dry_run,
878
if self.define is not None:
879
for (name, value) in self.define:
880
self.compiler.define_macro(name, value)
881
if self.undef is not None:
882
for macro in self.undef:
883
self.compiler.undefine_macro(macro)
884
if self.include_dirs is not None:
885
self.compiler.set_include_dirs(self.include_dirs)
886
if self.library_dirs is not None:
887
self.compiler.set_library_dirs(self.library_dirs)
888
if self.rpath is not None:
889
self.compiler.set_runtime_library_dirs(self.rpath)
890
if self.link_objects is not None:
891
self.compiler.set_link_objects(self.link_objects)
893
config = configuration(self, verbose=True)
894
configure_compiler(self.compiler, config)
896
self.build_libraries(self.libraries)
897
self.build_libraries(self.libraries_a)
898
self.build_libraries(self.libraries_so)
900
def build_libraries (self, libraries):
901
for lib in libraries:
903
if not isinstance(lib, Library):
904
cmd_build_clib.build_clib.build_libraries(self, [lib])
908
self.build_library(lib)
909
except (DistutilsError, CCompilerError):
910
if not lib.optional: raise
911
e = sys.exc_info()[1]
912
self.warn('building library "%s" failed' % lib.name)
915
def config_library (self, lib):
917
config_cmd = self.get_finalized_command('config')
918
config_cmd.compiler = self.compiler # fix compiler
919
return lib.configure(lib, config_cmd)
921
def build_library(self, lib):
922
from distutils.dep_util import newer_group
924
sources = [convert_path(p) for p in lib.sources]
925
depends = [convert_path(p) for p in lib.depends]
926
depends = sources + depends
928
if lib.kind == "static":
929
build_dir = self.build_clib_a
931
build_dir = self.build_clib_so
932
lib_fullpath = self.get_lib_fullpath(lib, build_dir)
934
if not (self.force or newer_group(depends, lib_fullpath, 'newer')):
935
log.debug("skipping '%s' %s library (up-to-date)",
939
ok = self.config_library(lib)
940
log.info("building '%s' %s library", lib.name, lib.kind)
942
# First, compile the source code to object files in the library
943
# directory. (This should probably change to putting object
944
# files in a temporary build directory.)
945
macros = lib.define_macros[:]
946
for undef in lib.undef_macros:
947
macros.append((undef,))
949
objects = self.compiler.compile(
952
output_dir=self.build_temp,
954
include_dirs=lib.include_dirs,
956
extra_postargs=lib.extra_compile_args,
960
if lib.kind == "static":
961
# Now "link" the object files together
962
# into a static library.
963
self.compiler.create_static_lib(
966
output_dir=os.path.dirname(lib_fullpath),
970
extra_objects = lib.extra_objects[:]
971
export_symbols = lib.export_symbols[:]
972
extra_link_args = lib.extra_link_args[:]
973
objects.extend(extra_objects)
974
if (self.compiler.compiler_type == 'msvc' and
975
export_symbols is not None):
976
output_dir = os.path.dirname(lib_fullpath)
977
implib_filename = self.compiler.library_filename(lib.name)
978
implib_file = os.path.join(output_dir, lib_fullpath)
979
extra_link_args.append ('/IMPLIB:' + implib_file)
980
# Detect target language, if not provided
981
src_language = self.compiler.detect_language(sources)
982
language = (lib.language or src_language)
983
# Now "link" the object files together
984
# into a shared library.
986
self.compiler.SHARED_LIBRARY,
987
objects, lib_fullpath,
989
libraries=lib.libraries,
990
library_dirs=lib.library_dirs,
991
runtime_library_dirs=lib.runtime_library_dirs,
992
export_symbols=export_symbols,
994
extra_postargs=extra_link_args,
996
target_lang=language,
1000
def get_lib_fullpath (self, lib, build_dir):
1001
package_dir = (lib.package or '').split('.')
1002
dest_dir = convert_path(lib.dest_dir or '')
1003
output_dir = os.path.join(build_dir, *package_dir+[dest_dir])
1005
if sys.platform != 'darwin':
1006
if lib_type == 'dylib':
1008
compiler = self.compiler # XXX
1009
lib_fullpath = compiler.library_filename(
1010
lib.name, lib_type=lib_type, output_dir=output_dir)
1013
def get_source_files (self):
1014
filenames = cmd_build_clib.build_clib.get_source_files(self)
1015
self.check_library_list(self.libraries)
1016
self.check_library_list(self.libraries_a)
1017
self.check_library_list(self.libraries_so)
1018
for (lib_name, build_info) in self.libraries:
1019
filenames.extend(build_info.get(sources, []))
1020
for lib in self.libraries_so + self.libraries_a:
1021
filenames.extend(lib.sources)
1024
def get_outputs (self):
1026
for lib in self.libraries_a:
1027
lib_fullpath = self.get_lib_fullpath(lib, self.build_clib_a)
1028
outputs.append(lib_fullpath)
1029
for lib in self.libraries_so:
1030
lib_fullpath = self.get_lib_fullpath(lib, self.build_clib_so)
1031
outputs.append(lib_fullpath)
1035
# Command class to build extension modules
1037
class build_ext(cmd_build_ext.build_ext):
1039
user_options = cmd_build_ext.build_ext.user_options + cmd_mpi_opts
1041
def initialize_options(self):
1042
cmd_build_ext.build_ext.initialize_options(self)
1043
cmd_initialize_mpi_options(self)
1045
def finalize_options(self):
1046
cmd_build_ext.build_ext.finalize_options(self)
1047
build_cmd = self.get_finalized_command('build')
1048
if isinstance(build_cmd, build):
1049
cmd_set_undefined_mpi_options(self, 'build')
1051
if ((sys.platform.startswith('linux') or
1052
sys.platform.startswith('gnu') or
1053
sys.platform.startswith('sunos')) and
1054
sysconfig.get_config_var('Py_ENABLE_SHARED')):
1055
py_version = sysconfig.get_python_version()
1056
bad_pylib_dir = os.path.join(sys.prefix, "lib",
1057
"python" + py_version,
1060
self.library_dirs.remove(bad_pylib_dir)
1063
pylib_dir = sysconfig.get_config_var("LIBDIR")
1064
if pylib_dir not in self.library_dirs:
1065
self.library_dirs.append(pylib_dir)
1066
if pylib_dir not in self.rpath:
1067
self.rpath.append(pylib_dir)
1068
if sys.exec_prefix == '/usr':
1069
self.library_dirs.remove(pylib_dir)
1070
self.rpath.remove(pylib_dir)
1073
if self.distribution.has_c_libraries():
1074
build_clib = self.get_finalized_command('build_clib')
1075
if build_clib.libraries:
1077
cmd_build_ext.build_ext.run(self)
1079
def build_extensions(self):
1080
# First, sanity-check the 'extensions' list
1081
self.check_extensions_list(self.extensions)
1082
# parse configuration file and configure compiler
1083
config = configuration(self, verbose=True)
1084
configure_compiler(self.compiler, config)
1085
if self.compiler.compiler_type == "unix":
1086
so_ext = sysconfig.get_config_var('SO')
1087
self.compiler.shared_lib_extension = so_ext
1088
self.config = config # XXX
1089
# extra configuration, check for all MPI symbols
1091
log.info('testing for missing MPI symbols')
1092
config_cmd = self.get_finalized_command('config')
1093
config_cmd.compiler = self.compiler # fix compiler
1094
configure = ConfigureMPI(config_cmd)
1095
results = configure.run()
1096
configure.dump(results)
1098
macro = 'HAVE_CONFIG_H'
1099
log.info("defining preprocessor macro '%s'" % macro)
1100
self.compiler.define_macro(macro, 1)
1102
for ext in self.extensions:
1104
self.build_extension(ext)
1105
except (DistutilsError, CCompilerError):
1106
if not ext.optional: raise
1107
e = sys.exc_info()[1]
1108
self.warn('building extension "%s" failed' % ext.name)
1111
def config_extension (self, ext):
1112
configure = getattr(ext, 'configure', None)
1114
config_cmd = self.get_finalized_command('config')
1115
config_cmd.compiler = self.compiler # fix compiler
1116
configure(ext, config_cmd)
1118
def build_extension (self, ext):
1119
from distutils.dep_util import newer_group
1120
fullname = self.get_ext_fullname(ext.name)
1121
filename = os.path.join(
1122
self.build_lib, self.get_ext_filename(fullname))
1123
depends = ext.sources + ext.depends
1124
if not (self.force or newer_group(depends, filename, 'newer')):
1125
log.debug("skipping '%s' extension (up-to-date)", ext.name)
1128
self.config_extension(ext)
1129
cmd_build_ext.build_ext.build_extension(self, ext)
1131
# XXX -- this is a Vile HACK!
1132
if ext.name == 'mpi4py.MPI':
1133
dest_dir = os.path.dirname(filename)
1134
self.mkpath(dest_dir)
1135
mpi_cfg = os.path.join(dest_dir, 'mpi.cfg')
1136
log.info("writing %s" % mpi_cfg)
1137
if not self.dry_run:
1138
self.config.dump(filename=mpi_cfg)
1140
def get_outputs(self):
1141
outputs = cmd_build_ext.build_ext.get_outputs(self)
1142
for ext in self.extensions:
1143
# XXX -- this is a Vile HACK!
1144
if ext.name == 'mpi4py.MPI':
1145
fullname = self.get_ext_fullname(ext.name)
1146
filename = os.path.join(
1148
self.get_ext_filename(fullname))
1149
dest_dir = os.path.dirname(filename)
1150
mpi_cfg = os.path.join(dest_dir, 'mpi.cfg')
1151
outputs.append(mpi_cfg)
1155
# Command class to build executables
1157
class build_exe(build_ext):
1159
description = "build binary executable components"
1162
('build-exe=', None,
1163
"build directory for executable components"),
1164
] + build_ext.user_options
1167
def initialize_options (self):
1168
build_ext.initialize_options(self)
1169
self.build_base = None
1170
self.build_exe = None
1172
def finalize_options (self):
1173
build_ext.finalize_options(self)
1174
self.configure = None
1175
self.set_undefined_options('build',
1176
('build_base','build_base'),
1177
('build_lib', 'build_exe'))
1178
#from distutils.util import get_platform
1179
#plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3])
1180
#if hasattr(sys, 'gettotalrefcount') and sys.version[0:3] > '2.5':
1181
# plat_specifier += '-pydebug'
1182
#if self.build_exe is None:
1183
# self.build_exe = os.path.join(self.build_base,
1184
# 'exe' + plat_specifier)
1185
self.executables = self.distribution.executables
1186
# XXX This is a hack
1187
self.extensions = self.distribution.executables
1188
self.check_extensions_list = self.check_executables_list
1189
self.build_extension = self.build_executable
1190
self.get_ext_filename = self.get_exe_filename
1191
self.build_lib = self.build_exe
1193
def check_executables_list (self, executables):
1194
ListType, TupleType = type([]), type(())
1195
if type(executables) is not ListType:
1196
raise DistutilsSetupError(
1197
"'executables' option must be a list of Executable instances")
1198
for exe in executables:
1199
if not isinstance(exe, Executable):
1200
raise DistutilsSetupError(
1201
"'executables' items must be Executable instances")
1202
if (exe.sources is None or
1203
type(exe.sources) not in (ListType, TupleType)):
1204
raise DistutilsSetupError(
1205
("in 'executables' option (executable '%s'), " +
1206
"'sources' must be present and must be " +
1207
"a list of source filenames") % exe.name)
1209
def get_exe_filename(self, exe_name):
1210
exe_ext = sysconfig.get_config_var('EXE') or ''
1211
return exe_name + exe_ext
1213
def get_exe_fullpath(self, exe, build_dir=None):
1214
build_dir = build_dir or self.build_exe
1215
package_dir = (exe.package or '').split('.')
1216
dest_dir = convert_path(exe.dest_dir or '')
1217
output_dir = os.path.join(build_dir, *package_dir+[dest_dir])
1218
exe_filename = self.get_exe_filename(exe.name)
1219
return os.path.join(output_dir, exe_filename)
1221
def config_executable (self, exe):
1222
build_ext.config_extension(self, exe)
1224
def build_executable (self, exe):
1225
from distutils.dep_util import newer_group
1226
sources = list(exe.sources)
1227
depends = list(exe.depends)
1228
exe_fullpath = self.get_exe_fullpath(exe)
1229
depends = sources + depends
1230
if not (self.force or newer_group(depends, exe_fullpath, 'newer')):
1231
log.debug("skipping '%s' executable (up-to-date)", exe.name)
1234
self.config_executable(exe)
1235
log.info("building '%s' executable", exe.name)
1237
# Next, compile the source code to object files.
1239
# XXX not honouring 'define_macros' or 'undef_macros' -- the
1240
# CCompiler API needs to change to accommodate this, and I
1241
# want to do one thing at a time!
1243
macros = exe.define_macros[:]
1244
for undef in exe.undef_macros:
1245
macros.append((undef,))
1247
# Two possible sources for extra compiler arguments:
1248
# - 'extra_compile_args' in Extension object
1249
# - CFLAGS environment variable (not particularly
1250
# elegant, but people seem to expect it and I
1251
# guess it's useful)
1252
# The environment variable should take precedence, and
1253
# any sensible compiler will give precedence to later
1254
# command line args. Hence we combine them in order:
1255
extra_args = exe.extra_compile_args[:]
1257
objects = self.compiler.compile(
1259
output_dir=self.build_temp,
1261
include_dirs=exe.include_dirs,
1263
extra_postargs=extra_args,
1264
depends=exe.depends)
1265
self._built_objects = objects[:]
1267
# XXX -- this is a Vile HACK!
1269
# Remove msvcrXX.dll when building executables with MinGW
1271
if self.compiler.compiler_type == 'mingw32':
1272
try: del self.compiler.dll_libraries[:]
1275
# Now link the object files together into a "shared object" --
1276
# of course, first we have to figure out all the other things
1277
# that go into the mix.
1278
if exe.extra_objects:
1279
objects.extend(exe.extra_objects)
1280
extra_args = exe.extra_link_args[:]
1281
# Get special linker flags for building a executable with
1282
# bundled Python library, also fix location of needed
1283
# python.exp file on AIX
1284
ldshflag = sysconfig.get_config_var('LINKFORSHARED') or ''
1285
ldshflag = ldshflag.replace('-Xlinker ', '-Wl,')
1286
if sys.platform == 'darwin': # fix wrong framework paths
1287
fwkprefix = sysconfig.get_config_var('PYTHONFRAMEWORKPREFIX')
1288
fwkdir = sysconfig.get_config_var('PYTHONFRAMEWORKDIR')
1289
if fwkprefix and fwkdir and fwkdir != 'no-framework':
1290
for flag in split_quoted(ldshflag):
1291
if flag.startswith(fwkdir):
1292
fwkpath = os.path.join(fwkprefix, flag)
1293
ldshflag = ldshflag.replace(flag, fwkpath)
1294
if sys.platform.startswith('aix'):
1295
python_lib = sysconfig.get_python_lib(standard_lib=1)
1296
python_exp = os.path.join(python_lib, 'config', 'python.exp')
1297
ldshflag = ldshflag.replace('Modules/python.exp', python_exp)
1298
# Detect target language, if not provided
1299
language = exe.language or self.compiler.detect_language(sources)
1301
self.compiler.EXECUTABLE,
1302
objects, exe_fullpath,
1304
libraries=self.get_libraries(exe),
1305
library_dirs=exe.library_dirs,
1306
runtime_library_dirs=exe.runtime_library_dirs,
1307
extra_preargs=split_quoted(ldshflag),
1308
extra_postargs=extra_args,
1310
target_lang=language)
1312
def get_outputs (self):
1314
for exe in self.executables:
1315
outputs.append(self.get_exe_fullpath(exe))
1319
class install(cmd_install.install):
1321
user_options = cmd_install.install.user_options + [
1322
('single-version-externally-managed', None,
1323
"setuptools compatibility option"),
1325
boolean_options = cmd_install.install.boolean_options + [
1326
'single-version-externally-managed',
1329
def initialize_options(self):
1330
cmd_install.install.initialize_options(self)
1331
self.single_version_externally_managed = None
1332
self.no_compile = None
1335
return (cmd_install.install.has_lib(self) and
1339
return self.distribution.has_executables()
1342
cmd_install.install.sub_commands[:] + \
1343
[('install_exe', has_exe),
1346
# XXX disable install_exe subcommand !!!
1347
del sub_commands[-1]
1350
class install_lib(cmd_install_lib.install_lib):
1352
def get_outputs(self):
1353
outputs = cmd_install_lib.install_lib.get_outputs(self)
1354
for (build_cmd, build_dir) in (('build_clib', 'build_lib'),
1355
('build_exe', 'build_exe')):
1356
outs = self._mutate_outputs(1, build_cmd, build_dir,
1358
build_cmd = self.get_finalized_command(build_cmd)
1359
build_files = build_cmd.get_outputs()
1360
outputs.extend(outs)
1364
class install_data (cmd_install_data.install_data):
1366
def finalize_options (self):
1367
self.set_undefined_options('install',
1368
('install_lib', 'install_dir'),
1374
class install_exe(cmd_install_lib.install_lib):
1376
description = "install binary executable components"
1379
('install-dir=', 'd', "directory to install to"),
1380
('build-dir=','b', "build directory (where to install from)"),
1381
('force', 'f', "force installation (overwrite existing files)"),
1382
('skip-build', None, "skip the build steps"),
1385
boolean_options = ['force', 'skip-build']
1388
def initialize_options (self):
1389
self.install_dir = None
1390
self.build_dir = None
1392
self.skip_build = None
1394
def finalize_options (self):
1395
self.set_undefined_options('build_exe',
1396
('build_exe', 'build_dir'))
1397
self.set_undefined_options('install',
1399
('skip_build', 'skip_build'),
1400
('install_scripts', 'install_dir'))
1407
if not self.skip_build:
1408
if self.distribution.has_executables():
1409
self.run_command('build_exe')
1413
if self.distribution.has_executables():
1414
build_exe = self.get_finalized_command('build_exe')
1415
for exe in build_exe.executables:
1416
exe_fullpath = build_exe.get_exe_fullpath(exe)
1417
exe_filename = os.path.basename(exe_fullpath)
1418
if (os.name == "posix" and
1419
exe_filename.startswith("python-")):
1420
install_name = exe_filename.replace(
1421
"python-","python%s-" % sys.version[:3])
1424
install_name = exe_fullpath
1426
source = exe_fullpath
1427
target = os.path.join(self.install_dir, install_name)
1428
self.mkpath(self.install_dir)
1429
out, done = self.copy_file(source, target, link=link)
1430
self.outfiles.append(out)
1432
def get_outputs (self):
1433
return self.outfiles
1435
def get_inputs (self):
1437
if self.distribution.has_executables():
1438
build_exe = self.get_finalized_command('build_exe')
1439
inputs.extend(build_exe.get_outputs())
1443
class test(Command):
1444
description = "run the test suite"
1446
('args=', None, "options"),
1449
def initialize_options(self):
1451
def finalize_options(self):
1453
self.args = split_quoted(self.args)
1460
class sdist(cmd_sdist.sdist):
1463
build_src = self.get_finalized_command('build_src')
1465
cmd_sdist.sdist.run(self)
1468
class clean(cmd_clean.clean):
1470
description = "clean up temporary files from 'build' command"
1472
cmd_clean.clean.user_options[:2] + [
1473
('build-exe=', None,
1474
"build directory for executable components "
1475
"(default: 'build_exe.build-exe')"),
1476
] + cmd_clean.clean.user_options[2:]
1478
def initialize_options(self):
1479
cmd_clean.clean.initialize_options(self)
1480
self.build_exe = None
1482
def finalize_options(self):
1483
cmd_clean.clean.finalize_options(self)
1484
self.set_undefined_options('build_exe',
1485
('build_exe', 'build_exe'))
1488
from distutils.dir_util import remove_tree
1490
# remove the build/temp.<plat> directory
1491
# (unless it's already gone)
1492
if os.path.exists(self.build_temp):
1493
remove_tree(self.build_temp, dry_run=self.dry_run)
1495
log.debug("'%s' does not exist -- can't clean it",
1499
# remove build directories
1500
for directory in (self.build_lib,
1505
if os.path.exists(directory):
1506
remove_tree(directory, dry_run=self.dry_run)
1508
log.debug("'%s' does not exist -- can't clean it",
1511
# just for the heck of it, try to remove the base build directory:
1512
# we might have emptied it right now, but if not we don't care
1513
if not self.dry_run:
1515
os.rmdir(self.build_base)
1516
log.info("removing '%s'", self.build_base)
1520
# -----------------------------------------------------------------------------
1524
Directory_make_short = msilib.Directory.make_short
1525
def make_short(self, file):
1526
parts = file.split('.')
1528
file = '_'.join(parts[:-1])+'.'+parts[-1]
1529
return Directory_make_short(self, file)
1530
msilib.Directory.make_short = make_short
1534
# -----------------------------------------------------------------------------