~yolanda.robla/ubuntu/trusty/nodejs/add_distribution

« back to all changes in this revision

Viewing changes to tools/wafadmin/Tools/d.py

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2013-08-14 00:16:46 UTC
  • mfrom: (7.1.40 sid)
  • Revision ID: package-import@ubuntu.com-20130814001646-bzlysfh8sd6mukbo
Tags: 0.10.15~dfsg1-4
* Update 2005 patch, adding a handful of tests that can fail on
  slow platforms.
* Add 1004 patch to fix test failures when writing NaN to buffer
  on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
# encoding: utf-8
3
 
# Carlos Rafael Giani, 2007 (dv)
4
 
# Thomas Nagy, 2007-2008 (ita)
5
 
 
6
 
import os, sys, re, optparse
7
 
import ccroot # <- leave this
8
 
import TaskGen, Utils, Task, Configure, Logs, Build
9
 
from Logs import debug, error
10
 
from TaskGen import taskgen, feature, after, before, extension
11
 
from Configure import conftest
12
 
 
13
 
EXT_D = ['.d', '.di', '.D']
14
 
D_METHS = ['apply_core', 'apply_vnum', 'apply_objdeps'] # additional d methods
15
 
 
16
 
def filter_comments(filename):
17
 
        txt = Utils.readf(filename)
18
 
        buf = []
19
 
 
20
 
        i = 0
21
 
        max = len(txt)
22
 
        while i < max:
23
 
                c = txt[i]
24
 
                # skip a string
25
 
                if c == '"':
26
 
                        i += 1
27
 
                        c = ''
28
 
                        while i < max:
29
 
                                p = c
30
 
                                c = txt[i]
31
 
                                i += 1
32
 
                                if i == max: return buf
33
 
                                if c == '"':
34
 
                                        cnt = 0
35
 
                                        while i < cnt and i < max:
36
 
                                                #print "cntcnt = ", str(cnt), self.txt[self.i-2-cnt]
37
 
                                                if txt[i-2-cnt] == '\\': cnt+=1
38
 
                                                else: break
39
 
                                        #print "cnt is ", str(cnt)
40
 
                                        if (cnt%2)==0: break
41
 
                        i += 1
42
 
                # skip a char
43
 
                elif c == "'":
44
 
                        i += 1
45
 
                        if i == max: return buf
46
 
                        c = txt[i]
47
 
                        if c == '\\':
48
 
                                i += 1
49
 
                                if i == max: return buf
50
 
                                c = txt[i]
51
 
                                if c == 'x':
52
 
                                        i += 2 # skip two chars
53
 
                                elif c == 'u':
54
 
                                        i += 4 # skip unicode chars
55
 
                        i += 1
56
 
                        if i == max: return buf
57
 
                        c = txt[i]
58
 
                        if c != '\'': error("uh-oh, invalid character")
59
 
 
60
 
                # skip a comment
61
 
                elif c == '/':
62
 
                        if i == max: break
63
 
                        c = txt[i+1]
64
 
                        # eat /+ +/ comments
65
 
                        if c == '+':
66
 
                                i += 1
67
 
                                nesting = 1
68
 
                                prev = 0
69
 
                                while i < max:
70
 
                                        c = txt[i]
71
 
                                        if c == '+':
72
 
                                                prev = 1
73
 
                                        elif c == '/':
74
 
                                                if prev:
75
 
                                                        nesting -= 1
76
 
                                                        if nesting == 0: break
77
 
                                                else:
78
 
                                                        if i < max:
79
 
                                                                i += 1
80
 
                                                                c = txt[i]
81
 
                                                                if c == '+':
82
 
                                                                        nesting += 1
83
 
                                                        else:
84
 
                                                                return buf
85
 
                                        else:
86
 
                                                prev = 0
87
 
                                        i += 1
88
 
                        # eat /* */ comments
89
 
                        elif c == '*':
90
 
                                i += 1
91
 
                                while i < max:
