~ubuntu-branches/ubuntu/feisty/python-numpy/feisty

« back to all changes in this revision

Viewing changes to numpy/distutils/command/build_src.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-07-12 10:00:24 UTC
  • Revision ID: james.westby@ubuntu.com-20060712100024-5lw9q2yczlisqcrt
Tags: upstream-0.9.8
ImportĀ upstreamĀ versionĀ 0.9.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
""" Build swig, f2py, weave, sources.
 
2
"""
 
3
 
 
4
import os
 
5
import re
 
6
import sys
 
7
 
 
8
from distutils.command import build_ext
 
9
from distutils.dep_util import newer_group, newer
 
10
from distutils.util import get_platform
 
11
 
 
12
from numpy.distutils import log
 
13
from numpy.distutils.misc_util import fortran_ext_match, \
 
14
     appendpath, is_string, is_sequence
 
15
from numpy.distutils.from_template import process_file as process_f_file
 
16
from numpy.distutils.conv_template import process_file as process_c_file
 
17
 
 
18
class build_src(build_ext.build_ext):
 
19
 
 
20
    description = "build sources from SWIG, F2PY files or a function"
 
21
 
 
22
    user_options = [
 
23
        ('build-src=', 'd', "directory to \"build\" sources to"),
 
24
        ('f2pyflags=', None, "additonal flags to f2py"),
 
25
        ('swigflags=', None, "additional flags to swig"),
 
26
        ('force', 'f', "forcibly build everything (ignore file timestamps)"),
 
27
        ('inplace', 'i',
 
28
         "ignore build-lib and put compiled extensions into the source " +
 
29
         "directory alongside your pure Python modules"),
 
30
        ]
 
31
 
 
32
    boolean_options = ['force','inplace']
 
33
 
 
34
    help_options = []
 
35
 
 
36
    def initialize_options(self):
 
37
        self.extensions = None
 
38
        self.package = None
 
39
        self.py_modules = None
 
40
        self.py_modules_dict = None
 
41
        self.build_src = None
 
42
        self.build_lib = None
 
43
        self.build_base = None
 
44
        self.force = None
 
45
        self.inplace = None
 
46
        self.package_dir = None
 
47
        self.f2pyflags = None
 
48
        self.swigflags = None
 
49
        return
 
50
 
 
51
    def finalize_options(self):
 
52
        self.set_undefined_options('build',
 
53
                                   ('build_base', 'build_base'),
 
54
                                   ('build_lib', 'build_lib'),
 
55
                                   ('force', 'force'))
 
56
        if self.package is None:
 
57
            self.package = self.distribution.ext_package
 
58
        self.extensions = self.distribution.ext_modules
 
59
        self.libraries = self.distribution.libraries or []
 
60
        self.py_modules = self.distribution.py_modules or []
 
61
        self.data_files = self.distribution.data_files or []
 
62
 
 
63
        if self.build_src is None:
 
64
            plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3])
 
65
            self.build_src = os.path.join(self.build_base, 'src'+plat_specifier)
 
66
        if self.inplace is None:
 
67
            build_ext = self.get_finalized_command('build_ext')
 
68
            self.inplace = build_ext.inplace
 
69
 
 
70
        # py_modules_dict is used in build_py.find_package_modules
 
71
        self.py_modules_dict = {}
 
72
 
 
73
        if self.f2pyflags is None:
 
74
            self.f2pyflags = []
 
75
        else:
 
76
            self.f2pyflags = self.f2pyflags.split() # XXX spaces??
 
77
 
 
78
        if self.swigflags is None:
 
79
            self.swigflags = []
 
80
        else:
 
81
            self.swigflags = self.swigflags.split() # XXX spaces??
 
82
        return
 
83
 
 
84
    def run(self):
 
85
        if not (self.extensions or self.libraries):
 
86
            return
 
87
        self.build_sources()
 
88
 
 
89
        return
 
90
 
 
91
    def build_sources(self):
 
92
 
 
93
        if self.inplace:
 
94
            self.get_package_dir = self.get_finalized_command('build_py')\
 
95
                                   .get_package_dir
 
96
 
 
97
        self.build_py_modules_sources()
 
