~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/libjingle/talk/site_scons/talk.py

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2010 Google Inc.
 
2
# All Rights Reserved.
 
3
#
 
4
# Author: Tim Haloun (thaloun@google.com)
 
5
#         Daniel Petersson (dape@google.com)
 
6
#
 
7
import os
 
8
import SCons.Util
 
9
 
 
10
class LibraryInfo:
 
11
  """Records information on the libraries defined in a build configuration.
 
12
 
 
13
  Attributes:
 
14
    lib_targets: Dictionary of library target params for lookups in
 
15
        ExtendComponent().
 
16
    prebuilt_libraries: Set of all prebuilt static libraries.
 
17
    system_libraries: Set of libraries not found in the above (used to detect
 
18
        out-of-order build rules).
 
19
  """
 
20
 
 
21
  # Dictionary of LibraryInfo objects keyed by BUILD_TYPE value.
 
22
  __library_info = {}
 
23
 
 
24
  @staticmethod
 
25
  def get(env):
 
26
    """Gets the LibraryInfo object for the current build type.
 
27
 
 
28
    Args:
 
29
      env: The environment object.
 
30
 
 
31
    Returns:
 
32
      The LibraryInfo object.
 
33
    """
 
34
    return LibraryInfo.__library_info.setdefault(env['BUILD_TYPE'],
 
35
                                                 LibraryInfo())
 
36
 
 
37
  def __init__(self):
 
38
    self.lib_targets = {}
 
39
    self.prebuilt_libraries = set()
 
40
    self.system_libraries = set()
 
41
 
 
42
 
 
43
def _GetLibParams(env, lib):
 
44
  """Gets the params for the given library if it is a library target.
 
45
 
 
46
  Returns the params that were specified when the given lib target name was
 
47
  created, or None if no such lib target has been defined. In the None case, it
 
48
  additionally records the negative result so as to detect out-of-order
 
49
  dependencies for future targets.
 
50
 
 
51
  Args:
 
52
    env: The environment object.
 
53
    lib: The library's name as a string.
 
54
 
 
55
  Returns:
 
56
    Its dictionary of params, or None.
 
57
  """
 
58
  info = LibraryInfo.get(env)
 
59
  if lib in info.lib_targets:
 
60
    return info.lib_targets[lib]
 
61
  else:
 
62
    if lib not in info.prebuilt_libraries and lib not in info.system_libraries:
 
63
      info.system_libraries.add(lib)
 
64
    return None
 
65
 
 
66
 
 
67
def _RecordLibParams(env, lib, params):
 
68
  """Record the params used for a library target.
 
69
 
 
70
  Record the params used for a library target while checking for several error
 
71
  conditions.
 
72
 
 
73
  Args:
 
74
    env: The environment object.
 
75
    lib: The library target's name as a string.
 
76
    params: Its dictionary of params.
 
77
 
 
78
  Raises:
 
79
    Exception: The lib target has already been recorded, or the lib was
 
80
        previously declared to be prebuilt, or the lib target is being defined
 
81
        after a reverse library dependency.
 
82
  """
 
83
  info = LibraryInfo.get(env)
 
84
  if lib in info.lib_targets:
 
85
    raise Exception('Multiple definitions of ' + lib)
 
86
  if lib in info.prebuilt_libraries:
 
87
    raise Exception(lib + ' already declared as a prebuilt library')
 
88
  if lib in info.system_libraries:
 
89
    raise Exception(lib + ' cannot be defined after its reverse library '
 
90
                    'dependencies')
 
91
  info.lib_targets[lib] = params
 
92
 
 
93
 
 
94
def _IsPrebuiltLibrary(env, lib):
 
95
  """Checks whether or not the given library is a prebuilt static library.
 
96
 
 
97
  Returns whether or not the given library name has been declared to be a
 
98
  prebuilt static library. In the False case, it additionally records the
 
99
  negative result so as to detect out-of-order dependencies for future targets.
 
100
 
 
101
  Args:
 
102
    env: The environment object.
 
103
    lib: The library's name as a string.
 
104
 
 
105
  Returns:
 
106
    True or False
 
107
  """
 
