1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2016 The Chromium Authors. All rights reserved. 4 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7 8"""Helper functions for gcc_toolchain.gni wrappers.""" 9 10import gzip 11import os 12import subprocess 13import shutil 14import threading 15 16_BAT_PREFIX = 'cmd /c call ' 17 18 19def _gzip_then_delete(src_path, dest_path): 20 """ Results for ohos map file with GCC on a z620: 21 Uncompressed: 207MB 22 gzip -9: 16.4MB, takes 8.7 seconds. 23 gzip -1: 21.8MB, takes 2.0 seconds. 24 Piping directly from the linker via -print-map (or via -Map with a fifo) 25 adds a whopping 30-45 seconds! 26 """ 27 with open(src_path, 'rb') as f_in, gzip.GzipFile(dest_path, 28 'wb', 29 1) as f_out: 30 shutil.copyfileobj(f_in, f_out) 31 os.unlink(src_path) 32 33 34def command_to_run(command): 35 """Generates commands compatible with Windows. 36 37 When running on a Windows host and using a toolchain whose tools are 38 actually wrapper scripts (i.e. .bat files on Windows) rather than binary 39 executables, the |command| to run has to be prefixed with this magic. 40 The GN toolchain definitions take care of that for when GN/Ninja is 41 running the tool directly. When that command is passed in to this 42 script, it appears as a unitary string but needs to be split up so that 43 just 'cmd' is the actual command given to Python's subprocess module. 44 45 Args: 46 command: List containing the UNIX style |command|. 47 48 Returns: 49 A list containing the Windows version of the |command|. 50 """ 51 if command[0].startswith(_BAT_PREFIX): 52 command = command[0].split(None, 3) + command[1:] 53 return command 54 55 56def run_link_with_optional_map_file(command, env=None, map_file=None): 57 """Runs the given command, adding in -Wl,-Map when |map_file| is given. 58 59 Also takes care of gzipping when |map_file| ends with .gz. 60 61 Args: 62 command: List of arguments comprising the command. 63 env: Environment variables. 64 map_file: Path to output map_file. 65 66 Returns: 67 The exit code of running |command|. 68 """ 69 tmp_map_path = None 70 if map_file and map_file.endswith('.gz'): 71 tmp_map_path = map_file + '.tmp' 72 command.append('-Wl,-Map,' + tmp_map_path) 73 elif map_file: 74 command.append('-Wl,-Map,' + map_file) 75 76 result = subprocess.call(command, env=env) 77 78 if tmp_map_path and result == 0: 79 threading.Thread( 80 target=lambda: _gzip_then_delete(tmp_map_path, map_file)).start() 81 elif tmp_map_path and os.path.exists(tmp_map_path): 82 os.unlink(tmp_map_path) 83 84 return result 85 86 87def capture_command_stderr(command, env=None): 88 """Returns the stderr of a command. 89 90 Args: 91 command: A list containing the command and arguments. 92 env: Environment variables for the new process. 93 """ 94 child = subprocess.Popen(command, stderr=subprocess.PIPE, env=env) 95 _, stderr = child.communicate() 96 return child.returncode, stderr 97