2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
7 This file holds a list of reasons why a particular build needs to be clobbered
8 (or a list of 'landmines').
10 This script runs every build as a hook. If it detects that the build should
11 be clobbered, it will touch the file <build_dir>/.landmine_triggered. The
12 various build scripts will then check for the presence of this file and clobber
13 accordingly. The script will also emit the reasons for the clobber to stdout.
15 A landmine is tripped when a builder checks out a different revision, and the
16 diff between the new landmines and the old ones is non-null. At this point, the
30 SRC_DIR
= os
.path
.dirname(os
.path
.dirname(os
.path
.realpath(__file__
)))
32 def memoize(default
=None):
33 """This decorator caches the return value of a parameterless pure function"""
36 @functools.wraps(func
)
40 val
.append(ret
if ret
is not None else default
)
41 if logging
.getLogger().isEnabledFor(logging
.INFO
):
42 print '%s -> %r' % (func
.__name
__, val
[0])
50 return sys
.platform
in ['win32', 'cygwin']
55 return sys
.platform
.startswith('linux')
60 return sys
.platform
== 'darwin'
65 """Parses and returns GYP_DEFINES env var as a dictionary."""
66 return dict(arg
.split('=', 1)
67 for arg
in shlex
.split(os
.environ
.get('GYP_DEFINES', '')))
73 Returns a string which is the distributed build engine in use (if any).
74 Possible values: 'goma', 'ib', ''
76 if 'goma' in gyp_defines():
79 if 'CHROME_HEADLESS' in os
.environ
:
80 return 'ib' # use (win and !goma and headless) as approximation of ib
86 Returns a string representing the platform this build is targetted for.
87 Possible values: 'win', 'mac', 'linux', 'ios', 'android'
89 if 'OS' in gyp_defines():
90 if 'android' in gyp_defines()['OS']:
93 return gyp_defines()['OS']
105 Returns a string representing the build engine (not compiler) to use.
106 Possible values: 'make', 'ninja', 'xcode', 'msvs', 'scons'
108 if 'GYP_GENERATORS' in os
.environ
:
109 # for simplicity, only support the first explicit generator
110 generator
= os
.environ
['GYP_GENERATORS'].split(',')[0]
111 if generator
.endswith('-android'):
112 return generator
.split('-')[0]
113 elif generator
.endswith('-ninja'):
118 if platform() == 'android':
119 # Good enough for now? Do any android bots use make?
121 elif platform() == 'ios':
130 assert False, 'Don\'t know what builder we\'re using!'
133 def get_landmines(target
):
135 ALL LANDMINES ARE DEFINED HERE.
136 target is 'Release' or 'Debug'
139 add
= lambda item
: landmines
.append(item
+ '\n')
141 if (distributor() == 'goma' and platform() == 'win32' and
142 builder() == 'ninja'):
143 add('Need to clobber winja goma due to backend cwd cache fix.')
144 if platform() == 'android':
145 add('Clobber: Resources removed in r195014 require clobber.')
146 if platform() == 'win' and builder() == 'ninja':
147 add('Compile on cc_unittests fails due to symbols removed in r185063.')
148 if platform() == 'linux' and builder() == 'ninja':
149 add('Builders switching from make to ninja will clobber on this.')
150 if platform() == 'mac':
151 add('Switching from bundle to unbundled dylib (issue 14743002).')
156 def get_target_build_dir(build_tool
, target
, is_iphone
=False):
158 Returns output directory absolute path dependent on build and targets.
160 r'c:\b\build\slave\win\build\src\out\Release'
161 '/mnt/data/b/build/slave/linux/build/src/out/Debug'
162 '/b/build/slave/ios_rel_device/build/src/xcodebuild/Release-iphoneos'
164 Keep this function in sync with tools/build/scripts/slave/compile.py
167 if build_tool
== 'xcode':
168 ret
= os
.path
.join(SRC_DIR
, 'xcodebuild',
169 target
+ ('-iphoneos' if is_iphone
else ''))
170 elif build_tool
in ['make', 'ninja', 'ninja-ios']: # TODO: Remove ninja-ios.
171 ret
= os
.path
.join(SRC_DIR
, 'out', target
)
172 elif build_tool
in ['msvs', 'vs', 'ib']:
173 ret
= os
.path
.join(SRC_DIR
, 'build', target
)
174 elif build_tool
== 'scons':
175 ret
= os
.path
.join(SRC_DIR
, 'sconsbuild', target
)
177 raise NotImplementedError('Unexpected GYP_GENERATORS (%s)' % build_tool
)
178 return os
.path
.abspath(ret
)
181 def set_up_landmines(target
):
182 """Does the work of setting, planting, and triggering landmines."""
183 out_dir
= get_target_build_dir(builder(), target
, platform() == 'ios')
185 landmines_path
= os
.path
.join(out_dir
, '.landmines')
186 if not os
.path
.exists(out_dir
):
189 new_landmines
= get_landmines(target
)
191 if not os
.path
.exists(landmines_path
):
192 with
open(landmines_path
, 'w') as f
:
193 f
.writelines(new_landmines
)
195 triggered
= os
.path
.join(out_dir
, '.landmines_triggered')
196 with
open(landmines_path
, 'r') as f
:
197 old_landmines
= f
.readlines()
198 if old_landmines
!= new_landmines
:
199 old_date
= time
.ctime(os
.stat(landmines_path
).st_ctime
)
200 diff
= difflib
.unified_diff(old_landmines
, new_landmines
,
201 fromfile
='old_landmines', tofile
='new_landmines',
202 fromfiledate
=old_date
, tofiledate
=time
.ctime(), n
=0)
204 with
open(triggered
, 'w') as f
:
206 elif os
.path
.exists(triggered
):
207 # Remove false triggered landmines.
212 parser
= optparse
.OptionParser()
213 parser
.add_option('-v', '--verbose', action
='store_true',
214 default
=('LANDMINES_VERBOSE' in os
.environ
),
215 help=('Emit some extra debugging information (default off). This option '
216 'is also enabled by the presence of a LANDMINES_VERBOSE environment '
218 options
, args
= parser
.parse_args()
221 parser
.error('Unknown arguments %s' % args
)
224 level
=logging
.DEBUG
if options
.verbose
else logging
.ERROR
)
226 gyp_helper
.apply_chromium_gyp_env()
228 for target
in ('Debug', 'Release', 'Debug_x64', 'Release_x64'):
229 set_up_landmines(target
)
234 if __name__
== '__main__':