98
 
 
99
        for libname_info in self.libraries:
 
100
            self.build_library_sources(*libname_info)
 
101
 
 
102
        if self.extensions:
 
103
            self.check_extensions_list(self.extensions)
 
104
 
 
105
            for ext in self.extensions:
 
106
                self.build_extension_sources(ext)
 
107
 
 
108
        self.build_data_files_sources()
 
109
 
 
110
        return
 
111
 
 
112
    def build_data_files_sources(self):
 
113
        if not self.data_files:
 
114
            return
 
115
        log.info('building data_files sources')
 
116
        from numpy.distutils.misc_util import get_data_files
 
117
        new_data_files = []
 
118
        for data in self.data_files:
 
119
            if isinstance(data,str):
 
120
                new_data_files.append(data)
 
121
            elif isinstance(data,tuple):
 
122
                d,files = data
 
123
                if self.inplace:
 
124
                    build_dir = self.get_package_dir('.'.join(d.split(os.sep)))
 
125
                else:
 
126
                    build_dir = os.path.join(self.build_src,d)
 
127
                funcs = filter(callable,files)
 
128
                files = filter(lambda f:not callable(f), files)
 
129
                for f in funcs:
 
130
                    if f.func_code.co_argcount==1:
 
131
                        s = f(build_dir)
 
132
                    else:
 
133
                        s = f()
 
134
                    if s is not None:
 
135
                        if isinstance(s,list):
 
136
                            files.extend(s)
 
137
                        elif isinstance(s,str):
 
138
                            files.append(s)
 
139
                        else:
 
140
                            raise TypeError(repr(s))
 
141
                filenames = get_data_files((d,files))
 
142
                new_data_files.append((d, filenames))
 
143
            else:
 
144
                raise
 
145
        self.data_files[:] = new_data_files
 
146
        return
 
147
 
 
148
    def build_py_modules_sources(self):
 
149
        if not self.py_modules:
 
150
            return
 
151
        log.info('building py_modules sources')
 
152
        new_py_modules = []
 
153
        for source in self.py_modules:
 
154
            if is_sequence(source) and len(source)==3:
 
155
                package, module_base, source = source
 
156
                if self.inplace:
 
157
                    build_dir = self.get_package_dir(package)
 
158
                else:
 
159
                    build_dir = os.path.join(self.build_src,
 
160
                                             os.path.join(*package.split('.')))
 
161
                if callable(source):
 
162
                    target = os.path.join(build_dir, module_base + '.py')
 
163
                    source = source(target)
 
164
                if source is None:
 
165
                    continue
 
166
                modules = [(package, module_base, source)]
 
167
                if not self.py_modules_dict.has_key(package):
 
168
                    self.py_modules_dict[package] = []
 
169
                self.py_modules_dict[package] += modules
 
170
            else:
 
171
                new_py_modules.append(source)
 
172
        self.py_modules[:] = new_py_modules
 
173
        return
 
174
 
 
175
    def build_library_sources(self, lib_name, build_info):
 
176
        sources = list(build_info.get('sources',[]))
 
177
 
 
178
        if not sources:
 
179
            return
 
180
 
 
181
        log.info('building library "%s" sources' % (lib_name))
 
182
 
 
183
        sources = self.generate_sources(sources, (lib_name, build_info))
 
184
 
 
185
        sources = self.template_sources(sources, (lib_name, build_info))
 
186
 
 
187
        sources, h_files = self.filter_h_files(sources)
 
188
 
 
189
        if h_files:
 
190
            print self.package,'- nothing done with h_files=',h_files
 
191
 
 
192
        #for f in h_files:
 
193
        #    self.distribution.headers.append((lib_name,f))
 
194
 
 
195
        build_info['sources'] = sources
 
196
        return
 
197
 
 
198
    def build_extension_sources(self, ext):
 
199
 
 
200
        sources = list(ext.sources)
 
201
 
 
202
        log.info('building extension "%s" sources' % (ext.name))
 
203
 
 
204
        fullname = self.get_ext_fullname(ext.name)
 
205
 
 
206
        modpath = fullname.split('.')
 
