summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/webrtc/build/toolchain/wrapper_utils.py
blob: f76192e206322e902146e241830201f040a73d84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Copyright (c) 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Helper functions for gcc_toolchain.gni wrappers."""

import gzip
import os
import re
import subprocess
import shlex
import shutil
import sys
import threading

_BAT_PREFIX = 'cmd /c call '
_WHITELIST_RE = re.compile('whitelisted_resource_(?P<resource_id>[0-9]+)')


def _GzipThenDelete(src_path, dest_path):
  # Results for Android map file with GCC on a z620:
  # Uncompressed: 207MB
  # gzip -9: 16.4MB, takes 8.7 seconds.
  # gzip -1: 21.8MB, takes 2.0 seconds.
  # Piping directly from the linker via -print-map (or via -Map with a fifo)
  # adds a whopping 30-45 seconds!
  with open(src_path, 'rb') as f_in, gzip.GzipFile(dest_path, 'wb', 1) as f_out:
    shutil.copyfileobj(f_in, f_out)
  os.unlink(src_path)


def CommandToRun(command):
  """Generates commands compatible with Windows.

  When running on a Windows host and using a toolchain whose tools are
  actually wrapper scripts (i.e. .bat files on Windows) rather than binary
  executables, the |command| to run has to be prefixed with this magic.
  The GN toolchain definitions take care of that for when GN/Ninja is
  running the tool directly.  When that command is passed in to this
  script, it appears as a unitary string but needs to be split up so that
  just 'cmd' is the actual command given to Python's subprocess module.

  Args:
    command: List containing the UNIX style |command|.

  Returns:
    A list containing the Windows version of the |command|.
  """
  if command[0].startswith(_BAT_PREFIX):
    command = command[0].split(None, 3) + command[1:]
  return command


def RunLinkWithOptionalMapFile(command, env=None, map_file=None):
  """Runs the given command, adding in -Wl,-Map when |map_file| is given.

  Also takes care of gzipping when |map_file| ends with .gz.

  Args:
    command: List of arguments comprising the command.
    env: Environment variables.
    map_file: Path to output map_file.

  Returns:
    The exit code of running |command|.
  """
  tmp_map_path = None
  if map_file and map_file.endswith('.gz'):
    tmp_map_path = map_file + '.tmp'
    command.append('-Wl,-Map,' + tmp_map_path)
  elif map_file:
    command.append('-Wl,-Map,' + map_file)

  result = subprocess.call(command, env=env)

  if tmp_map_path and result == 0:
    threading.Thread(
        target=lambda: _GzipThenDelete(tmp_map_path, map_file)).start()
  elif tmp_map_path and os.path.exists(tmp_map_path):
    os.unlink(tmp_map_path)

  return result


def ResolveRspLinks(inputs):
  """Return a list of files contained in a response file.

  Args:
    inputs: A command containing rsp files.

  Returns:
    A set containing the rsp file content."""
  rspfiles = [a[1:] for a in inputs if a.startswith('@')]
  resolved = set()
  for rspfile in rspfiles:
    with open(rspfile, 'r') as f:
      resolved.update(shlex.split(f.read()))

  return resolved


def CombineResourceWhitelists(whitelist_candidates, outfile):
  """Combines all whitelists for a resource file into a single whitelist.

  Args:
    whitelist_candidates: List of paths to rsp files containing all targets.
    outfile: Path to save the combined whitelist.
  """
  whitelists = ('%s.whitelist' % candidate for candidate in whitelist_candidates
                if os.path.exists('%s.whitelist' % candidate))

  resources = set()
  for whitelist in whitelists:
    with open(whitelist, 'r') as f:
      resources.update(f.readlines())

  with open(outfile, 'w') as f:
    f.writelines(resources)


def ExtractResourceIdsFromPragmaWarnings(text):
  """Returns set of resource IDs that are inside unknown pragma warnings.

  Args:
    text: The text that will be scanned for unknown pragma warnings.

  Returns:
    A set containing integers representing resource IDs.
  """
  used_resources = set()
  lines = text.splitlines()
  for ln in lines:
    match = _WHITELIST_RE.search(ln)
    if match:
      resource_id = int(match.group('resource_id'))
      used_resources.add(resource_id)

  return used_resources


def CaptureCommandStderr(command, env=None):
  """Returns the stderr of a command.

  Args:
    command: A list containing the command and arguments.
    env: Environment variables for the new process.
  """
  child = subprocess.Popen(command, stderr=subprocess.PIPE, env=env)
  _, stderr = child.communicate()
  return child.returncode, stderr