108
  info = LibraryInfo.get(env)
 
109
  if lib in info.prebuilt_libraries:
 
110
    return True
 
111
  else:
 
112
    if lib not in info.lib_targets and lib not in info.system_libraries:
 
113
      info.system_libraries.add(lib)
 
114
    return False
 
115
 
 
116
 
 
117
def _RecordPrebuiltLibrary(env, lib):
 
118
  """Record that a library is a prebuilt static library.
 
119
 
 
120
  Record that the given library name refers to a prebuilt static library while
 
121
  checking for several error conditions.
 
122
 
 
123
  Args:
 
124
    env: The environment object.
 
125
    lib: The library's name as a string.
 
126
 
 
127
  Raises:
 
128
    Exception: The lib has already been recorded to be prebuilt, or the lib was
 
129
        previously declared as a target, or the lib is being declared as
 
130
        prebuilt after a reverse library dependency.
 
131
  """
 
132
  info = LibraryInfo.get(env)
 
133
  if lib in info.prebuilt_libraries:
 
134
    raise Exception('Multiple prebuilt declarations of ' + lib)
 
135
  if lib in info.lib_targets:
 
136
    raise Exception(lib + ' already defined as a target')
 
137
  if lib in info.system_libraries:
 
138
    raise Exception(lib + ' cannot be declared as prebuilt after its reverse '
 
139
                    'library dependencies')
 
140
  info.prebuilt_libraries.add(lib)
 
141
 
 
142
 
 
143
def _GenericLibrary(env, static, **kwargs):
 
144
  """Extends ComponentLibrary to support multiplatform builds
 
145
     of dynamic or static libraries.
 
146
 
 
147
  Args:
 
148
    env: The environment object.
 
149
    kwargs: The keyword arguments.
 
150
 
 
151
  Returns:
 
152
    See swtoolkit ComponentLibrary
 
153
  """
 
154
  params = CombineDicts(kwargs, {'COMPONENT_STATIC': static})
 
155
  return ExtendComponent(env, 'ComponentLibrary', **params)
 
156
 
 
157
 
 
158
def DeclarePrebuiltLibraries(env, libraries):
 
159
  """Informs the build engine about external static libraries.
 
160
 
 
161
  Informs the build engine that the given external library name(s) are prebuilt
 
162
  static libraries, as opposed to shared libraries.
 
163
 
 
164
  Args:
 
165
    env: The environment object.
 
166
    libraries: The library or libraries that are being declared as prebuilt
 
167
        static libraries.
 
168
  """
 
169
  if not SCons.Util.is_List(libraries):
 
170
    libraries = [libraries]
 
171
  for library in libraries:
 
172
    _RecordPrebuiltLibrary(env, library)
 
173
 
 
174
 
 
175
def Library(env, **kwargs):
 
176
  """Extends ComponentLibrary to support multiplatform builds of static
 
177
     libraries.
 
178
 
 
179
  Args:
 
180
    env: The current environment.
 
181
    kwargs: The keyword arguments.
 
182
 
 
183
  Returns:
 
184
    See swtoolkit ComponentLibrary
 
185
  """
 
186
  return _GenericLibrary(env, True, **kwargs)
 
187
 
 
188
 
 
189
def DynamicLibrary(env, **kwargs):
 
190
  """Extends ComponentLibrary to support multiplatform builds
 
191
     of dynmic libraries.
 
192
 
 
193
  Args:
 
194
    env: The environment object.
 
195
    kwargs: The keyword arguments.
 
196
 
 
197
  Returns:
 
198
    See swtoolkit ComponentLibrary
 
199
  """
 
200
  return _GenericLibrary(env, False, **kwargs)
 
201
 
 
202
 
 
203
def Object(env, **kwargs):
 
204
  return ExtendComponent(env, 'ComponentObject', **kwargs)
 
205
 
 
206
 
 
207
def Unittest(env, **kwargs):
 
208
  """Extends ComponentTestProgram to support unittest built
 
209
     for multiple platforms.
 
210
 
 
211
  Args:
 
212
    env: The current environment.
 
213
    kwargs: The keyword arguments.
 
214
 
 
215
  Returns:
 
216
    See swtoolkit ComponentProgram.
 
217
  """
 