207
        package = '.'.join(modpath[0:-1])
 
208
 
 
209
        if self.inplace:
 
210
            self.ext_target_dir = self.get_package_dir(package)
 
211
 
 
212
        sources = self.generate_sources(sources, ext)
 
213
 
 
214
        sources = self.template_sources(sources, ext)
 
215
 
 
216
        sources = self.swig_sources(sources, ext)
 
217
 
 
218
        sources = self.f2py_sources(sources, ext)
 
219
 
 
220
        sources = self.pyrex_sources(sources, ext)
 
221
 
 
222
        sources, py_files = self.filter_py_files(sources)
 
223
 
 
224
        if not self.py_modules_dict.has_key(package):
 
225
            self.py_modules_dict[package] = []
 
226
        modules = []
 
227
        for f in py_files:
 
228
            module = os.path.splitext(os.path.basename(f))[0]
 
229
            modules.append((package, module, f))
 
230
        self.py_modules_dict[package] += modules
 
231
 
 
232
        sources, h_files = self.filter_h_files(sources)
 
233
 
 
234
        if h_files:
 
235
            print package,'- nothing done with h_files=',h_files
 
236
        #for f in h_files:
 
237
        #    self.distribution.headers.append((package,f))
 
238
 
 
239
        ext.sources = sources
 
240
 
 
241
        return
 
242
 
 
243
    def generate_sources(self, sources, extension):
 
244
        new_sources = []
 
245
        func_sources = []
 
246
        for source in sources:
 
247
            if is_string(source):
 
248
                new_sources.append(source)
 
249
            else:
 
250
                func_sources.append(source)
 
251
        if not func_sources:
 
252
            return new_sources
 
253
        if self.inplace and not is_sequence(extension):
 
254
            build_dir = self.ext_target_dir
 
255
        else:
 
256
            if is_sequence(extension):
 
257
                name = extension[0]
 
258
            #    if not extension[1].has_key('include_dirs'):
 
259
            #        extension[1]['include_dirs'] = []
 
260
            #    incl_dirs = extension[1]['include_dirs']
 
261
            else:
 
262
                name = extension.name
 
263
            #    incl_dirs = extension.include_dirs
 
264
            #if self.build_src not in incl_dirs:
 
265
            #    incl_dirs.append(self.build_src)
 
266
            build_dir = os.path.join(*([self.build_src]\
 
267
                                       +name.split('.')[:-1]))
 
268
        self.mkpath(build_dir)
 
269
        for func in func_sources:
 
270
            source = func(extension, build_dir)
 
271
            if not source:
 
272
                continue
 
273
            if is_sequence(source):
 
274
                [log.info("  adding '%s' to sources." % (s,)) for s in source]
 
275
                new_sources.extend(source)
 
276
            else:
 
277
                log.info("  adding '%s' to sources." % (source,))
 
278
                new_sources.append(source)
 
279
 
 
280
        return new_sources
 
281
 
 
282
    def filter_py_files(self, sources):
 
283
        return self.filter_files(sources,['.py'])
 
284
 
 
285
    def filter_h_files(self, sources):
 
286
        return self.filter_files(sources,['.h','.hpp','.inc'])
 
287
 
 
288
    def filter_files(self, sources, exts = []):
 
289
        new_sources = []
 
290
        files = []
 
291
        for source in sources:
 
292
            (base, ext) = os.path.splitext(source)
 
293
            if ext in exts:
 
294
                files.append(source)
 
295
            else:
 
296
                new_sources.append(source)
 
297
        return new_sources, files
 
298
 
 
299
    def template_sources(self, sources, extension):
 
300
        new_sources = []
 
301
        if is_sequence(extension):
 
302
            depends = extension[1].get('depends')
 
303
            include_dirs = extension[1].get('include_dirs')
 
304
        else:
 
305
            depends = extension.depends
 
306
            include_dirs = extension.include_dirs
 
307
        for source in sources:
 
308
            (base, ext) = os.path.splitext(source)
 
309
            if ext == '.src':  # Template file
 
310
                if self.inplace:
 
311
                    target_dir = os.path.dirname(base)
 
312
                else:
 
