| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 """Tool for automatically creating .nmf files from .nexe/.pexe/.bc executables. | 6 """Tool for automatically creating .nmf files from .nexe/.pexe/.bc executables. |
| 7 | 7 |
| 8 As well as creating the nmf file this tool can also find and stage | 8 As well as creating the nmf file this tool can also find and stage |
| 9 any shared libraries dependencies that the executables might have. | 9 any shared libraries dependencies that the executables might have. |
| 10 """ | 10 """ |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 sys.path.append(LIB_DIR) | 29 sys.path.append(LIB_DIR) |
| 30 | 30 |
| 31 import elf | 31 import elf |
| 32 import get_shared_deps | 32 import get_shared_deps |
| 33 import quote | 33 import quote |
| 34 | 34 |
| 35 | 35 |
| 36 ARCH_LOCATION = { | 36 ARCH_LOCATION = { |
| 37 'x86-32': 'lib32', | 37 'x86-32': 'lib32', |
| 38 'x86-64': 'lib64', | 38 'x86-64': 'lib64', |
| 39 'arm': 'lib', | 39 'arm': 'libarm', |
| 40 } | 40 } |
| 41 | 41 |
| 42 | 42 |
| 43 # These constants are used within nmf files. | 43 # These constants are used within nmf files. |
| 44 RUNNABLE_LD = 'runnable-ld.so' # Name of the dynamic loader | |
| 45 MAIN_NEXE = 'main.nexe' # Name of entry point for execution | 44 MAIN_NEXE = 'main.nexe' # Name of entry point for execution |
| 46 PROGRAM_KEY = 'program' # Key of the program section in an nmf file | 45 PROGRAM_KEY = 'program' # Key of the program section in an nmf file |
| 47 URL_KEY = 'url' # Key of the url field for a particular file in an nmf file | 46 URL_KEY = 'url' # Key of the url field for a particular file in an nmf file |
| 48 FILES_KEY = 'files' # Key of the files section in an nmf file | 47 FILES_KEY = 'files' # Key of the files section in an nmf file |
| 49 PNACL_OPTLEVEL_KEY = 'optlevel' # key for PNaCl optimization level | 48 PNACL_OPTLEVEL_KEY = 'optlevel' # key for PNaCl optimization level |
| 50 PORTABLE_KEY = 'portable' # key for portable section of manifest | 49 PORTABLE_KEY = 'portable' # key for portable section of manifest |
| 51 TRANSLATE_KEY = 'pnacl-translate' # key for translatable objects | 50 TRANSLATE_KEY = 'pnacl-translate' # key for translatable objects |
| 52 TRANSLATE_DEBUG_KEY = 'pnacl-debug' # key for translatable debug objects | 51 TRANSLATE_DEBUG_KEY = 'pnacl-debug' # key for translatable debug objects |
| 53 | 52 |
| 54 | 53 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 return elf.ParseElfHeader(path) | 134 return elf.ParseElfHeader(path) |
| 136 except elf.Error, e: | 135 except elf.Error, e: |
| 137 raise Error(str(e)) | 136 raise Error(str(e)) |
| 138 | 137 |
| 139 | 138 |
| 140 class Error(Exception): | 139 class Error(Exception): |
| 141 """Local Error class for this file.""" | 140 """Local Error class for this file.""" |
| 142 pass | 141 pass |
| 143 | 142 |
| 144 | 143 |
| 144 def IsLoader(filename): |
| 145 return (filename.endswith(get_shared_deps.LOADER_X86) or |
| 146 filename.endswith(get_shared_deps.LOADER_ARM)) |
| 147 |
| 148 |
| 145 class ArchFile(object): | 149 class ArchFile(object): |
| 146 """Simple structure containing information about an architecture-specific | 150 """Simple structure containing information about an architecture-specific |
| 147 file. | 151 file. |
| 148 | 152 |
| 149 Attributes: | 153 Attributes: |
| 150 name: Name of this file | 154 name: Name of this file |
| 151 path: Full path to this file on the build system | 155 path: Full path to this file on the build system |
| 152 arch: Architecture of this file (e.g., x86-32) | 156 arch: Architecture of this file (e.g., x86-32) |
| 153 url: Relative path to file in the staged web directory. | 157 url: Relative path to file in the staged web directory. |
| 154 Used for specifying the "url" attribute in the nmf file.""" | 158 Used for specifying the "url" attribute in the nmf file.""" |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 # This file is already in the nmf_root tree, so it does not need to be | 292 # This file is already in the nmf_root tree, so it does not need to be |
| 289 # staged. Just make the URL relative to the .nmf. | 293 # staged. Just make the URL relative to the .nmf. |
| 290 url = PosixRelPath(arch_file.path, self.nmf_root) | 294 url = PosixRelPath(arch_file.path, self.nmf_root) |
| 291 else: | 295 else: |
| 292 # This file is outside of the nmf_root subtree, so it needs to be | 296 # This file is outside of the nmf_root subtree, so it needs to be |
| 293 # staged. Its path should be relative to the main .nexe with the same | 297 # staged. Its path should be relative to the main .nexe with the same |
| 294 # architecture. | 298 # architecture. |
| 295 prefix = arch_to_main_dir[arch_file.arch] | 299 prefix = arch_to_main_dir[arch_file.arch] |
| 296 url = os.path.basename(arch_file.path) | 300 url = os.path.basename(arch_file.path) |
| 297 | 301 |
| 298 if arch_file.name.endswith('.nexe'): | 302 if arch_file.name.endswith('.nexe') and not IsLoader(arch_file.name): |
| 299 prefix = posixpath.join(prefix, self.nexe_prefix) | 303 prefix = posixpath.join(prefix, self.nexe_prefix) |
| 300 elif self.no_arch_prefix: | 304 elif self.no_arch_prefix: |
| 301 prefix = posixpath.join(prefix, self.lib_prefix) | 305 prefix = posixpath.join(prefix, self.lib_prefix) |
| 302 else: | 306 else: |
| 303 prefix = posixpath.join( | 307 prefix = posixpath.join( |
| 304 prefix, self.lib_prefix, ARCH_LOCATION[arch_file.arch]) | 308 prefix, self.lib_prefix, ARCH_LOCATION[arch_file.arch]) |
| 305 arch_file.url = posixpath.join(prefix, url) | 309 arch_file.url = posixpath.join(prefix, url) |
| 306 | 310 |
| 307 def StageDependencies(self, destination_dir): | 311 def StageDependencies(self, destination_dir): |
| 308 """Copies over the dependencies into a given destination directory | 312 """Copies over the dependencies into a given destination directory |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 needed = self.GetNeeded() | 372 needed = self.GetNeeded() |
| 369 | 373 |
| 370 extra_files_kv = [(key, ArchFile(name=key, | 374 extra_files_kv = [(key, ArchFile(name=key, |
| 371 arch=arch, | 375 arch=arch, |
| 372 path=url, | 376 path=url, |
| 373 url=url)) | 377 url=url)) |
| 374 for key, arch, url in self.extra_files] | 378 for key, arch, url in self.extra_files] |
| 375 | 379 |
| 376 manifest_items = needed.items() + extra_files_kv | 380 manifest_items = needed.items() + extra_files_kv |
| 377 | 381 |
| 378 # Add in runnable-ld.so entries to the program section. | 382 # Add dynamic loader to the program section. |
| 379 for need, archinfo in manifest_items: | 383 for need, archinfo in manifest_items: |
| 380 urlinfo = { URL_KEY: archinfo.url } | 384 if IsLoader(need): |
| 381 if need.endswith(RUNNABLE_LD): | 385 urlinfo = { URL_KEY: archinfo.url } |
| 382 manifest[PROGRAM_KEY][archinfo.arch] = urlinfo | 386 manifest[PROGRAM_KEY][archinfo.arch] = urlinfo |
| 383 | 387 |
| 384 for need, archinfo in manifest_items: | 388 for need, archinfo in manifest_items: |
| 385 urlinfo = { URL_KEY: archinfo.url } | 389 urlinfo = { URL_KEY: archinfo.url } |
| 386 name = archinfo.name | 390 name = archinfo.name |
| 387 arch = archinfo.arch | 391 arch = archinfo.arch |
| 388 | 392 |
| 389 if need.endswith(RUNNABLE_LD): | 393 if IsLoader(need): |
| 390 continue | 394 continue |
| 391 | 395 |
| 392 if need in self.main_files: | 396 if need in self.main_files: |
| 393 if need.endswith(".nexe"): | 397 if need.endswith(".nexe"): |
| 394 # Place it under program if we aren't using the runnable-ld.so. | 398 # Place it under program if we aren't using the runnable-ld.so. |
| 395 program = manifest[PROGRAM_KEY] | 399 program = manifest[PROGRAM_KEY] |
| 396 if arch not in program: | 400 if arch not in program: |
| 397 program[arch] = urlinfo | 401 program[arch] = urlinfo |
| 398 continue | 402 continue |
| 399 # Otherwise, treat it like another another file named main.nexe. | 403 # Otherwise, treat it like another another file named main.nexe. |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 | 554 |
| 551 bionic_dir = 'toolchain/%s_arm_bionic' % osname | 555 bionic_dir = 'toolchain/%s_arm_bionic' % osname |
| 552 if os.path.isdir(os.path.join(sdk_root, bionic_dir)): | 556 if os.path.isdir(os.path.join(sdk_root, bionic_dir)): |
| 553 libpath += [ | 557 libpath += [ |
| 554 '%s/arm-nacl/lib' % bionic_dir, | 558 '%s/arm-nacl/lib' % bionic_dir, |
| 555 '%s/arm-nacl/usr/lib' % bionic_dir, | 559 '%s/arm-nacl/usr/lib' % bionic_dir, |
| 556 'lib/bionic_arm/%s' % config, | 560 'lib/bionic_arm/%s' % config, |
| 557 ] | 561 ] |
| 558 libpath = [os.path.normpath(p) for p in libpath] | 562 libpath = [os.path.normpath(p) for p in libpath] |
| 559 libpath = [os.path.join(sdk_root, p) for p in libpath] | 563 libpath = [os.path.join(sdk_root, p) for p in libpath] |
| 564 libpath.append(os.path.join(sdk_root, 'tools')) |
| 560 return libpath | 565 return libpath |
| 561 | 566 |
| 562 | 567 |
| 563 def main(args): | 568 def main(args): |
| 564 parser = argparse.ArgumentParser(description=__doc__) | 569 parser = argparse.ArgumentParser(description=__doc__) |
| 565 parser.add_argument('-o', '--output', dest='output', | 570 parser.add_argument('-o', '--output', dest='output', |
| 566 help='Write manifest file to FILE (default is stdout)', | 571 help='Write manifest file to FILE (default is stdout)', |
| 567 metavar='FILE') | 572 metavar='FILE') |
| 568 parser.add_argument('-D', '--objdump', dest='objdump', | 573 parser.add_argument('-D', '--objdump', dest='objdump', |
| 569 help='Override the default "objdump" tool used to find ' | 574 help='Override the default "objdump" tool used to find ' |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 if __name__ == '__main__': | 714 if __name__ == '__main__': |
| 710 try: | 715 try: |
| 711 rtn = main(sys.argv[1:]) | 716 rtn = main(sys.argv[1:]) |
| 712 except Error, e: | 717 except Error, e: |
| 713 sys.stderr.write('%s: %s\n' % (os.path.basename(__file__), e)) | 718 sys.stderr.write('%s: %s\n' % (os.path.basename(__file__), e)) |
| 714 rtn = 1 | 719 rtn = 1 |
| 715 except KeyboardInterrupt: | 720 except KeyboardInterrupt: |
| 716 sys.stderr.write('%s: interrupted\n' % os.path.basename(__file__)) | 721 sys.stderr.write('%s: interrupted\n' % os.path.basename(__file__)) |
| 717 rtn = 1 | 722 rtn = 1 |
| 718 sys.exit(rtn) | 723 sys.exit(rtn) |
| OLD | NEW |