218
  kwargs['name'] = kwargs['name'] + '_unittest'
 
219
 
 
220
  common_test_params = {
 
221
    'posix_cppdefines': ['GUNIT_NO_GOOGLE3', 'GTEST_HAS_RTTI=0'],
 
222
    'libs': ['unittest_main', 'gunit']
 
223
  }
 
224
  if 'explicit_libs' not in kwargs:
 
225
    common_test_params['win_libs'] = [
 
226
      'advapi32',
 
227
      'crypt32',
 
228
      'iphlpapi',
 
229
      'secur32',
 
230
      'shell32',
 
231
      'shlwapi',
 
232
      'user32',
 
233
      'wininet',
 
234
      'ws2_32'
 
235
    ]
 
236
    common_test_params['lin_libs'] = [
 
237
      'crypto',
 
238
      'pthread',
 
239
      'ssl',
 
240
    ]
 
241
 
 
242
  params = CombineDicts(kwargs, common_test_params)
 
243
  return ExtendComponent(env, 'ComponentTestProgram', **params)
 
244
 
 
245
 
 
246
def App(env, **kwargs):
 
247
  """Extends ComponentProgram to support executables with platform specific
 
248
     options.
 
249
 
 
250
  Args:
 
251
    env: The current environment.
 
252
    kwargs: The keyword arguments.
 
253
 
 
254
  Returns:
 
255
    See swtoolkit ComponentProgram.
 
256
  """
 
257
  if 'explicit_libs' not in kwargs:
 
258
    common_app_params = {
 
259
      'win_libs': [
 
260
        'advapi32',
 
261
        'crypt32',
 
262
        'iphlpapi',
 
263
        'secur32',
 
264
        'shell32',
 
265
        'shlwapi',
 
266
        'user32',
 
267
        'wininet',
 
268
        'ws2_32'
 
269
      ]}
 
270
    params = CombineDicts(kwargs, common_app_params)
 
271
  else:
 
272
    params = kwargs
 
273
  return ExtendComponent(env, 'ComponentProgram', **params)
 
274
 
 
275
def WiX(env, **kwargs):
 
276
  """ Extends the WiX builder
 
277
  Args:
 
278
    env: The current environment.
 
279
    kwargs: The keyword arguments.
 
280
 
 
281
  Returns:
 
282
    The node produced by the environment's wix builder
 
283
  """
 
284
  return ExtendComponent(env, 'WiX', **kwargs)
 
285
 
 
286
def Repository(env, at, path):
 
287
  """Maps a directory external to $MAIN_DIR to the given path so that sources
 
288
     compiled from it end up in the correct place under $OBJ_DIR.  NOT required
 
289
     when only referring to header files.
 
290
 
 
291
  Args:
 
292
    env: The current environment object.
 
293
    at: The 'mount point' within the current directory.
 
294
    path: Path to the actual directory.
 
295
  """
 
296
  env.Dir(at).addRepository(env.Dir(path))
 
297
 
 
298
 
 
299
def Components(*paths):
 
300
  """Completes the directory paths with the correct file
 
301
     names such that the directory/directory.scons name
 
302
     convention can be used.
 
303
 
 
304
  Args:
 
305
    paths: The paths to complete. If it refers to an existing
 
306
           file then it is ignored.
 
307
 
 
308
  Returns:
 
309
    The completed lif scons files that are needed to build talk.
 
310
  """
 
311
  files = []
 
312
  for path in paths:
 
313
    if os.path.isfile(path):
 
314
      files.append(path)
 
315
    else:
 
316
      files.append(ExpandSconsPath(path))
 
317
  return files
 
318
 
 
319
 
 
320
def ExpandSconsPath(path):
 
321
  """Expands a directory path into the path to the
 
322
     scons file that our build uses.
 
323
     Ex: magiflute/plugin/common => magicflute/plugin/common/common.scons
 
324
 
 
325
  Args:
 
326
    path: The directory path to expand.
 
327
 
 
328
  Returns:
 
329
    The expanded path.
 
330
  """
 