313
                    target_dir = appendpath(self.build_src, os.path.dirname(base))
 
314
                self.mkpath(target_dir)
 
315
                target_file = os.path.join(target_dir,os.path.basename(base))
 
316
                if (self.force or newer_group([source] + depends, target_file)):
 
317
                    if _f_pyf_ext_match(base):
 
318
                        log.info("from_template:> %s" % (target_file))
 
319
                        outstr = process_f_file(source)
 
320
                    else:
 
321
                        log.info("conv_template:> %s" % (target_file))
 
322
                        outstr = process_c_file(source)
 
323
                    fid = open(target_file,'w')
 
324
                    fid.write(outstr)
 
325
                    fid.close()
 
326
                if _header_ext_match(target_file):
 
327
                    d = os.path.dirname(target_file)
 
328
                    if d not in include_dirs:
 
329
                        log.info("  adding '%s' to include_dirs." % (d))
 
330
                        include_dirs.append(d)
 
331
                new_sources.append(target_file)
 
332
            else:
 
333
                new_sources.append(source)
 
334
        return new_sources
 
335
 
 
336
    def pyrex_sources(self, sources, extension):
 
337
        have_pyrex = False
 
338
        try:
 
339
            import Pyrex
 
340
            have_pyrex = True
 
341
        except ImportError:
 
342
            pass
 
343
        new_sources = []
 
344
        ext_name = extension.name.split('.')[-1]
 
345
        for source in sources:
 
346
            (base, ext) = os.path.splitext(source)
 
347
            if ext == '.pyx':
 
348
                if self.inplace or not have_pyrex:
 
349
                    target_dir = os.path.dirname(base)
 
350
                else:
 
351
                    target_dir = appendpath(self.build_src, os.path.dirname(base))
 
352
                target_file = os.path.join(target_dir, ext_name + '.c')
 
353
                depends = [source] + extension.depends
 
354
                if (self.force or newer_group(depends, target_file, 'newer')):
 
355
                    if have_pyrex:
 
356
                        log.info("pyrexc:> %s" % (target_file))
 
357
                        self.mkpath(target_dir)
 
358
                        from Pyrex.Compiler import Main
 
359
                        options = Main.CompilationOptions(
 
360
                            defaults=Main.default_options,
 
361
                            output_file=target_file)
 
362
                        pyrex_result = Main.compile(source, options=options)
 
363
                        if pyrex_result.num_errors != 0:
 
364
                            raise RuntimeError("%d errors in Pyrex compile" %
 
365
                                               pyrex_result.num_errors)
 
366
                    else:
 
367
                        log.warn("Pyrex needed to compile %s but not available."\
 
368
                                 " Using old target %s"\
 
369
                                 % (source, target_file))
 
370
                new_sources.append(target_file)
 
371
            else:
 
372
                new_sources.append(source)
 
373
        return new_sources
 
374
 
 
375
    def f2py_sources(self, sources, extension):
 
376
        new_sources = []
 
377
        f2py_sources = []
 
378
        f_sources = []
 
379
        f2py_targets = {}
 
380
        target_dirs = []
 
381
        ext_name = extension.name.split('.')[-1]
 
382
        skip_f2py = 0
 
383
 
 
384
        for source in sources:
 
385
            (base, ext) = os.path.splitext(source)
 
386
            if ext == '.pyf': # F2PY interface file
 
387
                if self.inplace:
 
388
                    target_dir = os.path.dirname(base)
 
389
                else:
 
390
                    target_dir = appendpath(self.build_src, os.path.dirname(base))
 
391
                if os.path.isfile(source):
 
392
                    name = get_f2py_modulename(source)
 
393
                    if name != ext_name:
 
394
                        raise ValueError('mismatch of extension names: %s '
 
395
                                         'provides %r but expected %r' % (
 
396
                                          source, name, ext_name))
 
397
                    target_file = os.path.join(target_dir,name+'module.c')
 
398
                else:
 
399
                    log.debug('  source %s does not exist: skipping f2py\'ing.' \
 
400
                              % (source))
 
401
                    name = ext_name
 
402
                    skip_f2py = 1
 
403
                    target_file = os.path.join(target_dir,name+'module.c')
 
