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