331
  return '%s/%s.scons' % (path, os.path.basename(path))
 
332
 
 
333
 
 
334
def ReadVersion(filename):
 
335
  """Executes the supplied file and pulls out a version definition from it. """
 
336
  defs = {}
 
337
  execfile(str(filename), defs)
 
338
  if 'version' not in defs:
 
339
    return '0.0.0.0'
 
340
  version = defs['version']
 
341
  parts = version.split(',')
 
342
  build = os.environ.get('GOOGLE_VERSION_BUILDNUMBER')
 
343
  if build:
 
344
    parts[-1] = str(build)
 
345
  return '.'.join(parts)
 
346
 
 
347
 
 
348
#-------------------------------------------------------------------------------
 
349
# Helper methods for translating talk.Foo() declarations in to manipulations of
 
350
# environmuent construction variables, including parameter parsing and merging,
 
351
#
 
352
def PopEntry(dictionary, key):
 
353
  """Get the value from a dictionary by key. If the key
 
354
     isn't in the dictionary then None is returned. If it is in
 
355
     the dictionary the value is fetched and then is it removed
 
356
     from the dictionary.
 
357
 
 
358
  Args:
 
359
    dictionary: The dictionary.
 
360
    key: The key to get the value for.
 
361
  Returns:
 
362
    The value or None if the key is missing.
 
363
  """
 
364
  value = None
 
365
  if key in dictionary:
 
366
    value = dictionary[key]
 
367
    dictionary.pop(key)
 
368
  return value
 
369
 
 
370
 
 
371
def MergeAndFilterByPlatform(env, params):
 
372
  """Take a dictionary of arguments to lists of values, and, depending on
 
373
     which platform we are targetting, merge the lists of associated keys.
 
374
     Merge by combining value lists like so:
 
375
       {win_foo = [a,b], lin_foo = [c,d], foo = [e], mac_bar = [f], bar = [g] }
 
376
       becomes {foo = [a,b,e], bar = [g]} on windows, and
 
377
       {foo = [e], bar = [f,g]} on mac
 
378
 
 
379
  Args:
 
380
    env: The hammer environment which knows which platforms are active
 
381
    params: The keyword argument dictionary.
 
382
  Returns:
 
383
    A new dictionary with the filtered and combined entries of params
 
384
  """
 
385
  platforms = {
 
386
    'linux': 'lin_',
 
387
    'mac': 'mac_',
 
388
    'posix': 'posix_',
 
389
    'windows': 'win_',
 
390
  }
 
391
  active_prefixes = [
 
392
    platforms[x] for x in iter(platforms) if env.Bit(x)
 
393
  ]
 
394
  inactive_prefixes = [
 
395
    platforms[x] for x in iter(platforms) if not env.Bit(x)
 
396
  ]
 
397
 
 
398
  merged = {}
 
399
  for arg, values in params.iteritems():
 
400
    inactive_platform = False
 
401
 
 
402
    key = arg
 
403
 
 
404
    for prefix in active_prefixes:
 
405
      if arg.startswith(prefix):
 
406
        key = arg[len(prefix):]
 
407
 
 
408
    for prefix in inactive_prefixes:
 
409
      if arg.startswith(prefix):
 
410
        inactive_platform = True
 
411
 
 
412
    if inactive_platform:
 
413
      continue
 
414
 
 
415
    AddToDict(merged, key, values)
 
416
 
 
417
  return merged
 
418
 
 
419
 
 
420
def MergeSettingsFromLibraryDependencies(env, params):
 
421
  if 'libs' in params:
 
422
    for lib in params['libs']:
 
423
      libparams = _GetLibParams(env, lib)
 
424
      if libparams:
 
425
        if 'dependent_target_settings' in libparams:
 
426
          params = CombineDicts(
 
427
              params,
 
428
              MergeAndFilterByPlatform(
 
429
                  env,
 
430
                  libparams['dependent_target_settings']))
 
431
  return params
 
432
 
 
433
 
 
434
def ExtendComponent(env, component, **kwargs):
 
