| 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__)) |
| 18 |
| 17 class ScopedChangeDirectory(object): | 19 class ScopedChangeDirectory(object): |
| 18 """Changes current working directory and restores it back automatically.""" | 20 """Changes current working directory and restores it back automatically.""" |
| 19 | 21 |
| 20 def __init__(self, path): | 22 def __init__(self, path): |
| 21 self.path = path | 23 self.path = path |
| 22 self.old_path = '' | 24 self.old_path = '' |
| 23 | 25 |
| 24 def __enter__(self): | 26 def __enter__(self): |
| 25 self.old_path = os.getcwd() | 27 self.old_path = os.getcwd() |
| 26 os.chdir(self.path) | 28 os.chdir(self.path) |
| 27 return self | 29 return self |
| 28 | 30 |
| 29 def __exit__(self, exc_type, exc_value, traceback): | 31 def __exit__(self, exc_type, exc_value, traceback): |
| 30 os.chdir(self.old_path) | 32 os.chdir(self.old_path) |
| 31 | 33 |
| 32 | |
| 33 def get_script_absolute_path(): | |
| 34 return os.path.dirname(os.path.abspath(__file__)) | |
| 35 | |
| 36 | |
| 37 def get_package_build_dependencies(package): | 34 def get_package_build_dependencies(package): |
| 38 command = 'apt-get -s build-dep %s | grep Inst | cut -d " " -f 2' % package | 35 command = 'apt-get -s build-dep %s | grep Inst | cut -d " " -f 2' % package |
| 39 command_result = subprocess.Popen(command, stdout=subprocess.PIPE, | 36 command_result = subprocess.Popen(command, stdout=subprocess.PIPE, |
| 40 shell=True) | 37 shell=True) |
| 41 if command_result.wait(): | 38 if command_result.wait(): |
| 42 raise Exception('Failed to determine build dependencies for %s' % package) | 39 raise Exception('Failed to determine build dependencies for %s' % package) |
| 43 build_dependencies = [l.strip() for l in command_result.stdout] | 40 build_dependencies = [l.strip() for l in command_result.stdout] |
| 44 return build_dependencies | 41 return build_dependencies |
| 45 | 42 |
| 46 | 43 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 print stdout | 76 print stdout |
| 80 if child.returncode: | 77 if child.returncode: |
| 81 raise Exception('Failed to run: %s' % command) | 78 raise Exception('Failed to run: %s' % command) |
| 82 | 79 |
| 83 | 80 |
| 84 def run_shell_commands(commands, verbose=False, environment=None): | 81 def run_shell_commands(commands, verbose=False, environment=None): |
| 85 for command in commands: | 82 for command in commands: |
| 86 shell_call(command, verbose, environment) | 83 shell_call(command, verbose, environment) |
| 87 | 84 |
| 88 | 85 |
| 86 def fix_rpaths(destdir): |
| 87 # TODO(earthdok): reimplement fix_rpaths.sh in Python. |
| 88 shell_call("%s/fix_rpaths.sh %s/lib" % (SCRIPT_ABSOLUTE_PATH, destdir)) |
| 89 |
| 90 |
| 89 def destdir_configure_make_install(parsed_arguments, environment, | 91 def destdir_configure_make_install(parsed_arguments, environment, |
| 90 install_prefix): | 92 install_prefix): |
| 91 configure_command = './configure %s' % parsed_arguments.extra_configure_flags | 93 configure_command = './configure %s' % parsed_arguments.extra_configure_flags |
| 92 configure_command += ' --libdir=/lib/' | 94 configure_command += ' --libdir=/lib/' |
| 93 # Installing to a temporary directory allows us to safely clean up the .la | 95 # Installing to a temporary directory allows us to safely clean up the .la |
| 94 # files below. | 96 # files below. |
| 95 destdir = '%s/debian/instrumented_build' % os.getcwd() | 97 destdir = '%s/debian/instrumented_build' % os.getcwd() |
| 96 # Some makefiles use BUILDROOT instead of DESTDIR. | 98 # Some makefiles use BUILDROOT instead of DESTDIR. |
| 97 make_command = 'make DESTDIR=%s BUILDROOT=%s' % (destdir, destdir) | 99 make_command = 'make DESTDIR=%s BUILDROOT=%s' % (destdir, destdir) |
| 98 run_shell_commands([ | 100 build_and_install_in_destdir = [ |
| 99 configure_command, | 101 configure_command, |
| 100 '%s -j%s' % (make_command, parsed_arguments.jobs), | 102 '%s -j%s' % (make_command, parsed_arguments.jobs), |
| 101 # Parallel install is flaky for some packages. | 103 # Parallel install is flaky for some packages. |
| 102 '%s install -j1' % make_command, | 104 '%s install -j1' % make_command, |
| 103 # Kill the .la files. They contain absolute paths, and will cause build | 105 # Kill the .la files. They contain absolute paths, and will cause build |
| 104 # errors in dependent libraries. | 106 # errors in dependent libraries. |
| 105 'rm %s/lib/*.la -f' % destdir, | 107 'rm %s/lib/*.la -f' % destdir |
| 108 ] |
| 109 run_shell_commands(build_and_install_in_destdir, |
| 110 parsed_arguments.verbose, environment) |
| 111 fix_rpaths(destdir) |
| 112 shell_call( |
| 106 # Now move the contents of the temporary destdir to their final place. | 113 # Now move the contents of the temporary destdir to their final place. |
| 107 'cp %s/* %s/ -rdf' % (destdir, install_prefix)], | 114 'cp %s/* %s/ -rdf' % (destdir, install_prefix), |
| 108 parsed_arguments.verbose, environment) | 115 parsed_arguments.verbose, environment) |
| 109 | 116 |
| 110 | 117 |
| 111 def nss_make_and_copy(parsed_arguments, environment, install_prefix): | 118 def nss_make_and_copy(parsed_arguments, environment, install_prefix): |
| 112 # NSS uses a build system that's different from configure/make/install. All | 119 # NSS uses a build system that's different from configure/make/install. All |
| 113 # flags must be passed as arguments to make. | 120 # flags must be passed as arguments to make. |
| 114 make_args = [] | 121 make_args = [] |
| 115 # Do an optimized build. | 122 # Do an optimized build. |
| 116 make_args.append('BUILD_OPT=1') | 123 make_args.append('BUILD_OPT=1') |
| 117 # Set USE_64=1 on x86_64 systems. | 124 # Set USE_64=1 on x86_64 systems. |
| 118 if platform.architecture()[0] == '64bit': | 125 if platform.architecture()[0] == '64bit': |
| (...skipping 10 matching lines...) Expand all Loading... |
| 129 make_args.append('NSPR_INCLUDE_DIR=/usr/include/nspr') | 136 make_args.append('NSPR_INCLUDE_DIR=/usr/include/nspr') |
| 130 make_args.append('NSPR_LIB_DIR=%s/lib' % install_prefix) | 137 make_args.append('NSPR_LIB_DIR=%s/lib' % install_prefix) |
| 131 make_args.append('NSS_ENABLE_ECC=1') | 138 make_args.append('NSS_ENABLE_ECC=1') |
| 132 # Make sure we don't override the default flags. | 139 # Make sure we don't override the default flags. |
| 133 for variable in ['CFLAGS', 'CXXFLAGS', 'LDFLAGS']: | 140 for variable in ['CFLAGS', 'CXXFLAGS', 'LDFLAGS']: |
| 134 del environment[variable] | 141 del environment[variable] |
| 135 with ScopedChangeDirectory('nss') as cd_nss: | 142 with ScopedChangeDirectory('nss') as cd_nss: |
| 136 # -j is not supported | 143 # -j is not supported |
| 137 shell_call('make %s' % ' '.join(make_args), parsed_arguments.verbose, | 144 shell_call('make %s' % ' '.join(make_args), parsed_arguments.verbose, |
| 138 environment) | 145 environment) |
| 146 fix_rpaths(os.getcwd()) |
| 139 # 'make install' is not supported. Copy the DSOs manually. | 147 # 'make install' is not supported. Copy the DSOs manually. |
| 140 install_dir = '%s/lib/' % install_prefix | 148 install_dir = '%s/lib/' % install_prefix |
| 141 for (dirpath, dirnames, filenames) in os.walk('./lib/'): | 149 for (dirpath, dirnames, filenames) in os.walk('./lib/'): |
| 142 for filename in filenames: | 150 for filename in filenames: |
| 143 if filename.endswith('.so'): | 151 if filename.endswith('.so'): |
| 144 full_path = os.path.join(dirpath, filename) | 152 full_path = os.path.join(dirpath, filename) |
| 145 if parsed_arguments.verbose: | 153 if parsed_arguments.verbose: |
| 146 print 'download_build_install.py: installing %s' % full_path | 154 print 'download_build_install.py: installing %s' % full_path |
| 147 shutil.copy(full_path, install_dir) | 155 shutil.copy(full_path, install_dir) |
| 148 | 156 |
| 149 | 157 |
| 150 def libcap2_make_install(parsed_arguments, environment, install_prefix): | 158 def libcap2_make_install(parsed_arguments, environment, install_prefix): |
| 151 # libcap2 doesn't come with a configure script | 159 # libcap2 doesn't come with a configure script |
| 152 make_args = [ | 160 make_args = [ |
| 153 '%s="%s"' % (name, environment[name]) | 161 '%s="%s"' % (name, environment[name]) |
| 154 for name in['CC', 'CXX', 'CFLAGS', 'CXXFLAGS', 'LDFLAGS']] | 162 for name in['CC', 'CXX', 'CFLAGS', 'CXXFLAGS', 'LDFLAGS']] |
| 155 shell_call('make -j%s %s' % (parsed_arguments.jobs, ' '.join(make_args)), | 163 shell_call('make -j%s %s' % (parsed_arguments.jobs, ' '.join(make_args)), |
| 156 parsed_arguments.verbose, environment) | 164 parsed_arguments.verbose, environment) |
| 165 destdir = '%s/debian/instrumented_build' % os.getcwd() |
| 157 install_args = [ | 166 install_args = [ |
| 158 'DESTDIR=%s' % install_prefix, | 167 'DESTDIR=%s' % destdir, |
| 159 # Do not install in lib64/. | 168 # Do not install in lib64/. |
| 160 'lib=lib', | 169 'lib=lib', |
| 161 # Skip a step that requires sudo. | 170 # Skip a step that requires sudo. |
| 162 'RAISE_SETFCAP=no' | 171 'RAISE_SETFCAP=no' |
| 163 ] | 172 ] |
| 164 shell_call('make -j%s install %s' % | 173 shell_call('make -j%s install %s' % |
| 165 (parsed_arguments.jobs, ' '.join(install_args)), | 174 (parsed_arguments.jobs, ' '.join(install_args)), |
| 166 parsed_arguments.verbose, environment) | 175 parsed_arguments.verbose, environment) |
| 176 fix_rpaths(destdir) |
| 177 shell_call([ |
| 178 # Now move the contents of the temporary destdir to their final place. |
| 179 'cp %s/* %s/ -rdf' % (destdir, install_prefix)], |
| 180 parsed_arguments.verbose, environment) |
| 167 | 181 |
| 168 | 182 |
| 169 def libpci3_make_install(parsed_arguments, environment, install_prefix): | 183 def libpci3_make_install(parsed_arguments, environment, install_prefix): |
| 170 # pciutils doesn't have a configure script | 184 # pciutils doesn't have a configure script |
| 171 # This build script follows debian/rules. | 185 # This build script follows debian/rules. |
| 172 | 186 |
| 173 # Find out the package version. We'll use this when creating symlinks. | 187 # Find out the package version. We'll use this when creating symlinks. |
| 174 dir_name = os.path.split(os.getcwd())[-1] | 188 dir_name = os.path.split(os.getcwd())[-1] |
| 175 match = re.match('pciutils-(\d+\.\d+\.\d+)', dir_name) | 189 match = re.match('pciutils-(\d+\.\d+\.\d+)', dir_name) |
| 176 if match is None: | 190 if match is None: |
| (...skipping 19 matching lines...) Expand all Loading... |
| 196 'IDSDIR=/usr/share/misc', | 210 'IDSDIR=/usr/share/misc', |
| 197 ] | 211 ] |
| 198 install_args = ['DESTDIR=%s' % destdir] | 212 install_args = ['DESTDIR=%s' % destdir] |
| 199 run_shell_commands([ | 213 run_shell_commands([ |
| 200 'mkdir -p %s-udeb/usr/bin' % destdir, | 214 'mkdir -p %s-udeb/usr/bin' % destdir, |
| 201 'make -j%s %s' % (parsed_arguments.jobs, ' '.join(make_args + paths)), | 215 'make -j%s %s' % (parsed_arguments.jobs, ' '.join(make_args + paths)), |
| 202 'make -j%s %s install' % ( | 216 'make -j%s %s install' % ( |
| 203 parsed_arguments.jobs, | 217 parsed_arguments.jobs, |
| 204 ' '.join(install_args + paths))], | 218 ' '.join(install_args + paths))], |
| 205 parsed_arguments.verbose, environment) | 219 parsed_arguments.verbose, environment) |
| 220 fix_rpaths(destdir) |
| 206 # Now move the contents of the temporary destdir to their final place. | 221 # Now move the contents of the temporary destdir to their final place. |
| 207 run_shell_commands([ | 222 run_shell_commands([ |
| 208 'cp %s/* %s/ -rd' % (destdir, install_prefix), | 223 'cp %s/* %s/ -rd' % (destdir, install_prefix), |
| 209 'install -m 644 lib/libpci.so* %s/lib/' % install_prefix, | 224 'install -m 644 lib/libpci.so* %s/lib/' % install_prefix, |
| 210 'ln -sf libpci.so.%s %s/lib/libpci.so.3' % (version, install_prefix)], | 225 'ln -sf libpci.so.%s %s/lib/libpci.so.3' % (version, install_prefix)], |
| 211 parsed_arguments.verbose, environment) | 226 parsed_arguments.verbose, environment) |
| 212 | 227 |
| 213 | 228 |
| 214 def build_and_install(parsed_arguments, environment, install_prefix): | 229 def build_and_install(parsed_arguments, environment, install_prefix): |
| 215 if parsed_arguments.build_method == 'destdir': | 230 if parsed_arguments.build_method == 'destdir': |
| (...skipping 22 matching lines...) Expand all Loading... |
| 238 # The CC/CXX environment variables take precedence over the command line | 253 # The CC/CXX environment variables take precedence over the command line |
| 239 # flags. | 254 # flags. |
| 240 if 'CC' not in environment and parsed_arguments.cc: | 255 if 'CC' not in environment and parsed_arguments.cc: |
| 241 environment['CC'] = parsed_arguments.cc | 256 environment['CC'] = parsed_arguments.cc |
| 242 if 'CXX' not in environment and parsed_arguments.cxx: | 257 if 'CXX' not in environment and parsed_arguments.cxx: |
| 243 environment['CXX'] = parsed_arguments.cxx | 258 environment['CXX'] = parsed_arguments.cxx |
| 244 | 259 |
| 245 cflags = unescape_flags(parsed_arguments.cflags) | 260 cflags = unescape_flags(parsed_arguments.cflags) |
| 246 if parsed_arguments.sanitizer_blacklist: | 261 if parsed_arguments.sanitizer_blacklist: |
| 247 cflags += ' -fsanitize-blacklist=%s/%s' % ( | 262 cflags += ' -fsanitize-blacklist=%s/%s' % ( |
| 248 get_script_absolute_path(), | 263 SCRIPT_ABSOLUTE_PATH, |
| 249 parsed_arguments.sanitizer_blacklist) | 264 parsed_arguments.sanitizer_blacklist) |
| 250 environment['CFLAGS'] = cflags | 265 environment['CFLAGS'] = cflags |
| 251 environment['CXXFLAGS'] = cflags | 266 environment['CXXFLAGS'] = cflags |
| 252 | 267 |
| 253 ldflags = unescape_flags(parsed_arguments.ldflags) | 268 ldflags = unescape_flags(parsed_arguments.ldflags) |
| 254 # Make sure the linker searches the instrumented libraries dir for | 269 # Make sure the linker searches the instrumented libraries dir for |
| 255 # library dependencies. | 270 # library dependencies. |
| 256 environment['LDFLAGS'] = '%s -L%s/lib' % (ldflags, install_prefix) | 271 environment['LDFLAGS'] = '%s -L%s/lib' % (ldflags, install_prefix) |
| 257 | 272 |
| 258 if parsed_arguments.sanitizer_type == 'asan': | 273 if parsed_arguments.sanitizer_type == 'asan': |
| 259 # Do not report leaks during the build process. | 274 # Do not report leaks during the build process. |
| 260 environment['ASAN_OPTIONS'] = '%s:detect_leaks=0' % \ | 275 environment['ASAN_OPTIONS'] = '%s:detect_leaks=0' % \ |
| 261 environment.get('ASAN_OPTIONS', '') | 276 environment.get('ASAN_OPTIONS', '') |
| 262 | 277 |
| 263 # libappindicator1 needs this. | 278 # libappindicator1 needs this. |
| 264 environment['CSC'] = '/usr/bin/mono-csc' | 279 environment['CSC'] = '/usr/bin/mono-csc' |
| 265 return environment | 280 return environment |
| 266 | 281 |
| 267 | 282 |
| 268 | 283 |
| 269 def download_build_install(parsed_arguments): | 284 def download_build_install(parsed_arguments): |
| 270 product_directory = os.path.normpath('%s/%s' % ( | 285 product_directory = os.path.normpath('%s/%s' % ( |
| 271 get_script_absolute_path(), | 286 SCRIPT_ABSOLUTE_PATH, |
| 272 parsed_arguments.product_directory)) | 287 parsed_arguments.product_directory)) |
| 273 | 288 |
| 274 install_prefix = '%s/instrumented_libraries/%s' % ( | 289 install_prefix = '%s/instrumented_libraries/%s' % ( |
| 275 product_directory, | 290 product_directory, |
| 276 parsed_arguments.sanitizer_type) | 291 parsed_arguments.sanitizer_type) |
| 277 | 292 |
| 278 environment = build_environment(parsed_arguments, product_directory, | 293 environment = build_environment(parsed_arguments, product_directory, |
| 279 install_prefix) | 294 install_prefix) |
| 280 | 295 |
| 281 package_directory = '%s/%s' % (parsed_arguments.intermediate_directory, | 296 package_directory = '%s/%s' % (parsed_arguments.intermediate_directory, |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 argument_parser.add_argument('--run-before-build', default='') | 379 argument_parser.add_argument('--run-before-build', default='') |
| 365 argument_parser.add_argument('--build-method', default='destdir') | 380 argument_parser.add_argument('--build-method', default='destdir') |
| 366 argument_parser.add_argument('--sanitizer-blacklist', default='') | 381 argument_parser.add_argument('--sanitizer-blacklist', default='') |
| 367 | 382 |
| 368 # Ignore all empty arguments because in several cases gyp passes them to the | 383 # Ignore all empty arguments because in several cases gyp passes them to the |
| 369 # script, but ArgumentParser treats them as positional arguments instead of | 384 # script, but ArgumentParser treats them as positional arguments instead of |
| 370 # ignoring (and doesn't have such options). | 385 # ignoring (and doesn't have such options). |
| 371 parsed_arguments = argument_parser.parse_args( | 386 parsed_arguments = argument_parser.parse_args( |
| 372 [arg for arg in sys.argv[1:] if len(arg) != 0]) | 387 [arg for arg in sys.argv[1:] if len(arg) != 0]) |
| 373 # Ensure current working directory is this script directory. | 388 # Ensure current working directory is this script directory. |
| 374 os.chdir(get_script_absolute_path()) | 389 os.chdir(SCRIPT_ABSOLUTE_PATH) |
| 375 # Ensure all build dependencies are installed. | 390 # Ensure all build dependencies are installed. |
| 376 if parsed_arguments.check_build_deps: | 391 if parsed_arguments.check_build_deps: |
| 377 check_package_build_dependencies(parsed_arguments.package) | 392 check_package_build_dependencies(parsed_arguments.package) |
| 378 | 393 |
| 379 download_build_install(parsed_arguments) | 394 download_build_install(parsed_arguments) |
| 380 | 395 |
| 381 | 396 |
| 382 if __name__ == '__main__': | 397 if __name__ == '__main__': |
| 383 main() | 398 main() |
| OLD | NEW |