404
                    if not os.path.isfile(target_file):
 
405
                        log.debug('  target %s does not exist:\n   '\
 
406
                                  'Assuming %smodule.c was generated with '\
 
407
                                  '"build_src --inplace" command.' \
 
408
                                  % (target_file, name))
 
409
                        target_dir = os.path.dirname(base)
 
410
                        target_file = os.path.join(target_dir,name+'module.c')
 
411
                        if not os.path.isfile(target_file):
 
412
                            raise ValueError("%r missing" % (target_file,))
 
413
                        log.debug('   Yes! Using %s as up-to-date target.' \
 
414
                                  % (target_file))
 
415
                target_dirs.append(target_dir)
 
416
                f2py_sources.append(source)
 
417
                f2py_targets[source] = target_file
 
418
                new_sources.append(target_file)
 
419
            elif fortran_ext_match(ext):
 
420
                f_sources.append(source)
 
421
            else:
 
422
                new_sources.append(source)
 
423
 
 
424
        if not (f2py_sources or f_sources):
 
425
            return new_sources
 
426
 
 
427
        map(self.mkpath, target_dirs)
 
428
 
 
429
        f2py_options = extension.f2py_options + self.f2pyflags
 
430
 
 
431
        if self.distribution.libraries:
 
432
            for name,build_info in self.distribution.libraries:
 
433
                if name in extension.libraries:
 
434
                    f2py_options.extend(build_info.get('f2py_options',[]))
 
435
 
 
436
        log.info("f2py options: %s" % (f2py_options))
 
437
 
 
438
        if f2py_sources:
 
439
            if len(f2py_sources) != 1:
 
440
                raise ValueError(
 
441
                    'only one .pyf file is allowed per extension module but got'\
 
442
                    ' more: %r' % (f2py_sources,))
 
443
            source = f2py_sources[0]
 
444
            target_file = f2py_targets[source]
 
445
            target_dir = os.path.dirname(target_file) or '.'
 
446
            depends = [source] + extension.depends
 
447
            if (self.force or newer_group(depends, target_file,'newer')) \
 
448
                   and not skip_f2py:
 
449
                log.info("f2py: %s" % (source))
 
450
                import numpy.f2py as f2py2e
 
451
                f2py2e.run_main(f2py_options + ['--build-dir',target_dir,source])
 
452
            else:
 
453
                log.debug("  skipping '%s' f2py interface (up-to-date)" % (source))
 
454
        else:
 
455
            #XXX TODO: --inplace support for sdist command
 
456
            if is_sequence(extension):
 
457
                name = extension[0]
 
458
            else: name = extension.name
 
459
            target_dir = os.path.join(*([self.build_src]\
 
460
                                        +name.split('.')[:-1]))
 
461
            target_file = os.path.join(target_dir,ext_name + 'module.c')
 
462
            new_sources.append(target_file)
 
463
            depends = f_sources + extension.depends
 
464
            if (self.force or newer_group(depends, target_file, 'newer')) \
 
465
                   and not skip_f2py:
 
466
                import numpy.f2py as f2py2e
 
467
                log.info("f2py:> %s" % (target_file))
 
468
                self.mkpath(target_dir)
 
469
                f2py2e.run_main(f2py_options + ['--lower',
 
470
                                                '--build-dir',target_dir]+\
 
471
                                ['-m',ext_name]+f_sources)
 
472
            else:
 
473
                log.debug("  skipping f2py fortran files for '%s' (up-to-date)"\
 
474
                          % (target_file))
 
475
 
 
476
        if not os.path.isfile(target_file):
 
477
            raise ValueError("%r missing" % (target_file,))
 
478
 
 
479
        target_c = os.path.join(self.build_src,'fortranobject.c')
 
480
        target_h = os.path.join(self.build_src,'fortranobject.h')
 
481
        log.info("  adding '%s' to sources." % (target_c))
 
482
        new_sources.append(target_c)
 
483
        if self.build_src not in extension.include_dirs:
 
484
            log.info("  adding '%s' to include_dirs." \
 
485
                     % (self.build_src))
 
486
            extension.include_dirs.append(self.build_src)
 