435
  """A wrapper around a scons builder function that preprocesses and post-
 
436
     processes its inputs and outputs.  For example, it merges and filters
 
437
     certain keyword arguments before appending them to the environments
 
438
     construction variables.  It can build signed targets and 64bit copies
 
439
     of targets as well.
 
440
 
 
441
  Args:
 
442
    env: The hammer environment with which to build the target
 
443
    component: The environment's builder function, e.g. ComponentProgram
 
444
    kwargs: keyword arguments that are either merged, translated, and passed on
 
445
            to the call to component, or which control execution.
 
446
            TODO(): Document the fields, such as cppdefines->CPPDEFINES,
 
447
            prepend_includedirs, include_talk_media_libs, etc.
 
448
  Returns:
 
449
    The output node returned by the call to component, or a subsequent signed
 
450
    dependant node.
 
451
  """
 
452
  env = env.Clone()
 
453
 
 
454
  # prune parameters intended for other platforms, then merge
 
455
  params = MergeAndFilterByPlatform(env, kwargs)
 
456
 
 
457
  # get the 'target' field
 
458
  name = PopEntry(params, 'name')
 
459
 
 
460
  # get the 'packages' field and process it if present (only used for Linux).
 
461
  packages = PopEntry(params, 'packages')
 
462
  if packages and len(packages):
 
463
    params = CombineDicts(params, env.GetPackageParams(packages))
 
464
 
 
465
  # save pristine params of lib targets for future reference
 
466
  if 'ComponentLibrary' == component:
 
467
    _RecordLibParams(env, name, dict(params))
 
468
 
 
469
  # add any dependent target settings from library dependencies
 
470
  params = MergeSettingsFromLibraryDependencies(env, params)
 
471
 
 
472
  # if this is a signed binary we need to make an unsigned version first
 
473
  signed = env.Bit('windows') and PopEntry(params, 'signed')
 
474
  if signed:
 
475
    name = 'unsigned_' + name
 
476
 
 
477
  # potentially exit now
 
478
  srcs = PopEntry(params, 'srcs')
 
479
  if not srcs or not hasattr(env, component):
 
480
    return None
 
481
 
 
482
  # apply any explicit dependencies
 
483
  dependencies = PopEntry(params, 'depends')
 
484
  if dependencies is not None:
 
485
    env.Depends(name, dependencies)
 
486
 
 
487
  # put the contents of params into the environment
 
488
  # some entries are renamed then appended, others renamed then prepended
 
489
  appends = {
 
490
    'cppdefines' : 'CPPDEFINES',
 
491
    'libdirs' : 'LIBPATH',
 
492
    'link_flags' : 'LINKFLAGS',
 
493
    'libs' : 'LIBS',
 
494
    'FRAMEWORKS' : 'FRAMEWORKS',
 
495
  }
 
496
  prepends = {}
 
497
  if env.Bit('windows'):
 
498
    # MSVC compile flags have precedence at the beginning ...
 
499
    prepends['ccflags'] = 'CCFLAGS'
 
500
  else:
 
501
    # ... while GCC compile flags have precedence at the end
 
502
    appends['ccflags'] = 'CCFLAGS'
 
503
  if PopEntry(params, 'prepend_includedirs'):
 
504
    prepends['includedirs'] = 'CPPPATH'
 
505
  else:
 
506
    appends['includedirs'] = 'CPPPATH'
 
507
 
 
508
  for field, var in appends.items():
 
509
    values = PopEntry(params, field)
 
510
    if values is not None:
 
511
      env.Append(**{var : values})
 
512
  for field, var in prepends.items():
 
513
    values = PopEntry(params, field)
 
514
    if values is not None:
 
515
      env.Prepend(**{var : values})
 
516
 
 
517
  # any other parameters are replaced without renaming
 
518
  for field, value in params.items():
 
519
    env.Replace(**{field : value})
 
520
 
 
521
  if env.Bit('linux') and 'LIBS' in env:
 
522
    libs = env['LIBS']
 
523
    # When using --as-needed + --start/end-group, shared libraries need to come
 
524
    # after --end-group on the command-line because the pruning decision only
 
525
    # considers the preceding modules and --start/end-group may cause the
 
526
    # effective position of early static libraries on the command-line to be
 
