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