| OLD | NEW |
| 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 re | 11 import re |
| 12 import shlex | 12 import shlex |
| 13 import shutil | 13 import shutil |
| 14 import subprocess | 14 import subprocess |
| 15 import sys | 15 import sys |
| 16 | 16 |
| 17 SCRIPT_ABSOLUTE_PATH = os.path.dirname(os.path.abspath(__file__)) | 17 SCRIPT_ABSOLUTE_PATH = os.path.dirname(os.path.abspath(__file__)) |
| 18 | 18 |
| 19 def unescape_flags(s): | 19 def unescape_flags(s): |
| 20 """Un-escapes build flags received from GYP. | 20 """Un-escapes build flags received from GYP. |
| 21 | 21 |
| 22 GYP escapes build flags as if they are to be inserted directly into a command | 22 GYP escapes build flags as if they are to be inserted directly into a command |
| 23 line, wrapping each flag in double quotes. When flags are passed via | 23 line, wrapping each flag in double quotes. When flags are passed via |
| 24 CFLAGS/LDFLAGS instead, double quotes must be dropped. | 24 CFLAGS/LDFLAGS instead, double quotes must be dropped. |
| 25 """ | 25 """ |
| 26 return ' '.join(shlex.split(s)) | 26 return ' '.join(shlex.split(s)) |
| 27 | 27 |
| 28 | 28 |
| 29 def real_path(path_relative_to_script): | 29 def real_path(path_relative_to_gyp): |
| 30 """Returns the absolute path to a file. | 30 """Returns the absolute path to a file. |
| 31 | 31 |
| 32 GYP generates paths relative to the location of the .gyp file, which coincides | 32 GYP generates paths relative to the location of the .gyp file, which is one |
| 33 with the location of this script. This function converts them to absolute | 33 level above the location of this script. This function converts them to |
| 34 paths. | 34 absolute paths. |
| 35 """ | 35 """ |
| 36 return os.path.realpath(os.path.join(SCRIPT_ABSOLUTE_PATH, | 36 return os.path.realpath(os.path.join(SCRIPT_ABSOLUTE_PATH, '..', |
| 37 path_relative_to_script)) | 37 path_relative_to_gyp)) |
| 38 | 38 |
| 39 | 39 |
| 40 class InstrumentedPackageBuilder(object): | 40 class InstrumentedPackageBuilder(object): |
| 41 """Checks out and builds a single instrumented package.""" | 41 """Checks out and builds a single instrumented package.""" |
| 42 def __init__(self, args, clobber): | 42 def __init__(self, args, clobber): |
| 43 self._cc = args.cc | 43 self._cc = args.cc |
| 44 self._cxx = args.cxx | 44 self._cxx = args.cxx |
| 45 self._extra_configure_flags = args.extra_configure_flags | 45 self._extra_configure_flags = args.extra_configure_flags |
| 46 self._jobs = args.jobs | 46 self._jobs = args.jobs |
| 47 self._libdir = args.libdir | 47 self._libdir = args.libdir |
| 48 self._package = args.package | 48 self._package = args.package |
| 49 self._patch = real_path(args.patch) if args.patch else None | 49 self._patch = real_path(args.patch) if args.patch else None |
| 50 self._run_before_build = \ | 50 self._pre_build = \ |
| 51 real_path(args.run_before_build) if args.run_before_build else None | 51 real_path(args.pre_build) if args.pre_build else None |
| 52 self._sanitizer = args.sanitizer | 52 self._sanitizer = args.sanitizer |
| 53 self._verbose = args.verbose | 53 self._verbose = args.verbose |
| 54 self._clobber = clobber | 54 self._clobber = clobber |
| 55 self._working_dir = os.path.join( | 55 self._working_dir = os.path.join( |
| 56 real_path(args.intermediate_dir), self._package, '') | 56 real_path(args.intermediate_dir), self._package, '') |
| 57 | 57 |
| 58 product_dir = real_path(args.product_dir) | 58 product_dir = real_path(args.product_dir) |
| 59 self._destdir = os.path.join( | 59 self._destdir = os.path.join( |
| 60 product_dir, 'instrumented_libraries', self._sanitizer) | 60 product_dir, 'instrumented_libraries', self._sanitizer) |
| 61 self._source_archives_dir = os.path.join( | 61 self._source_archives_dir = os.path.join( |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 raise Exception('Can\'t find source archives after `apt-get source %s\'.' | 132 raise Exception('Can\'t find source archives after `apt-get source %s\'.' |
| 133 % self._package) | 133 % self._package) |
| 134 self._source_archives = \ | 134 self._source_archives = \ |
| 135 [os.path.join(dirpath, filename) for filename in filenames] | 135 [os.path.join(dirpath, filename) for filename in filenames] |
| 136 | 136 |
| 137 return get_fresh_source | 137 return get_fresh_source |
| 138 | 138 |
| 139 def patch_source(self): | 139 def patch_source(self): |
| 140 if self._patch: | 140 if self._patch: |
| 141 self.shell_call('patch -p1 -i %s' % self._patch, cwd=self._source_dir) | 141 self.shell_call('patch -p1 -i %s' % self._patch, cwd=self._source_dir) |
| 142 if self._run_before_build: | 142 if self._pre_build: |
| 143 self.shell_call(self._run_before_build, cwd=self._source_dir) | 143 self.shell_call(self._pre_build, cwd=self._source_dir) |
| 144 | 144 |
| 145 def copy_source_archives(self): | 145 def copy_source_archives(self): |
| 146 """Copies the downloaded source archives to the output dir. | 146 """Copies the downloaded source archives to the output dir. |
| 147 | 147 |
| 148 For license compliance purposes, every Chromium build that includes | 148 For license compliance purposes, every Chromium build that includes |
| 149 instrumented libraries must include their full source code. | 149 instrumented libraries must include their full source code. |
| 150 """ | 150 """ |
| 151 self.shell_call('rm -rf %s' % self._source_archives_dir) | 151 self.shell_call('rm -rf %s' % self._source_archives_dir) |
| 152 os.makedirs(self._source_archives_dir) | 152 os.makedirs(self._source_archives_dir) |
| 153 for filename in self._source_archives: | 153 for filename in self._source_archives: |
| 154 shutil.copy(filename, self._source_archives_dir) | 154 shutil.copy(filename, self._source_archives_dir) |
| 155 if self._patch: | 155 if self._patch: |
| 156 shutil.copy(self._patch, self._source_archives_dir) | 156 shutil.copy(self._patch, self._source_archives_dir) |
| 157 | 157 |
| 158 def download_build_install(self): | 158 def download_build_install(self): |
| 159 got_fresh_source = self.maybe_download_source() | 159 got_fresh_source = self.maybe_download_source() |
| 160 if got_fresh_source: | 160 if got_fresh_source: |
| 161 self.patch_source() | 161 self.patch_source() |
| 162 self.copy_source_archives() | 162 self.copy_source_archives() |
| 163 | 163 |
| 164 self.shell_call('mkdir -p %s' % self.dest_libdir()) | 164 self.shell_call('mkdir -p %s' % self.dest_libdir()) |
| 165 | 165 |
| 166 try: | 166 try: |
| 167 self.build_and_install() | 167 self.build_and_install() |
| 168 except Exception as exception: | 168 except Exception as exception: |
| 169 print 'ERROR: Failed to build package %s. Have you run ' \ | 169 print 'ERROR: Failed to build package %s. Have you run ' \ |
| 170 'src/third_party/instrumented_libraries/install-build-deps.sh?' % \ | 170 'src/third_party/instrumented_libraries/scripts/' \ |
| 171 'install-build-deps.sh?' % \ |
| 171 self._package | 172 self._package |
| 172 print | 173 print |
| 173 raise | 174 raise |
| 174 | 175 |
| 175 # Touch a text file to indicate package is installed. | 176 # Touch a text file to indicate package is installed. |
| 176 stamp_file = os.path.join(self._destdir, '%s.txt' % self._package) | 177 stamp_file = os.path.join(self._destdir, '%s.txt' % self._package) |
| 177 open(stamp_file, 'w').close() | 178 open(stamp_file, 'w').close() |
| 178 | 179 |
| 179 # Remove downloaded package and generated temporary build files. Failed | 180 # Remove downloaded package and generated temporary build files. Failed |
| 180 # builds intentionally skip this step to help debug build failures. | 181 # builds intentionally skip this step to help debug build failures. |
| 181 if self._clobber: | 182 if self._clobber: |
| 182 self.shell_call('rm -rf %s' % self._working_dir) | 183 self.shell_call('rm -rf %s' % self._working_dir) |
| 183 | 184 |
| 184 def fix_rpaths(self, directory): | 185 def fix_rpaths(self, directory): |
| 185 # TODO(earthdok): reimplement fix_rpaths.sh in Python. | 186 # TODO(earthdok): reimplement fix_rpaths.sh in Python. |
| 186 script = real_path('fix_rpaths.sh') | 187 script = real_path('scripts/fix_rpaths.sh') |
| 187 self.shell_call("%s %s" % (script, directory)) | 188 self.shell_call("%s %s" % (script, directory)) |
| 188 | 189 |
| 189 def temp_dir(self): | 190 def temp_dir(self): |
| 190 """Returns the directory which will be passed to `make install'.""" | 191 """Returns the directory which will be passed to `make install'.""" |
| 191 return os.path.join(self._source_dir, 'debian', 'instrumented_build') | 192 return os.path.join(self._source_dir, 'debian', 'instrumented_build') |
| 192 | 193 |
| 193 def temp_libdir(self): | 194 def temp_libdir(self): |
| 194 """Returns the directory under temp_dir() containing the DSOs.""" | 195 """Returns the directory under temp_dir() containing the DSOs.""" |
| 195 return os.path.join(self.temp_dir(), self._libdir) | 196 return os.path.join(self.temp_dir(), self._libdir) |
| 196 | 197 |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 parser.add_argument('--cflags', default='') | 386 parser.add_argument('--cflags', default='') |
| 386 parser.add_argument('--ldflags', default='') | 387 parser.add_argument('--ldflags', default='') |
| 387 parser.add_argument('-s', '--sanitizer', required=True, | 388 parser.add_argument('-s', '--sanitizer', required=True, |
| 388 choices=['asan', 'msan', 'tsan']) | 389 choices=['asan', 'msan', 'tsan']) |
| 389 parser.add_argument('-v', '--verbose', action='store_true') | 390 parser.add_argument('-v', '--verbose', action='store_true') |
| 390 parser.add_argument('--cc') | 391 parser.add_argument('--cc') |
| 391 parser.add_argument('--cxx') | 392 parser.add_argument('--cxx') |
| 392 parser.add_argument('--patch', default='') | 393 parser.add_argument('--patch', default='') |
| 393 # This should be a shell script to run before building specific libraries. | 394 # This should be a shell script to run before building specific libraries. |
| 394 # This will be run after applying the patch above. | 395 # This will be run after applying the patch above. |
| 395 parser.add_argument('--run-before-build', default='') | 396 parser.add_argument('--pre-build', default='') |
| 396 parser.add_argument('--build-method', default='destdir') | 397 parser.add_argument('--build-method', default='destdir') |
| 397 parser.add_argument('--sanitizer-blacklist', default='') | 398 parser.add_argument('--sanitizer-blacklist', default='') |
| 398 # The LIBDIR argument to configure/make. | 399 # The LIBDIR argument to configure/make. |
| 399 parser.add_argument('--libdir', default='lib') | 400 parser.add_argument('--libdir', default='lib') |
| 400 | 401 |
| 401 # Ignore all empty arguments because in several cases gyp passes them to the | 402 # Ignore all empty arguments because in several cases gyp passes them to the |
| 402 # script, but ArgumentParser treats them as positional arguments instead of | 403 # script, but ArgumentParser treats them as positional arguments instead of |
| 403 # ignoring (and doesn't have such options). | 404 # ignoring (and doesn't have such options). |
| 404 args = parser.parse_args([arg for arg in sys.argv[1:] if len(arg) != 0]) | 405 args = parser.parse_args([arg for arg in sys.argv[1:] if len(arg) != 0]) |
| 405 | 406 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 416 builder = LibcapBuilder(args, clobber) | 417 builder = LibcapBuilder(args, clobber) |
| 417 elif args.build_method == 'custom_libpci3': | 418 elif args.build_method == 'custom_libpci3': |
| 418 builder = Libpci3Builder(args, clobber) | 419 builder = Libpci3Builder(args, clobber) |
| 419 else: | 420 else: |
| 420 raise Exception('Unrecognized build method: %s' % args.build_method) | 421 raise Exception('Unrecognized build method: %s' % args.build_method) |
| 421 | 422 |
| 422 builder.download_build_install() | 423 builder.download_build_install() |
| 423 | 424 |
| 424 if __name__ == '__main__': | 425 if __name__ == '__main__': |
| 425 main() | 426 main() |
| OLD | NEW |