| # 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 ' | |
| 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 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 |