527
    # deferred to the point of --end-group. To effect this, we move shared libs
 
528
    # into _LIBFLAGS, which has the --end-group as its first entry. SCons does
 
529
    # not track dependencies on system shared libraries anyway so we lose
 
530
    # nothing by removing them from LIBS.
 
531
    static_libs = [lib for lib in libs if
 
532
                   _GetLibParams(env, lib) or _IsPrebuiltLibrary(env, lib)]
 
533
    shared_libs = ['-l' + lib for lib in libs if not
 
534
                   (_GetLibParams(env, lib) or _IsPrebuiltLibrary(env, lib))]
 
535
    env.Replace(LIBS=static_libs)
 
536
    env.Append(_LIBFLAGS=shared_libs)
 
537
 
 
538
  # invoke the builder function
 
539
  builder = getattr(env, component)
 
540
 
 
541
  node = builder(name, srcs)
 
542
 
 
543
  if signed:
 
544
    # Get the name of the built binary, then get the name of the final signed
 
545
    # version from it.  We need the output path since we don't know the file
 
546
    # extension beforehand.
 
547
    target = node[0].path.split('_', 1)[1]
 
548
    # postsignprefix: If defined, postsignprefix is a string that should be
 
549
    # prepended to the target executable.  This is to provide a work around
 
550
    # for EXEs and DLLs with the same name, which thus have PDBs with the
 
551
    # same name.  Setting postsignprefix allows the EXE and its PDB
 
552
    # to be renamed and copied in a previous step; then the desired
 
553
    # name of the EXE (but not PDB) is reconstructed after signing.
 
554
    postsignprefix = PopEntry(params, 'postsignprefix')
 
555
    if postsignprefix is not None:
 
556
        target = postsignprefix + target
 
557
    signed_node = env.SignedBinary(
 
558
      source = node,
 
559
      target = '$STAGING_DIR/' + target,
 
560
    )
 
561
    env.Alias('signed_binaries', signed_node)
 
562
    return signed_node
 
563
 
 
564
  return node
 
565
 
 
566
 
 
567
def AddToDict(dictionary, key, values, append=True):
 
568
  """Merge the given key value(s) pair into a dictionary.  If it contains an
 
569
     entry with that key already, then combine by appending or prepending the
 
570
     values as directed.  Otherwise, assign a new keyvalue pair.
 
571
  """
 
572
  if values is None:
 
573
    return
 
574
 
 
575
  if key not in dictionary:
 
576
    dictionary[key] = values
 
577
    return
 
578
 
 
579
  cur = dictionary[key]
 
580
  # TODO: Make sure that there are no duplicates
 
581
  # in the list. I can't use python set for this since
 
582
  # the nodes that are returned by the SCONS builders
 
583
  # are not hashable.
 
584
  # dictionary[key] = list(set(cur).union(set(values)))
 
585
  if append:
 
586
    dictionary[key] = cur + values
 
587
  else:
 
588
    dictionary[key] = values + cur
 
589
 
 
590
 
 
591
def CombineDicts(a, b):
 
592
  """Unions two dictionaries of arrays/dictionaries.
 
593
 
 
594
  Unions two dictionaries of arrays/dictionaries by combining the values of keys
 
595
  shared between them. The original dictionaries should not be used again after
 
596
  this call.
 
597
 
 
598
  Args:
 
599
    a: First dict.
 
600
    b: Second dict.
 
601
 
 
602
  Returns:
 
603
    The union of a and b.
 
604
  """
 
605
  c = {}
 
606
  for key in a:
 
607
    if key in b:
 
608
      aval = a[key]
 
609
      bval = b.pop(key)
 
610
      if isinstance(aval, dict) and isinstance(bval, dict):
 
611
        c[key] = CombineDicts(aval, bval)
 
612
      else:
 
613
        c[key] = aval + bval
 
614
    else:
 
615
      c[key] = a[key]
 
616
 
 
617
  for key in b:
 
618
    c[key] = b[key]
 
619
 
 
620
  return c
 
621
 
 
622
 
 
623
def RenameKey(d, old, new, append=True):
 
624
  AddToDict(d, new, PopEntry(d, old), append)