92
 
                                        c = txt[i]
93
 
                                        if c == '*':
94
 
                                                prev = 1
95
 
                                        elif c == '/':
96
 
                                                if prev: break
97
 
                                        else:
98
 
                                                prev = 0
99
 
                                        i += 1
100
 
                        # eat // comments
101
 
                        elif c == '/':
102
 
                                i += 1
103
 
                                c = txt[i]
104
 
                                while i < max and c != '\n':
105
 
                                        i += 1
106
 
                                        c = txt[i]
107
 
                # a valid char, add it to the buffer
108
 
                else:
109
 
                        buf.append(c)
110
 
                i += 1
111
 
        return buf
112
 
 
113
 
class d_parser(object):
114
 
        def __init__(self, env, incpaths):
115
 
                #self.code = ''
116
 
                #self.module = ''
117
 
                #self.imports = []
118
 
 
119
 
                self.allnames = []
120
 
 
121
 
                self.re_module = re.compile("module\s+([^;]+)")
122
 
                self.re_import = re.compile("import\s+([^;]+)")
123
 
                self.re_import_bindings = re.compile("([^:]+):(.*)")
124
 
                self.re_import_alias = re.compile("[^=]+=(.+)")
125
 
 
126
 
                self.env = env
127
 
 
128
 
                self.nodes = []
129
 
                self.names = []
130
 
 
131
 
                self.incpaths = incpaths
132
 
 
133
 
        def tryfind(self, filename):
134
 
                found = 0
135
 
                for n in self.incpaths:
136
 
                        found = n.find_resource(filename.replace('.', '/') + '.d')
137
 
                        if found:
138
 
                                self.nodes.append(found)
139
 
                                self.waiting.append(found)
140
 
                                break
141
 
                if not found:
142
 
                        if not filename in self.names:
143
 
                                self.names.append(filename)
144
 
 
145
 
        def get_strings(self, code):
146
 
                #self.imports = []
147
 
                self.module = ''
148
 
                lst = []
149
 
 
150
 
                # get the module name (if present)
151
 
 
152
 
                mod_name = self.re_module.search(code)
153
 
                if mod_name:
154
 
                        self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces
155
 
 
156
 
                # go through the code, have a look at all import occurrences
157
 
 
158
 
                # first, lets look at anything beginning with "import" and ending with ";"
159
 
                import_iterator = self.re_import.finditer(code)
160
 
                if import_iterator:
161
 
                        for import_match in import_iterator:
162
 
                                import_match_str = re.sub('\s+', '', import_match.group(1)) # strip all whitespaces
163
 
 
164
 
                                # does this end with an import bindings declaration?
165
 
                                # (import bindings always terminate the list of imports)
166
 
                                bindings_match = self.re_import_bindings.match(import_match_str)
167
 
                                if bindings_match:
168
 
                                        import_match_str = bindings_match.group(1)
169
 
                                        # if so, extract the part before the ":" (since the module declaration(s) is/are located there)
170
 
 
171
 
                                # split the matching string into a bunch of strings, separated by a comma
172
 
                                matches = import_match_str.split(',')
173
 
 
174
 
                                for match in matches:
175
 
                                        alias_match = self.re_import_alias.match(match)
176
 
                                        if alias_match:
177
 
                                                # is this an alias declaration? (alias = module name) if so, extract the module name
178
 
                                                match = alias_match.group(1)
179
 
 
180
 
                                        lst.append(match)
181
 
                return lst
182
 
 
183
 
        def start(self, node):
184
 
                self.waiting = [node]
185
 
                # while the stack is not empty, add the dependencies
186
 
                while self.waiting:
187
 
                        nd = self.waiting.pop(0)
188
 
                        self.iter(nd)
189
 
 
190
 
        def iter(self, node):
191
 
                path = node.abspath(self.env) # obtain the absolute path
192
 
                code = "".join(filter_comments(path)) # read the file and filter the comments
