15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch"""Tool for automatically creating .nmf files from .nexe/.pexe/.bc executables.
70f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
80f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)As well as creating the nmf file this tool can also find and stage
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)any shared libraries dependencies that the executables might have.
100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)"""
110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import errno
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import json
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import posixpath
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import shutil
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import getos
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)if sys.version_info < (2, 6, 0):
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sys.stderr.write("python 2.6 or later is required run this script\n")
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sys.exit(1)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)LIB_DIR = os.path.join(SCRIPT_DIR, 'lib')
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)sys.path.append(LIB_DIR)
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import elf
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import get_shared_deps
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import quote
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ARCH_LOCATION = {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'x86-32': 'lib32',
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'x86-64': 'lib64',
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'arm': 'lib',
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# These constants are used within nmf files.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RUNNABLE_LD = 'runnable-ld.so'  # Name of the dynamic loader
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MAIN_NEXE = 'main.nexe'  # Name of entry point for execution
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PROGRAM_KEY = 'program'  # Key of the program section in an nmf file
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URL_KEY = 'url'  # Key of the url field for a particular file in an nmf file
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILES_KEY = 'files'  # Key of the files section in an nmf file
49ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochPNACL_OPTLEVEL_KEY = 'optlevel' # key for PNaCl optimization level
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PORTABLE_KEY = 'portable' # key for portable section of manifest
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TRANSLATE_KEY = 'pnacl-translate' # key for translatable objects
52effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochTRANSLATE_DEBUG_KEY = 'pnacl-debug' # key for translatable debug objects
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def DebugPrint(message):
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if DebugPrint.debug_mode:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write('%s\n' % message)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DebugPrint.debug_mode = False  # Set to True to enable extra debug prints
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def SplitPath(path):
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Returns all components of a path as a list.
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  e.g.
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  'foo/bar/baz.blah' => ['foo', 'bar', 'baz.blah']
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  result = []
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while path:
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    path, part = os.path.split(path)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result.append(part)
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return result[::-1]  # Reverse.
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def MakePosixPath(path):
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Converts from the native format to posixpath format.
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  e.g. on Windows, "foo\\bar\\baz.blah" => "foo/bar/baz.blah"
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  on Mac/Linux this is a no-op.
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if os.path == posixpath:
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return path
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return posixpath.join(*SplitPath(path))
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def PosixRelPath(path, start):
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Takes two paths in native format, and produces a relative path in posix
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  format.
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  e.g.
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  For Windows: "foo\\bar\\baz.blah", "foo" => "bar/baz.blah"
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  For Mac/Linux: "foo/bar/baz.blah", "foo" => "bar/baz.blah"
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOTE: This function uses os.path.realpath to create a canonical path for
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  |path| and |start|.
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  real_path = os.path.realpath(path)
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  real_start = os.path.realpath(start)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return MakePosixPath(os.path.relpath(real_path, real_start))
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def DirectoryTreeContainsFile(dirname, filename):
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Returns True if a file is in a directory, or any of that directory's
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  subdirectories recursively.
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  e.g.
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DirectoryTreeContainsFile("foo", "foo/quux.txt") => True
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DirectoryTreeContainsFile("foo", "foo/bar/baz/blah.txt") => True
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DirectoryTreeContainsFile("foo", "bar/blah.txt") => False
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  real_dirname = os.path.realpath(dirname)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  real_filename = os.path.realpath(filename)
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return real_filename.startswith(real_dirname)
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MakeDir(dirname):
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Just like os.makedirs but doesn't generate errors when dirname
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  already exists.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if os.path.isdir(dirname):
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Trace("mkdir: %s" % dirname)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(dirname)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except OSError as exception_info:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if exception_info.errno != errno.EEXIST:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def ParseElfHeader(path):
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Wrap elf.ParseElfHeader to return raise this module's Error on failure."""
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  try:
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return elf.ParseElfHeader(path)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  except elf.Error, e:
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    raise Error(str(e))
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class Error(Exception):
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Local Error class for this file."""
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  pass
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ArchFile(object):
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Simple structure containing information about an architecture-specific
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)     file.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Attributes:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name: Name of this file
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path: Full path to this file on the build system
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arch: Architecture of this file (e.g., x86-32)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url: Relative path to file in the staged web directory.
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        Used for specifying the "url" attribute in the nmf file."""
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self, name, path, url=None, arch=None):
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = name
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.path = path
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.url = url
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.arch = arch
16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if not arch:
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self.arch = ParseElfHeader(path)[0]
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __repr__(self):
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return '<ArchFile %s>' % self.path
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Return the file path when invoked with the str() function"""
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.path
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NmfUtils(object):
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  """Helper class for creating and managing nmf files"""
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, main_files=None, objdump=None,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               lib_path=None, extra_files=None, lib_prefix=None,
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               nexe_prefix=None, no_arch_prefix=None, remap=None,
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch               pnacl_optlevel=None, pnacl_debug_optlevel=None,
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch               nmf_root=None):
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Constructor
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      main_files: List of main entry program files.  These will be named
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          files->main.nexe for dynamic nexes, and program for static nexes
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      objdump: path to x86_64-nacl-objdump tool (or Linux equivalent)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lib_path: List of paths to library directories
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extra_files: List of extra files to include in the nmf
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      lib_prefix: A path prefix to prepend to the library paths, both for
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          staging the libraries and for inclusion into the nmf file.
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          Example: '../lib_dir'
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      nexe_prefix: Like lib_prefix, but is prepended to the nexes instead.
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      no_arch_prefix: Don't prefix shared libraries by lib32/lib64.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      remap: Remaps the library name in the manifest.
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      pnacl_optlevel: Optimization level for PNaCl translation.
195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      pnacl_debug_optlevel: Optimization level for debug PNaCl translation.
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      nmf_root: Directory of the NMF. All urls are relative to this directory.
197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    """
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    assert len(main_files) > 0
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.objdump = objdump
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.main_files = main_files
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.extra_files = extra_files or []
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.lib_path = lib_path or []
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.manifest = None
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.needed = None
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.lib_prefix = lib_prefix or ''
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.nexe_prefix = nexe_prefix or ''
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.no_arch_prefix = no_arch_prefix
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.remap = remap or {}
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self.pnacl = main_files[0].endswith(('.pexe', '.bc'))
210ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    self.pnacl_optlevel = pnacl_optlevel
211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self.pnacl_debug_optlevel = pnacl_debug_optlevel
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if nmf_root is not None:
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.nmf_root = nmf_root
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    else:
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      # To match old behavior, if there is no nmf_root, use the directory of
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      # the first nexe found in main_files.
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.nmf_root = os.path.dirname(main_files[0])
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for filename in self.main_files:
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if not os.path.exists(filename):
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        raise Error('Input file not found: %s' % filename)
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if not os.path.isfile(filename):
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        raise Error('Input is not a file: %s' % filename)
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNeeded(self):
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Collect the list of dependencies for the main_files
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A dict with key=filename and value=ArchFile of input files.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Includes the input files as well, with arch filled in if absent.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Example: { '/path/to/my.nexe': ArchFile(my.nexe),
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     '/path/to/libfoo.so': ArchFile(libfoo.so) }"""
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.needed:
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self.needed
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DebugPrint('GetNeeded(%s)' % self.main_files)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if not self.objdump:
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.objdump = FindObjdumpExecutable()
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    try:
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      all_files = get_shared_deps.GetNeeded(self.main_files, self.objdump,
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                            self.lib_path)
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    except get_shared_deps.NoObjdumpError:
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      raise Error('No objdump executable found (see --help for more info)')
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    except get_shared_deps.Error, e:
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      raise Error(str(e))
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.needed = {}
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # all_files is a dictionary mapping filename to architecture. self.needed
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # should be a dictionary of filename to ArchFile.
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for filename, arch in all_files.iteritems():
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      name = os.path.basename(filename)
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.needed[filename] = ArchFile(name=name, path=filename, arch=arch)
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._SetArchFileUrls()
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.needed
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def _SetArchFileUrls(self):
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Fill in the url member of all ArchFiles in self.needed.
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    All urls are relative to the nmf_root. In addition, architecture-specific
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    files are relative to the .nexe with the matching architecture. This is
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    useful when making a multi-platform packaged app, so each architecture's
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    files are in a different directory.
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # self.GetNeeded() should have already been called.
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    assert self.needed is not None
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    main_nexes = [f for f in self.main_files if f.endswith('.nexe')]
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # map from each arch to its corresponding main nexe.
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    arch_to_main_dir = {}
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for main_file in main_nexes:
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      arch, _ = ParseElfHeader(main_file)
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      main_dir = os.path.dirname(main_file)
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      main_dir = PosixRelPath(main_dir, self.nmf_root)
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if main_dir == '.':
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        main_dir = ''
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      arch_to_main_dir[arch] = main_dir
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for arch_file in self.needed.itervalues():
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prefix = ''
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if DirectoryTreeContainsFile(self.nmf_root, arch_file.path):
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        # This file is already in the nmf_root tree, so it does not need to be
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        # staged. Just make the URL relative to the .nmf.
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        url = PosixRelPath(arch_file.path, self.nmf_root)
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      else:
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        # This file is outside of the nmf_root subtree, so it needs to be
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        # staged. Its path should be relative to the main .nexe with the same
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        # architecture.
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        prefix = arch_to_main_dir[arch_file.arch]
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        url = os.path.basename(arch_file.path)
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if arch_file.name.endswith('.nexe'):
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        prefix = posixpath.join(prefix, self.nexe_prefix)
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      elif self.no_arch_prefix:
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        prefix = posixpath.join(prefix, self.lib_prefix)
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      else:
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        prefix = posixpath.join(
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            prefix, self.lib_prefix, ARCH_LOCATION[arch_file.arch])
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      arch_file.url = posixpath.join(prefix, url)
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def StageDependencies(self, destination_dir):
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Copies over the dependencies into a given destination directory
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Each library will be put into a subdirectory that corresponds to the arch.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      destination_dir: The destination directory for staging the dependencies
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    assert self.needed is not None
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for arch_file in self.needed.itervalues():
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      source = arch_file.path
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      destination = os.path.join(destination_dir, arch_file.url)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (os.path.normcase(os.path.realpath(source)) ==
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          os.path.normcase(os.path.realpath(destination))):
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # make sure target dir exists
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MakeDir(os.path.dirname(destination))
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Trace('copy: %s -> %s' % (source, destination))
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      shutil.copy2(source, destination)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GeneratePNaClManifest(self):
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    manifest = {}
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    manifest[PROGRAM_KEY] = {}
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    manifest[PROGRAM_KEY][PORTABLE_KEY] = {}
334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    portable = manifest[PROGRAM_KEY][PORTABLE_KEY]
335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for filename in self.main_files:
336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      translate_dict =  {
337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          'url': os.path.basename(filename),
338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if filename.endswith('.pexe'):
340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if self.pnacl_optlevel is not None:
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          translate_dict[PNACL_OPTLEVEL_KEY] = self.pnacl_optlevel
342effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if TRANSLATE_KEY in portable:
343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          raise Error('Multiple .pexe files')
344effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        portable[TRANSLATE_KEY] = translate_dict
345effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      elif filename.endswith('.bc'):
346effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if self.pnacl_debug_optlevel is not None:
347effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          translate_dict[PNACL_OPTLEVEL_KEY] = self.pnacl_debug_optlevel
348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if TRANSLATE_DEBUG_KEY in portable:
349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          raise Error('Multiple .bc files')
350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        portable[TRANSLATE_DEBUG_KEY] = translate_dict
351effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      else:
352effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        raise Error('Unexpected executable type: %s' % filename)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.manifest = manifest
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GenerateManifest(self):
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Create a JSON formatted dict containing the files
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NaCl will map url requests based on architecture.  The startup NEXE
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    can always be found under the top key PROGRAM.  Additional files are under
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the FILES key further mapped by file name.  In the case of 'runnable' the
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PROGRAM key is populated with urls pointing the runnable-ld.so which acts
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    as the startup nexe.  The application itself is then placed under the
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FILES key mapped as 'main.exe' instead of the original name so that the
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    loader can find it.
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    manifest = { FILES_KEY: {}, PROGRAM_KEY: {} }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    needed = self.GetNeeded()
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    runnable = any(n.endswith(RUNNABLE_LD) for n in needed)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extra_files_kv = [(key, ArchFile(name=key,
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     arch=arch,
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     path=url,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     url=url))
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      for key, arch, url in self.extra_files]
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for need, archinfo in needed.items() + extra_files_kv:
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      urlinfo = { URL_KEY: archinfo.url }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = archinfo.name
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If starting with runnable-ld.so, make that the main executable.
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if runnable:
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if need.endswith(RUNNABLE_LD):
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          manifest[PROGRAM_KEY][archinfo.arch] = urlinfo
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if need in self.main_files:
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if need.endswith(".nexe"):
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          # Place it under program if we aren't using the runnable-ld.so.
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if not runnable:
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            manifest[PROGRAM_KEY][archinfo.arch] = urlinfo
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            continue
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          # Otherwise, treat it like another another file named main.nexe.
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          name = MAIN_NEXE
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name = self.remap.get(name, name)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fileinfo = manifest[FILES_KEY].get(name, {})
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fileinfo[archinfo.arch] = urlinfo
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      manifest[FILES_KEY][name] = fileinfo
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.manifest = manifest
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetManifest(self):
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Returns a JSON-formatted dict containing the NaCl dependencies"""
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.manifest:
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self.pnacl:
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._GeneratePNaClManifest()
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._GenerateManifest()
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.manifest
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetJson(self):
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Returns the Manifest as a JSON-formatted string"""
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pretty_string = json.dumps(self.GetManifest(), indent=2)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # json.dumps sometimes returns trailing whitespace and does not put
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # a newline at the end.  This code fixes these problems.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pretty_lines = pretty_string.split('\n')
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join([line.rstrip() for line in pretty_lines]) + '\n'
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Trace(msg):
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if Trace.verbose:
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stderr.write(str(msg) + '\n')
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Trace.verbose = False
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def ParseExtraFiles(encoded_list, err):
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Parse the extra-files list and return a canonicalized list of
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [key, arch, url] triples.  The |encoded_list| should be a list of
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  strings of the form 'key:url' or 'key:arch:url', where an omitted
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  'arch' is taken to mean 'portable'.
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  All entries in |encoded_list| are checked for syntax errors before
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  returning.  Error messages are written to |err| (typically
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sys.stderr) so that the user has actionable feedback for fixing all
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  errors, rather than one at a time.  If there are any errors, None is
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  returned instead of a list, since an empty list is a valid return
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  value.
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  seen_error = False
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  canonicalized = []
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for ix in range(len(encoded_list)):
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    kv = encoded_list[ix]
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unquoted = quote.unquote(kv, ':')
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if len(unquoted) == 3:
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if unquoted[1] != ':':
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        err.write('Syntax error for key:value tuple ' +
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  'for --extra-files argument: ' + kv + '\n')
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        seen_error = True
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        canonicalized.append([unquoted[0], 'portable', unquoted[2]])
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif len(unquoted) == 5:
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if unquoted[1] != ':' or unquoted[3] != ':':
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        err.write('Syntax error for key:arch:url tuple ' +
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  'for --extra-files argument: ' +
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  kv + '\n')
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        seen_error = True
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        canonicalized.append([unquoted[0], unquoted[2], unquoted[4]])
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      err.write('Bad key:arch:url tuple for --extra-files: ' + kv + '\n')
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if seen_error:
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return None
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return canonicalized
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetSDKRoot():
46990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Determine current NACL_SDK_ROOT, either via the environment variable
47090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  itself, or by attempting to derive it from the location of this script.
47190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """
47290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  sdk_root = os.environ.get('NACL_SDK_ROOT')
47390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not sdk_root:
47490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    sdk_root = os.path.dirname(SCRIPT_DIR)
47590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if not os.path.exists(os.path.join(sdk_root, 'toolchain')):
47690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return None
47790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
47890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return sdk_root
47990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def FindObjdumpExecutable():
48290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Derive path to objdump executable to use for determining shared
48390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  object dependencies.
48490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """
48590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  sdk_root = GetSDKRoot()
48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not sdk_root:
48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return None
48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  osname = getos.GetPlatform()
49090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  toolchain = os.path.join(sdk_root, 'toolchain', '%s_x86_glibc' % osname)
49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  objdump = os.path.join(toolchain, 'bin', 'x86_64-nacl-objdump')
49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if osname == 'win':
49390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    objdump += '.exe'
49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not os.path.exists(objdump):
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    sys.stderr.write('WARNING: failed to find objdump in default '
49790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     'location: %s' % objdump)
49890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return None
49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return objdump
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)def GetDefaultLibPath(config):
50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """Derive default library path to use when searching for shared
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  objects.  This currently include the toolchain library folders
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  as well as the top level SDK lib folder and the naclports lib
50790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  folder.  We include both 32-bit and 64-bit library paths.
50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  """
50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  assert(config in ('Debug', 'Release'))
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  sdk_root = GetSDKRoot()
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not sdk_root:
51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # TOOD(sbc): output a warning here?  We would also need to suppress
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # the warning when run from the chromium build.
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return []
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  osname = getos.GetPlatform()
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  libpath = [
518868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    # Core toolchain libraries
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    'toolchain/%s_x86_glibc/x86_64-nacl/lib' % osname,
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    'toolchain/%s_x86_glibc/x86_64-nacl/lib32' % osname,
521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    # naclports installed libraries
522868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    'toolchain/%s_x86_glibc/x86_64-nacl/usr/lib' % osname,
523868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    'toolchain/%s_x86_glibc/i686-nacl/usr/lib' % osname,
524868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    # SDK bundle libraries
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    'lib/glibc_x86_32/%s' % config,
52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    'lib/glibc_x86_64/%s' % config,
527868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    # naclports bundle libraries
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    'ports/lib/glibc_x86_32/%s' % config,
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    'ports/lib/glibc_x86_64/%s' % config,
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ]
531c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
532c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bionic_dir = 'toolchain/%s_arm_bionic' % osname
533c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if os.path.isdir(os.path.join(sdk_root, bionic_dir)):
534c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    libpath += [
535c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      '%s/arm-nacl/lib' % bionic_dir,
536c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      '%s/arm-nacl/usr/lib' % bionic_dir,
537c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      'lib/bionic_arm/%s' % config,
538c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ]
53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  libpath = [os.path.normpath(p) for p in libpath]
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  libpath = [os.path.join(sdk_root, p) for p in libpath]
54190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return libpath
54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def main(argv):
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = optparse.OptionParser(
5460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      usage='Usage: %prog [options] nexe [extra_libs...]', description=__doc__)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-o', '--output', dest='output',
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Write manifest file to FILE (default is stdout)',
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='FILE')
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-D', '--objdump', dest='objdump',
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    help='Override the default "objdump" tool used to find '
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         'shared object dependencies',
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='TOOL')
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  parser.add_option('--no-default-libpath', action='store_true',
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    help="Don't include the SDK default library paths")
55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  parser.add_option('--debug-libs', action='store_true',
55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                    help='Use debug library paths when constructing default '
55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                         'library path.')
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-L', '--library-path', dest='lib_path',
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    action='append', default=[],
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Add DIRECTORY to library search path',
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='DIRECTORY')
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-P', '--path-prefix', dest='path_prefix', default='',
564a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    help='Deprecated. An alias for --lib-prefix.',
565a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    metavar='DIRECTORY')
566a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  parser.add_option('-p', '--lib-prefix', dest='lib_prefix', default='',
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='A path to prepend to shared libraries in the .nmf',
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='DIRECTORY')
569a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  parser.add_option('-N', '--nexe-prefix', dest='nexe_prefix', default='',
570a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    help='A path to prepend to nexes in the .nmf',
571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    metavar='DIRECTORY')
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-s', '--stage-dependencies', dest='stage_dependencies',
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Destination directory for staging libraries',
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    metavar='DIRECTORY')
575a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  parser.add_option('--no-arch-prefix', action='store_true',
576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    help='Don\'t put shared libraries in the lib32/lib64 '
577a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    'directories. Instead, they will be put in the same '
578a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    'directory as the .nexe that matches its architecture.')
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option('-t', '--toolchain', help='Legacy option, do not use')
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-n', '--name', dest='name',
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Rename FOO as BAR',
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    action='append', default=[], metavar='FOO,BAR')
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  parser.add_option('-x', '--extra-files',
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    help=('Add extra key:file tuple to the "files"' +
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          ' section of the .nmf'),
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    action='append', default=[], metavar='FILE')
587ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  parser.add_option('-O', '--pnacl-optlevel',
588ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                    help='Set the optimization level to N in PNaCl manifests',
589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                    metavar='N')
590effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  parser.add_option('--pnacl-debug-optlevel',
591effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    help='Set the optimization level to N for debugging '
592effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         'sections in PNaCl manifests',
593effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    metavar='N')
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-v', '--verbose',
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Verbose output', action='store_true')
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser.add_option('-d', '--debug-mode',
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help='Debug mode', action='store_true')
5980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
5990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  # To enable bash completion for this command first install optcomplete
6000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  # and then add this line to your .bashrc:
6010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  #  complete -F _optcomplete create_nmf.py
6020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  try:
6030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    import optcomplete
6040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    optcomplete.autocomplete(parser)
6050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  except ImportError:
6060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    pass
6070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  options, args = parser.parse_args(argv)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.verbose:
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Trace.verbose = True
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.debug_mode:
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DebugPrint.debug_mode = True
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if options.toolchain is not None:
615868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    sys.stderr.write('warning: option -t/--toolchain is deprecated.\n')
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if len(args) < 1:
618868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    parser.error('No nexe files specified.  See --help for more info')
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  canonicalized = ParseExtraFiles(options.extra_files, sys.stderr)
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if canonicalized is None:
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    parser.error('Bad --extra-files (-x) argument syntax')
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remap = {}
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ren in options.name:
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts = ren.split(',')
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(parts) != 2:
628868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      parser.error('Expecting --name=<orig_arch.so>,<new_name.so>')
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remap[parts[0]] = parts[1]
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.path_prefix:
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    options.lib_prefix = options.path_prefix
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
63490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for libpath in options.lib_path:
63590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if not os.path.exists(libpath):
636868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sys.stderr.write('Specified library path does not exist: %s\n' % libpath)
637868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    elif not os.path.isdir(libpath):
638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      sys.stderr.write('Specified library is not a directory: %s\n' % libpath)
63990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
64090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not options.no_default_libpath:
64190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # Add default libraries paths to the end of the search path.
64290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    config = options.debug_libs and 'Debug' or 'Release'
64390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    options.lib_path += GetDefaultLibPath(config)
644c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    for path in options.lib_path:
645c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      Trace('libpath: %s' % path)
64690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
647ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pnacl_optlevel = None
648ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if options.pnacl_optlevel is not None:
649ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    pnacl_optlevel = int(options.pnacl_optlevel)
650ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if pnacl_optlevel < 0 or pnacl_optlevel > 3:
651ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      sys.stderr.write(
652ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          'warning: PNaCl optlevel %d is unsupported (< 0 or > 3)\n' %
653ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          pnacl_optlevel)
654effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if options.pnacl_debug_optlevel is not None:
655effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    pnacl_debug_optlevel = int(options.pnacl_debug_optlevel)
656effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else:
657effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    pnacl_debug_optlevel = pnacl_optlevel
658ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
659a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  nmf_root = None
660a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if options.output:
661a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    nmf_root = os.path.dirname(options.output)
662a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nmf = NmfUtils(objdump=options.objdump,
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 main_files=args,
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 lib_path=options.lib_path,
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 extra_files=canonicalized,
667a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 lib_prefix=options.lib_prefix,
668a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 nexe_prefix=options.nexe_prefix,
669a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 no_arch_prefix=options.no_arch_prefix,
670ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 remap=remap,
671a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 pnacl_optlevel=pnacl_optlevel,
672effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 pnacl_debug_optlevel=pnacl_debug_optlevel,
673a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 nmf_root=nmf_root)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
67590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if not options.output:
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.stdout.write(nmf.GetJson())
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with open(options.output, 'w') as output:
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output.write(nmf.GetJson())
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if options.stage_dependencies and not nmf.pnacl:
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Trace('Staging dependencies...')
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nmf.StageDependencies(options.stage_dependencies)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    rtn = main(sys.argv[1:])
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except Error, e:
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sys.stderr.write('%s: %s\n' % (os.path.basename(__file__), e))
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rtn = 1
69490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  except KeyboardInterrupt:
69590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    sys.stderr.write('%s: interrupted\n' % os.path.basename(__file__))
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    rtn = 1
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(rtn)
698