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 |