193
 
                names = self.get_strings(code) # obtain the import strings
194
 
                for x in names:
195
 
                        # optimization
196
 
                        if x in self.allnames: continue
197
 
                        self.allnames.append(x)
198
 
 
199
 
                        # for each name, see if it is like a node or not
200
 
                        self.tryfind(x)
201
 
 
202
 
def scan(self):
203
 
        "look for .d/.di the .d source need"
204
 
        env = self.env
205
 
        gruik = d_parser(env, env['INC_PATHS'])
206
 
        gruik.start(self.inputs[0])
207
 
 
208
 
        if Logs.verbose:
209
 
                debug('deps: nodes found for %s: %s %s' % (str(self.inputs[0]), str(gruik.nodes), str(gruik.names)))
210
 
                #debug("deps found for %s: %s" % (str(node), str(gruik.deps)), 'deps')
211
 
        return (gruik.nodes, gruik.names)
212
 
 
213
 
def get_target_name(self):
214
 
        "for d programs and libs"
215
 
        v = self.env
216
 
        tp = 'program'
217
 
        for x in self.features:
218
 
                if x in ['dshlib', 'dstaticlib']:
219
 
                        tp = x.lstrip('d')
220
 
        return v['D_%s_PATTERN' % tp] % self.target
221
 
 
222
 
d_params = {
223
 
'dflags': '',
224
 
'importpaths':'',
225
 
'libs':'',
226
 
'libpaths':'',
227
 
'generate_headers':False,
228
 
}
229
 
 
230
 
@feature('d')
231
 
@before('apply_type_vars')
232
 
def init_d(self):
233
 
        for x in d_params:
234
 
                setattr(self, x, getattr(self, x, d_params[x]))
235
 
 
236
 
class d_taskgen(TaskGen.task_gen):
237
 
        def __init__(self, *k, **kw):
238
 
                TaskGen.task_gen.__init__(self, *k, **kw)
239
 
 
240
 
                # COMPAT
241
 
                if len(k) > 1:
242
 
                        self.features.append('d' + k[1])
243
 
 
244
 
# okay, we borrow a few methods from ccroot
245
 
TaskGen.bind_feature('d', D_METHS)
246
 
 
247
 
@feature('d')
248
 
@before('apply_d_libs')
249
 
def init_d(self):
250
 
        Utils.def_attrs(self,
251
 
                dflags='',
252
 
                importpaths='',
253
 
                libs='',
254
 
                libpaths='',
255
 
                uselib='',
256
 
                uselib_local='',
257
 
                generate_headers=False, # set to true if you want .di files as well as .o
258
 
                compiled_tasks=[],
259
 
                add_objects=[],
260
 
                link_task=None)
261
 
 
262
 
@feature('d')
263
 
@after('apply_d_link', 'init_d')
264
 
@before('apply_vnum')
265
 
def apply_d_libs(self):
266
 
        """after apply_link because of 'link_task'
267
 
        after default_cc because of the attribute 'uselib'"""
268
 
        env = self.env
269
 
 
270
 
        # 1. the case of the libs defined in the project (visit ancestors first)
271
 
        # the ancestors external libraries (uselib) will be prepended
272
 
        self.uselib = self.to_list(self.uselib)
273
 
        names = self.to_list(self.uselib_local)
274
 
 
275
 
        seen = set([])
276
 
        tmp = Utils.deque(names) # consume a copy of the list of names
277
 
        while tmp:
278
 
                lib_name = tmp.popleft()
279
 
                # visit dependencies only once
280
 
                if lib_name in seen:
281
 
                        continue
282
 
 
283
 
                y = self.name_to_obj(lib_name)
284
 
                if not y:
285
 
                        raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name))
286
 
                y.post()
287
 
                seen.add(lib_name)
288
 
 
289
 
                # object has ancestors to process (shared libraries): add them to the end of the list
290
 
                if getattr(y, 'uselib_local', None):