487
 
 
488
        if not skip_f2py:
 
489
            import numpy.f2py as f2py2e
 
490
            d = os.path.dirname(f2py2e.__file__)
 
491
            source_c = os.path.join(d,'src','fortranobject.c')
 
492
            source_h = os.path.join(d,'src','fortranobject.h')
 
493
            if newer(source_c,target_c) or newer(source_h,target_h):
 
494
                self.mkpath(os.path.dirname(target_c))
 
495
                self.copy_file(source_c,target_c)
 
496
                self.copy_file(source_h,target_h)
 
497
        else:
 
498
            if not os.path.isfile(target_c):
 
499
                raise ValueError("%r missing" % (target_c,))
 
500
            if not os.path.isfile(target_h):
 
501
                raise ValueError("%r missing" % (target_h,))
 
502
 
 
503
        for name_ext in ['-f2pywrappers.f','-f2pywrappers2.f90']:
 
504
            filename = os.path.join(target_dir,ext_name + name_ext)
 
505
            if os.path.isfile(filename):
 
506
                log.info("  adding '%s' to sources." % (filename))
 
507
                f_sources.append(filename)
 
508
 
 
509
        return new_sources + f_sources
 
510
 
 
511
    def swig_sources(self, sources, extension):
 
512
        # Assuming SWIG 1.3.14 or later. See compatibility note in
 
513
        #   http://www.swig.org/Doc1.3/Python.html#Python_nn6
 
514
 
 
515
        new_sources = []
 
516
        swig_sources = []
 
517
        swig_targets = {}
 
518
        target_dirs = []
 
519
        py_files = []     # swig generated .py files
 
520
        target_ext = '.c'
 
521
        typ = None
 
522
        is_cpp = 0
 
523
        skip_swig = 0
 
524
        ext_name = extension.name.split('.')[-1]
 
525
 
 
526
        for source in sources:
 
527
            (base, ext) = os.path.splitext(source)
 
528
            if ext == '.i': # SWIG interface file
 
529
                if self.inplace:
 
530
                    target_dir = os.path.dirname(base)
 
531
                    py_target_dir = self.ext_target_dir
 
532
                else:
 
533
                    target_dir = appendpath(self.build_src, os.path.dirname(base))
 
534
                    py_target_dir = target_dir
 
535
                if os.path.isfile(source):
 
536
                    name = get_swig_modulename(source)
 
537
                    if name != ext_name[1:]:
 
538
                        raise ValueError(
 
539
                            'mismatch of extension names: %s provides %r'
 
540
                            ' but expected %r' % (source, name, ext_name[1:]))
 
541
                    if typ is None:
 
542
                        typ = get_swig_target(source)
 
543
                        is_cpp = typ=='c++'
 
544
                        if is_cpp:
 
545
                            target_ext = '.cpp'
 
546
                    else:
 
547
                        assert typ == get_swig_target(source), repr(typ)
 
548
                    target_file = os.path.join(target_dir,'%s_wrap%s' \
 
549
                                               % (name, target_ext))
 
550
                else:
 
551
                    log.debug('  source %s does not exist: skipping swig\'ing.' \
 
552
                             % (source))
 
553
                    name = ext_name[1:]
 
554
                    skip_swig = 1
 
555
                    target_file = _find_swig_target(target_dir, name)
 
556
                    if not os.path.isfile(target_file):
 
557
                        log.debug('  target %s does not exist:\n   '\
 
558
                                  'Assuming %s_wrap.{c,cpp} was generated with '\
 
559
                                  '"build_src --inplace" command.' \
 
560
                                 % (target_file, name))
 
561
                        target_dir = os.path.dirname(base)
 
562
                        target_file = _find_swig_target(target_dir, name)
 
563
                        if not os.path.isfile(target_file):
 
564
                            raise ValueError("%r missing" % (target_file,))
 
565
                        log.debug('   Yes! Using %s as up-to-date target.' \
 
566
                                  % (target_file))
 
567
                target_dirs.append(target_dir)
 
568
                new_sources.append(target_file)
 
569
                py_files.append(os.path.join(py_target_dir, name+'.py'))
 
