Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: third_party/instrumented_libraries/download_build_install.py

Issue 337613008: Instrumented libraries: move build-flags-related logic to the GYP file. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | third_party/instrumented_libraries/instrumented_libraries.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Downloads, builds (with instrumentation) and installs shared libraries.""" 6 """Downloads, builds (with instrumentation) and installs shared libraries."""
7 7
8 import argparse 8 import argparse
9 import os 9 import os
10 import platform 10 import platform
11 import shlex
11 import shutil 12 import shutil
12 import subprocess 13 import subprocess
13 import sys 14 import sys
14 15
15 # Build parameters for different sanitizers.
16 # We use XORIGIN as RPATH and after building library replace it to $ORIGIN
17 # The reason: this flag goes through configure script and makefiles
18 # differently for different libraries. So the dollar sign '$' should be
19 # differently escaped. Instead of having problems with that it just
20 # uses XORIGIN to build library and after that replaces it to $ORIGIN
21 # directly in .so file.
22 SUPPORTED_SANITIZERS = {
23 'asan': {
24 'compiler_flags': '-O2 -fsanitize=address -gline-tables-only -fPIC -w '
25 '-U_FORITFY_SOURCE',
26 'linker_flags': '-fsanitize=address -Wl,-z,origin -Wl,-R,XORIGIN/.'
27 },
28 'msan': {
29 'compiler_flags': '-O2 -fsanitize=memory '
30 '-fsanitize-memory-track-origins '
31 '-gline-tables-only -fPIC -w -U_FORTIFY_SOURCE',
32 'linker_flags': '-fsanitize=memory -Wl,-z,origin -Wl,-R,XORIGIN/.'
33 },
34 'tsan': {
35 'compiler_flags': '-O2 -fsanitize=thread -gline-tables-only -fPIC -w '
36 '-U_FORTIFY_SOURCE',
37 'linker_flags': '-fsanitize=thread -Wl,-z,origin -Wl,-R,XORIGIN/.'
38 },
39 }
40
41
42 class ScopedChangeDirectory(object): 16 class ScopedChangeDirectory(object):
43 """Changes current working directory and restores it back automatically.""" 17 """Changes current working directory and restores it back automatically."""
44 18
45 def __init__(self, path): 19 def __init__(self, path):
46 self.path = path 20 self.path = path
47 self.old_path = '' 21 self.old_path = ''
48 22
49 def __enter__(self): 23 def __enter__(self):
50 self.old_path = os.getcwd() 24 self.old_path = os.getcwd()
51 os.chdir(self.path) 25 os.chdir(self.path)
52 return self 26 return self
53 27
54 def __exit__(self, exc_type, exc_value, traceback): 28 def __exit__(self, exc_type, exc_value, traceback):
55 os.chdir(self.old_path) 29 os.chdir(self.old_path)
56 30
57 31
58 def get_script_absolute_path(): 32 def get_script_absolute_path():
59 return os.path.dirname(os.path.abspath(__file__)) 33 return os.path.dirname(os.path.abspath(__file__))
60 34
61 35
62 def get_library_build_dependencies(library): 36 def get_package_build_dependencies(package):
63 command = 'apt-get -s build-dep %s | grep Inst | cut -d " " -f 2' % library 37 command = 'apt-get -s build-dep %s | grep Inst | cut -d " " -f 2' % package
64 command_result = subprocess.Popen(command, stdout=subprocess.PIPE, 38 command_result = subprocess.Popen(command, stdout=subprocess.PIPE,
65 shell=True) 39 shell=True)
66 if command_result.wait(): 40 if command_result.wait():
67 raise Exception('Failed to determine build dependencies for %s' % library) 41 raise Exception('Failed to determine build dependencies for %s' % package)
68 build_dependencies = [l.strip() for l in command_result.stdout] 42 build_dependencies = [l.strip() for l in command_result.stdout]
69 return build_dependencies 43 return build_dependencies
70 44
71 45
72 def check_library_build_dependencies(library): 46 def check_package_build_dependencies(package):
73 build_dependencies = get_library_build_dependencies(library) 47 build_dependencies = get_package_build_dependencies(package)
74 if len(build_dependencies): 48 if len(build_dependencies):
75 print >> sys.stderr, 'Please, install build-dependencies for %s' % library 49 print >> sys.stderr, 'Please, install build-dependencies for %s' % package
76 print >> sys.stderr, 'One-liner for APT:' 50 print >> sys.stderr, 'One-liner for APT:'
77 print >> sys.stderr, 'sudo apt-get -y --no-remove build-dep %s' % library 51 print >> sys.stderr, 'sudo apt-get -y --no-remove build-dep %s' % package
78 sys.exit(1) 52 sys.exit(1)
79 53
80 54
81 def shell_call(command, verbose=False, environment=None): 55 def shell_call(command, verbose=False, environment=None):
82 """ Wrapper on subprocess.Popen 56 """ Wrapper on subprocess.Popen
83 57
84 Calls command with specific environment and verbosity using 58 Calls command with specific environment and verbosity using
85 subprocess.Popen 59 subprocess.Popen
86 60
87 Args: 61 Args:
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 elif parsed_arguments.build_method == 'custom_libpci3': 225 elif parsed_arguments.build_method == 'custom_libpci3':
252 libpci3_make_install(parsed_arguments, environment, install_prefix) 226 libpci3_make_install(parsed_arguments, environment, install_prefix)
253 elif parsed_arguments.build_method == 'custom_libappindicator1': 227 elif parsed_arguments.build_method == 'custom_libappindicator1':
254 environment['CSC'] = '/usr/bin/mono-csc' 228 environment['CSC'] = '/usr/bin/mono-csc'
255 destdir_configure_make_install( 229 destdir_configure_make_install(
256 parsed_arguments, environment, install_prefix) 230 parsed_arguments, environment, install_prefix)
257 else: 231 else:
258 raise Exception('Unrecognized build method: %s' % 232 raise Exception('Unrecognized build method: %s' %
259 parsed_arguments.build_method) 233 parsed_arguments.build_method)
260 234
235 def unescape_flags(s):
236 # GYP escapes the build flags as if they are going to be inserted directly
237 # into the command line. Since we pass them via CFLAGS/LDFLAGS, we must drop
238 # the double quotes accordingly.
239 return ' '.join(shlex.split(s))
261 240
262 def download_build_install(parsed_arguments): 241 def download_build_install(parsed_arguments):
263 sanitizer_params = SUPPORTED_SANITIZERS[parsed_arguments.sanitizer_type]
264
265 environment = os.environ.copy() 242 environment = os.environ.copy()
266 # Usage of environment variables CC and CXX prefers usage flags --c-compiler 243 # The CC/CXX environment variables take precedence over the command line
267 # and --cxx-compiler 244 # flags.
268 if 'CC' not in environment and parsed_arguments.cc: 245 if 'CC' not in environment and parsed_arguments.cc:
269 environment['CC'] = parsed_arguments.cc 246 environment['CC'] = parsed_arguments.cc
270 if 'CXX' not in environment and parsed_arguments.cxx: 247 if 'CXX' not in environment and parsed_arguments.cxx:
271 environment['CXX'] = parsed_arguments.cxx 248 environment['CXX'] = parsed_arguments.cxx
272 249
273 product_directory = os.path.normpath('%s/%s' % ( 250 product_directory = os.path.normpath('%s/%s' % (
274 get_script_absolute_path(), 251 get_script_absolute_path(),
275 parsed_arguments.product_directory)) 252 parsed_arguments.product_directory))
276 253
277 compiler_flags = sanitizer_params['compiler_flags'] 254 cflags = unescape_flags(parsed_arguments.cflags)
278 if parsed_arguments.sanitizer_blacklist: 255 if parsed_arguments.sanitizer_blacklist:
279 compiler_flags += ' -fsanitize-blacklist=%s/%s' % ( 256 cflags += ' -fsanitize-blacklist=%s/%s' % (
280 product_directory, 257 product_directory,
281 parsed_arguments.sanitizer_blacklist) 258 parsed_arguments.sanitizer_blacklist)
282 environment['CFLAGS'] = '%s %s' % (compiler_flags, 259 environment['CFLAGS'] = cflags
283 parsed_arguments.extra_cflags) 260 environment['CXXFLAGS'] = cflags
284 environment['CXXFLAGS'] = '%s %s' % (
285 compiler_flags,
286 parsed_arguments.extra_cxxflags)
287 261
288 install_prefix = '%s/instrumented_libraries/%s' % ( 262 install_prefix = '%s/instrumented_libraries/%s' % (
289 product_directory, 263 product_directory,
290 parsed_arguments.sanitizer_type) 264 parsed_arguments.sanitizer_type)
291 265
266 ldflags = unescape_flags(parsed_arguments.ldflags)
292 # Make sure the linker searches the instrumented libraries dir for 267 # Make sure the linker searches the instrumented libraries dir for
293 # library dependencies. 268 # library dependencies.
294 environment['LDFLAGS'] = '%s -L%s/lib %s' % ( 269 environment['LDFLAGS'] = '%s -L%s/lib' % (ldflags, install_prefix)
295 sanitizer_params['linker_flags'],
296 install_prefix, parsed_arguments.extra_ldflags)
297 270
298 library_directory = '%s/%s' % (parsed_arguments.intermediate_directory, 271 package_directory = '%s/%s' % (parsed_arguments.intermediate_directory,
299 parsed_arguments.library) 272 parsed_arguments.package)
300 273
301 # A failed build might have left a dirty source tree behind. 274 # A failed build might have left a dirty source tree behind.
302 if os.path.exists(library_directory): 275 if os.path.exists(package_directory):
303 shell_call('rm -rf %s' % library_directory, parsed_arguments.verbose) 276 shell_call('rm -rf %s' % package_directory, parsed_arguments.verbose)
304 os.makedirs(library_directory) 277 os.makedirs(package_directory)
305 278
306 with ScopedChangeDirectory(library_directory) as cd_library: 279 with ScopedChangeDirectory(package_directory) as cd_package:
307 shell_call('apt-get source %s' % parsed_arguments.library, 280 shell_call('apt-get source %s' % parsed_arguments.package,
308 parsed_arguments.verbose) 281 parsed_arguments.verbose)
309 # There should be exactly one subdirectory after downloading a package. 282 # There should be exactly one subdirectory after downloading a package.
310 subdirectories = [d for d in os.listdir('.') if os.path.isdir(d)] 283 subdirectories = [d for d in os.listdir('.') if os.path.isdir(d)]
311 if len(subdirectories) != 1: 284 if len(subdirectories) != 1:
312 raise (Exception('There was not one directory after downloading ' 285 raise (Exception('There was not one directory after downloading '
313 'a package %s' % parsed_arguments.library)) 286 'a package %s' % parsed_arguments.package))
314 with ScopedChangeDirectory(subdirectories[0]): 287 with ScopedChangeDirectory(subdirectories[0]):
315 # Here we are in the package directory. 288 # Here we are in the package directory.
316 if parsed_arguments.run_before_build: 289 if parsed_arguments.run_before_build:
317 shell_call( 290 shell_call(
318 '%s/%s' % 291 '%s/%s' %
319 (os.path.relpath(cd_library.old_path), 292 (os.path.relpath(cd_package.old_path),
320 parsed_arguments.run_before_build), 293 parsed_arguments.run_before_build),
321 parsed_arguments.verbose) 294 parsed_arguments.verbose)
322 try: 295 try:
323 build_and_install(parsed_arguments, environment, install_prefix) 296 build_and_install(parsed_arguments, environment, install_prefix)
324 except Exception as exception: 297 except Exception as exception:
325 print exception 298 print exception
326 print 'Failed to build library %s.' % parsed_arguments.library 299 print 'Failed to build package %s.' % parsed_arguments.package
327 print ('Probably, some of its dependencies are not installed: %s' % 300 print ('Probably, some of its dependencies are not installed: %s' %
328 ' '.join(get_library_build_dependencies(parsed_arguments.library) )) 301 ' '.join(get_package_build_dependencies(parsed_arguments.package) ))
329 sys.exit(1) 302 sys.exit(1)
330 303
331 # Touch a txt file to indicate library is installed. 304 # Touch a txt file to indicate package is installed.
332 open('%s/%s.txt' % (install_prefix, parsed_arguments.library), 'w').close() 305 open('%s/%s.txt' % (install_prefix, parsed_arguments.package), 'w').close()
333 306
334 # Remove downloaded package and generated temporary build files. 307 # Remove downloaded package and generated temporary build files.
335 # Failed builds intentionally skip this step, in order to aid in tracking down 308 # Failed builds intentionally skip this step, in order to aid in tracking down
336 # build failures. 309 # build failures.
337 shell_call('rm -rf %s' % library_directory, parsed_arguments.verbose) 310 shell_call('rm -rf %s' % package_directory, parsed_arguments.verbose)
338
339 311
340 def main(): 312 def main():
341 argument_parser = argparse.ArgumentParser( 313 argument_parser = argparse.ArgumentParser(
342 description='Download, build and install instrumented library') 314 description='Download, build and install instrumented package')
343 315
344 argument_parser.add_argument('-j', '--jobs', type=int, default=1) 316 argument_parser.add_argument('-j', '--jobs', type=int, default=1)
345 argument_parser.add_argument('-l', '--library', required=True) 317 argument_parser.add_argument('-p', '--package', required=True)
346 argument_parser.add_argument( 318 argument_parser.add_argument(
347 '-i', '--product-directory', default='.', 319 '-i', '--product-directory', default='.',
348 help='Relative path to the directory with chrome binaries') 320 help='Relative path to the directory with chrome binaries')
349 argument_parser.add_argument( 321 argument_parser.add_argument(
350 '-m', '--intermediate-directory', default='.', 322 '-m', '--intermediate-directory', default='.',
351 help='Relative path to the directory for temporary build files') 323 help='Relative path to the directory for temporary build files')
352 argument_parser.add_argument('--extra-configure-flags', default='') 324 argument_parser.add_argument('--extra-configure-flags', default='')
353 argument_parser.add_argument('--extra-cflags', default='') 325 argument_parser.add_argument('--cflags', default='')
354 argument_parser.add_argument('--extra-cxxflags', default='') 326 argument_parser.add_argument('--ldflags', default='')
355 argument_parser.add_argument('--extra-ldflags', default='')
356 argument_parser.add_argument('-s', '--sanitizer-type', required=True, 327 argument_parser.add_argument('-s', '--sanitizer-type', required=True,
357 choices=SUPPORTED_SANITIZERS.keys()) 328 choices=['asan', 'msan', 'tsan'])
358 argument_parser.add_argument('-v', '--verbose', action='store_true') 329 argument_parser.add_argument('-v', '--verbose', action='store_true')
359 argument_parser.add_argument('--check-build-deps', action='store_true') 330 argument_parser.add_argument('--check-build-deps', action='store_true')
360 argument_parser.add_argument('--cc') 331 argument_parser.add_argument('--cc')
361 argument_parser.add_argument('--cxx') 332 argument_parser.add_argument('--cxx')
362 # This should be a shell script to run before building specific libraries 333 # This should be a shell script to run before building specific libraries
363 # e.g. extracting archives with sources, patching makefiles, etc. 334 # e.g. extracting archives with sources, patching makefiles, etc.
364 argument_parser.add_argument('--run-before-build', default='') 335 argument_parser.add_argument('--run-before-build', default='')
365 argument_parser.add_argument('--build-method', default='destdir') 336 argument_parser.add_argument('--build-method', default='destdir')
366 argument_parser.add_argument('--sanitizer-blacklist', default='') 337 argument_parser.add_argument('--sanitizer-blacklist', default='')
367 338
368 # Ignore all empty arguments because in several cases gyp passes them to the 339 # Ignore all empty arguments because in several cases gyp passes them to the
369 # script, but ArgumentParser treats them as positional arguments instead of 340 # script, but ArgumentParser treats them as positional arguments instead of
370 # ignoring (and doesn't have such options). 341 # ignoring (and doesn't have such options).
371 parsed_arguments = argument_parser.parse_args( 342 parsed_arguments = argument_parser.parse_args(
372 [arg for arg in sys.argv[1:] if len(arg) != 0]) 343 [arg for arg in sys.argv[1:] if len(arg) != 0])
373 # Ensure current working directory is this script directory. 344 # Ensure current working directory is this script directory.
374 os.chdir(get_script_absolute_path()) 345 os.chdir(get_script_absolute_path())
375 # Ensure all build dependencies are installed. 346 # Ensure all build dependencies are installed.
376 if parsed_arguments.check_build_deps: 347 if parsed_arguments.check_build_deps:
377 check_library_build_dependencies(parsed_arguments.library) 348 check_package_build_dependencies(parsed_arguments.package)
378 349
379 download_build_install(parsed_arguments) 350 download_build_install(parsed_arguments)
380 351
381 352
382 if __name__ == '__main__': 353 if __name__ == '__main__':
383 main() 354 main()
OLDNEW
« no previous file with comments | « no previous file | third_party/instrumented_libraries/instrumented_libraries.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698