291
 
                        lst = y.to_list(y.uselib_local)
292
 
                        if 'dshlib' in y.features or 'dprogram' in y.features:
293
 
                                lst = [x for x in lst if not 'dstaticlib' in self.name_to_obj(x).features]
294
 
                        tmp.extend(lst)
295
 
 
296
 
                # link task and flags
297
 
                if getattr(y, 'link_task', None):
298
 
 
299
 
                        link_name = y.target[y.target.rfind(os.sep) + 1:]
300
 
                        if 'dstaticlib' in y.features or 'dshlib' in y.features:
301
 
                                env.append_unique('DLINKFLAGS', env.DLIB_ST % link_name)
302
 
                                env.append_unique('DLINKFLAGS', env.DLIBPATH_ST % y.link_task.outputs[0].parent.bldpath(env))
303
 
 
304
 
                        # the order
305
 
                        self.link_task.set_run_after(y.link_task)
306
 
 
307
 
                        # for the recompilation
308
 
                        dep_nodes = getattr(self.link_task, 'dep_nodes', [])
309
 
                        self.link_task.dep_nodes = dep_nodes + y.link_task.outputs
310
 
 
311
 
                # add ancestors uselib too - but only propagate those that have no staticlib
312
 
                for v in self.to_list(y.uselib):
313
 
                        if not v in self.uselib:
314
 
                                self.uselib.insert(0, v)
315
 
 
316
 
                # if the library task generator provides 'export_incdirs', add to the include path
317
 
                # the export_incdirs must be a list of paths relative to the other library
318
 
                if getattr(y, 'export_incdirs', None):
319
 
                        for x in self.to_list(y.export_incdirs):
320
 
                                node = y.path.find_dir(x)
321
 
                                if not node:
322
 
                                        raise Utils.WafError('object %r: invalid folder %r in export_incdirs' % (y.target, x))
323
 
                                self.env.append_unique('INC_PATHS', node)
324
 
 
325
 
@feature('dprogram', 'dshlib', 'dstaticlib')
326
 
@after('apply_core')
327
 
def apply_d_link(self):
328
 
        link = getattr(self, 'link', None)
329
 
        if not link:
330
 
                if 'dstaticlib' in self.features: link = 'static_link'
331
 
                else: link = 'd_link'
332
 
 
333
 
        outputs = [t.outputs[0] for t in self.compiled_tasks]
334
 
        self.link_task = self.create_task(link, outputs, self.path.find_or_declare(get_target_name(self)))
335
 
 
336
 
@feature('d')
337
 
@after('apply_core')
338
 
def apply_d_vars(self):
339
 
        env = self.env
340
 
        dpath_st   = env['DPATH_ST']
341
 
        lib_st     = env['DLIB_ST']
342
 
        libpath_st = env['DLIBPATH_ST']
343
 
 
344
 
        importpaths = self.to_list(self.importpaths)
345
 
        libpaths = []
346
 
        libs = []
347
 
        uselib = self.to_list(self.uselib)
348
 
 
349
 
        for i in uselib:
350
 
                if env['DFLAGS_' + i]:
351
 
                        env.append_unique('DFLAGS', env['DFLAGS_' + i])
352
 
 
353
 
        for x in self.features:
354
 
                if not x in ['dprogram', 'dstaticlib', 'dshlib']:
355
 
                        continue
356
 
                x.lstrip('d')
357
 
                d_shlib_dflags = env['D_' + x + '_DFLAGS']
358
 
                if d_shlib_dflags:
359
 
                        env.append_unique('DFLAGS', d_shlib_dflags)
360
 
 
361
 
        # add import paths
362
 
        for i in uselib:
363
 
                if env['DPATH_' + i]:
364
 
                        for entry in self.to_list(env['DPATH_' + i]):
365
 
                                if not entry in importpaths:
366
 
                                        importpaths.append(entry)
367
 
 
368
 
        # now process the import paths
369
 
        for path in importpaths:
370
 
                if os.path.isabs(path):
371
 
                        env.append_unique('_DIMPORTFLAGS', dpath_st % path)
372
 
                else:
373
 
                        node = self.path.find_dir(path)
374
 
                        self.env.append_unique('INC_PATHS', node)
375
 
                        env.append_unique('_DIMPORTFLAGS', dpath_st % node.srcpath(env))
376
 
                        env.append_unique('_DIMPORTFLAGS', dpath_st % node.bldpath(env))
377
 
 
378
 
        # add library paths
379
 
        for i in uselib:
380
 
                if env['LIBPATH_' + i]:
381
 
                        for entry in self.to_list(env['LIBPATH_' + i]):
382
 
                                if not entry in libpaths:
383
 
                                        libpaths.append(entry)
384
 
        libpaths = self.to_list(self.libpaths) + libpaths
385
 
 
386
 
        # now process the library paths
387
 
        # apply same path manipulation as used with import paths
388
 
        for path in libpaths:
389
 
                if not os.path.isabs(path):
390
 
                        node = self.path.find_resource(path)
391
 
                        if not node:
392
 
                                raise Utils.WafError('could not find libpath %r from %r' % (path, self))
393
 
                        path = node.abspath(self.env)
394
 
 
395
 
                env.append_unique('DLINKFLAGS', libpath_st % path)
396
 
 
397
 
        # add libraries
398
 
        for i in uselib:
399
 
                if env['LIB_' + i]:
400
 
                        for entry in self.to_list(env['LIB_' + i]):
401
 
                                if not entry in libs:
402
 
                                        libs.append(entry)
403
 
        libs.extend(self.to_list(self.libs))
404
 
 
405
 
        # process user flags
406
 
        for flag in self.to_list(self.dflags):
407
 
                env.append_unique('DFLAGS', flag)
408
 
 
409
 
        # now process the libraries
410
 
        for lib in libs:
411
 
                env.append_unique('DLINKFLAGS', lib_st % lib)
412
 
 
413
 
        # add linker flags
414
 
        for i in uselib:
415
 
                dlinkflags = env['DLINKFLAGS_' + i]
416
 
                if dlinkflags:
417
 
                        for linkflag in dlinkflags:
418
 
                                env.append_unique('DLINKFLAGS', linkflag)
419
 
 
420
 
@feature('dshlib')
421
 
@after('apply_d_vars')
422
 
def add_shlib_d_flags(self):
423
 
        for linkflag in self.env['D_shlib_LINKFLAGS']:
424
 
                self.env.append_unique('DLINKFLAGS', linkflag)
425
 
 
426
 
@extension(EXT_D)
427
 
def d_hook(self, node):
428
 
        # create the compilation task: cpp or cc
429
 
        task = self.create_task(self.generate_headers and 'd_with_header' or 'd')
430
 
        try: obj_ext = self.obj_ext
431
 
        except AttributeError: obj_ext = '_%d.o' % self.idx
432
 
 
433
 
        task.inputs = [node]
434
 
        task.outputs = [node.change_ext(obj_ext)]
435
 
        self.compiled_tasks.append(task)
436
 
 
437
 
        if self.generate_headers:
438
 
                header_node = node.change_ext(self.env['DHEADER_ext'])
439
 
                task.outputs += [header_node]
440
 
 
441
 
d_str = '${D_COMPILER} ${DFLAGS} ${_DIMPORTFLAGS} ${D_SRC_F}${SRC} ${D_TGT_F}${TGT}'
442
 
d_with_header_str = '${D_COMPILER} ${DFLAGS} ${_DIMPORTFLAGS} \
443
 
${D_HDR_F}${TGT[1].bldpath(env)} \
444
 
${D_SRC_F}${SRC} \
445
 
${D_TGT_F}${TGT[0].bldpath(env)}'
446
 
link_str = '${D_LINKER} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F}${TGT} ${DLINKFLAGS}'
447
 
 
448
 