570
                swig_sources.append(source)
 
571
                swig_targets[source] = new_sources[-1]
 
572
            else:
 
573
                new_sources.append(source)
 
574
 
 
575
        if not swig_sources:
 
576
            return new_sources
 
577
 
 
578
        if skip_swig:
 
579
            return new_sources + py_files
 
580
 
 
581
        map(self.mkpath, target_dirs)
 
582
        swig = self.find_swig()
 
583
        swig_cmd = [swig, "-python"]
 
584
        if is_cpp:
 
585
            swig_cmd.append('-c++')
 
586
        for d in extension.include_dirs:
 
587
            swig_cmd.append('-I'+d)
 
588
        for source in swig_sources:
 
589
            target = swig_targets[source]
 
590
            depends = [source] + extension.depends
 
591
            if self.force or newer_group(depends, target, 'newer'):
 
592
                log.info("%s: %s" % (os.path.basename(swig) \
 
593
                                     + (is_cpp and '++' or ''), source))
 
594
                self.spawn(swig_cmd + self.swigflags \
 
595
                           + ["-o", target, '-outdir', py_target_dir, source])
 
596
            else:
 
597
                log.debug("  skipping '%s' swig interface (up-to-date)" \
 
598
                         % (source))
 
599
 
 
600
        return new_sources + py_files
 
601
 
 
602
_f_pyf_ext_match = re.compile(r'.*[.](f90|f95|f77|for|ftn|f|pyf)\Z',re.I).match
 
603
_header_ext_match = re.compile(r'.*[.](inc|h|hpp)\Z',re.I).match
 
604
 
 
605
#### SWIG related auxiliary functions ####
 
606
_swig_module_name_match = re.compile(r'\s*%module\s*(.*\(\s*package\s*=\s*"(?P<package>[\w_]+)".*\)|)\s*(?P<name>[\w_]+)',
 
607
                                     re.I).match
 
608
_has_c_header = re.compile(r'-[*]-\s*c\s*-[*]-',re.I).search
 
609
_has_cpp_header = re.compile(r'-[*]-\s*c[+][+]\s*-[*]-',re.I).search
 
610
 
 
611
def get_swig_target(source):
 
612
    f = open(source,'r')
 
613
    result = 'c'
 
614
    line = f.readline()
 
615
    if _has_cpp_header(line):
 
616
        result = 'c++'
 
617
    if _has_c_header(line):
 
618
        result = 'c'
 
619
    f.close()
 
620
    return result
 
621
 
 
622
def get_swig_modulename(source):
 
623
    f = open(source,'r')
 
624
    f_readlines = getattr(f,'xreadlines',f.readlines)
 
625
    name = None
 
626
    for line in f_readlines():
 
627
        m = _swig_module_name_match(line)
 
628
        if m:
 
629
            name = m.group('name')
 
630
            break
 
631
    f.close()
 
632
    return name
 
633
 
 
634
def _find_swig_target(target_dir,name):
 
635
    for ext in ['.cpp','.c']:
 
636
        target = os.path.join(target_dir,'%s_wrap%s' % (name, ext))
 
637
        if os.path.isfile(target):
 
638
            break
 
639
    return target
 
640
 
 
641
#### F2PY related auxiliary functions ####
 
642
 
 
643
_f2py_module_name_match = re.compile(r'\s*python\s*module\s*(?P<name>[\w_]+)',
 
644
                                re.I).match
 
645
_f2py_user_module_name_match = re.compile(r'\s*python\s*module\s*(?P<name>[\w_]*?'\
 
646
                                     '__user__[\w_]*)',re.I).match
 
647
 
 
648
def get_f2py_modulename(source):
 
649
    name = None
 
650
    f = open(source)
 
651
    f_readlines = getattr(f,'xreadlines',f.readlines)
 
652
    for line in f_readlines():
 
653
        m = _f2py_module_name_match(line)
 
654
        if m:
 
655
            if _f2py_user_module_name_match(line): # skip *__user__* names
 
656
                continue
 
657
            name = m.group('name')
 
658
            break
 
659
    f.close()
 
660
    return name
 
661
 
 
662
##########################################