def override_exec(cls):
449
 
        """stupid dmd wants -of stuck to the file name"""
450
 
        old_exec = cls.exec_command
451
 
        def exec_command(self, *k, **kw):
452
 
                if isinstance(k[0], list):
453
 
                        lst = k[0]
454
 
                        for i in xrange(len(lst)):
455
 
                                if lst[i] == '-of':
456
 
                                        del lst[i]
457
 
                                        lst[i] = '-of' + lst[i]
458
 
                                        break
459
 
                return old_exec(self, *k, **kw)
460
 
        cls.exec_command = exec_command
461
 
 
462
 
cls = Task.simple_task_type('d', d_str, 'GREEN', before='static_link d_link', shell=False)
463
 
cls.scan = scan
464
 
override_exec(cls)
465
 
 
466
 
cls = Task.simple_task_type('d_with_header', d_with_header_str, 'GREEN', before='static_link d_link', shell=False)
467
 
override_exec(cls)
468
 
 
469
 
cls = Task.simple_task_type('d_link', link_str, color='YELLOW', shell=False)
470
 
override_exec(cls)
471
 
 
472
 
# for feature request #104
473
 
@taskgen
474
 
def generate_header(self, filename, install_path):
475
 
        if not hasattr(self, 'header_lst'): self.header_lst = []
476
 
        self.meths.append('process_header')
477
 
        self.header_lst.append([filename, install_path])
478
 
 
479
 
@before('apply_core')
480
 
def process_header(self):
481
 
        env = self.env
482
 
        for i in getattr(self, 'header_lst', []):
483
 
                node = self.path.find_resource(i[0])
484
 
 
485
 
                if not node:
486
 
                        raise Utils.WafError('file not found on d obj '+i[0])
487
 
 
488
 
                task = self.create_task('d_header')
489
 
                task.set_inputs(node)
490
 
                task.set_outputs(node.change_ext('.di'))
491
 
 
492
 
d_header_str = '${D_COMPILER} ${D_HEADER} ${SRC}'
493
 
Task.simple_task_type('d_header', d_header_str, color='BLUE', shell=False)
494
 
 
495
 
@conftest
496
 
def d_platform_flags(conf):
497
 
        v = conf.env
498
 
        binfmt = v.DEST_BINFMT or Utils.unversioned_sys_platform_to_binary_format(
499
 
                v.DEST_OS or Utils.unversioned_sys_platform())
500
 
        if binfmt == 'pe':
501
 
                v['D_program_PATTERN']   = '%s.exe'
502
 
                v['D_shlib_PATTERN']     = 'lib%s.dll'
503
 
                v['D_staticlib_PATTERN'] = 'lib%s.a'
504
 
        else:
505
 
                v['D_program_PATTERN']   = '%s'
506
 
                v['D_shlib_PATTERN']     = 'lib%s.so'
507
 
                v['D_staticlib_PATTERN'] = 'lib%s.a'
508
 
 
509
 
# quick test #
510
 
if __name__ == "__main__":
511
 
        #Logs.verbose = 2
512
 
 
513
 
        try: arg = sys.argv[1]
514
 
        except IndexError: arg = "file.d"
515
 
 
516
 
        print("".join(filter_comments(arg)))
517
 
        # TODO
518
 
        paths = ['.']
519
 
 
520
 
        #gruik = filter()
521
 
        #gruik.start(arg)
522
 
 
523
 
        #code = "".join(gruik.buf)
524
 
 
525
 
        #print "we have found the following code"
526
 
        #print code
527
 
 
528
 
        #print "now parsing"
529
 
        #print "-------------------------------------------"
530
 
        """
531
 
        parser_ = d_parser()
532
 
        parser_.start(arg)
533
 
 
534
 
        print "module: %s" % parser_.module
535
 
        print "imports: ",
536
 
        for imp in parser_.imports:
537
 
                print imp + " ",
538
 
        print
539
 
"""
540