Remove ndk-depends.

Judging by the lack of interest on the web, it seems like this probably
isn't much used. ReLinker (https://github.com/KeepSafe/ReLinker) seems
like a better solution to native library loading problems anyway. Rather
than rewrite ndk-depends in Python now, let's see if anyone actually
still has a reasonable use for it.

(Folks who just want readelf/llvm-readobj should probably just be using
those already.)

Bug: http://b/22085867
Test: builds
Change-Id: I938ddd55586c4ff8768bc7b5e0b356f1c31abed1
diff --git a/README.md b/README.md
index 136c4ca..74c94b8 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@
       when this toolchain is used.
 * `prebuilt/$HOST_TAG` contains build dependencies and additional tools.
     * make, python, yasm, and for Windows: cmp.exe and echo.exe
-    * `ndk-depends`, `ndk-stack` and `ndk-gdb` can also be found here.
+    * `ndk-stack` and `ndk-gdb` can also be found here.
 
 ### Target Prebuilts
 
diff --git a/checkbuild.py b/checkbuild.py
index 2ebdc4f..49206c7 100755
--- a/checkbuild.py
+++ b/checkbuild.py
@@ -735,18 +735,6 @@
     shutil.copy2(src, dst)
 
 
-class NdkDepends(ndk.builds.InvokeExternalBuildModule):
-    name = 'ndk-depends'
-    path = 'prebuilt/{host}/bin'
-    script = 'ndk/sources/host-tools/ndk-depends/build.py'
-    notice = ndk.paths.ndk_path('sources/host-tools/ndk-depends/NOTICE')
-
-    def install(self):
-        src = os.path.join(self.out_dir, self.host, self.name)
-        install_dir = self.get_install_path()
-        install_exe(src, install_dir, self.name, self.host)
-
-
 class GdbServer(ndk.builds.InvokeBuildModule):
     name = 'gdbserver'
     path = 'prebuilt/android-{arch}/gdbserver'
@@ -2002,13 +1990,6 @@
     windows_ext = ''  # There isn't really a Windows ndk-which.
 
 
-class NdkDependsShortcut(ndk.builds.ScriptShortcutModule):
-    name = 'ndk-depends-shortcut'
-    path = 'ndk-depends'
-    script = 'prebuilt/{host}/bin/ndk-depends'
-    windows_ext = '.exe'
-
-
 class NdkStackShortcut(ndk.builds.ScriptShortcutModule):
     name = 'ndk-stack-shortcut'
     path = 'ndk-stack'
@@ -2309,8 +2290,6 @@
     NativeAppGlue(),
     NdkBuild(),
     NdkBuildShortcut(),
-    NdkDepends(),
-    NdkDependsShortcut(),
     NdkGdb(),
     NdkGdbShortcut(),
     NdkHelper(),
diff --git a/docs/changelogs/Changelog-r19.md b/docs/changelogs/Changelog-r19.md
index 31db229..d9556b1 100644
--- a/docs/changelogs/Changelog-r19.md
+++ b/docs/changelogs/Changelog-r19.md
@@ -41,8 +41,12 @@
    Android-specific code. For more information, see the [Build System
    Maintainers] guide.
 
+ * ndk-depends has been removed. We believe that [ReLinker] is a better
+   solution to native library loading issues on old Android versions.
+
 [Build System Maintainers]: https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md
 [Issue 780]: https://github.com/android-ndk/ndk/issues/780
+[ReLinker]: https://github.com/KeepSafe/ReLinker
 
 Changes
 -------
diff --git a/sources/host-tools/ndk-depends/GNUmakefile b/sources/host-tools/ndk-depends/GNUmakefile
deleted file mode 100644
index 49102a9..0000000
--- a/sources/host-tools/ndk-depends/GNUmakefile
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# The following variables can be over-ridden by the caller
-CC        := gcc
-CXX       := g++
-STRIP     := strip
-BUILD_DIR := /tmp/ndk-$(USER)/build/build-ndk-depends
-PROGNAME  := /tmp/ndk-$(USER)/ndk-depends
-
-EXECUTABLE := $(PROGNAME)
-
-all: $(EXECUTABLE)
-
-# The rest should be left alone
-EXTRA_CFLAGS := -Wall -Werror -fno-exceptions -fno-rtti
-EXTRA_LDFLAGS := -lstdc++
-
-ifneq (,$(strip $(DEBUG)))
-  CFLAGS += -O0 -g
-  hide = @
-  strip-cmd =
-else
-  CFLAGS += -O2 -s
-  hide =
-  strip-cmd = $(STRIP) $1
-endif
-
-SOURCES := ndk-depends.cc
-
-OBJECTS=
-
-define build-c-object
-OBJECTS += $1
-$1: $2
-	mkdir -p $$(dir $1)
-	$$(CC) $$(CFLAGS) $$(EXTRA_CFLAGS) -c -o $1 $2
-endef
-
-define build-cxx-object
-OBJECTS += $1
-$1: $2
-	mkdir -p $$(dir $1)
-	$$(CXX) $$(CFLAGS) $$(EXTRA_CFLAGS) -c -o $1 $2
-endef
-
-$(foreach src,$(filter %.c,$(SOURCES)),\
-    $(eval $(call build-c-object,$(BUILD_DIR)/$(src:%.c=%.o),$(src)))\
-)
-
-$(foreach src,$(filter %.cc,$(SOURCES)),\
-    $(eval $(call build-cxx-object,$(BUILD_DIR)/$(src:%.cc=%.o),$(src)))\
-)
-
-clean:
-	rm -f $(EXECUTABLE)
-
-$(EXECUTABLE): $(OBJECTS)
-	$(CXX) $(LDFLAGS) $(OBJECTS) -o $@ $(EXTRA_LDFLAGS)
-	$(call strip-cmd,$@)
diff --git a/sources/host-tools/ndk-depends/NOTICE b/sources/host-tools/ndk-depends/NOTICE
deleted file mode 100644
index d6c0922..0000000
--- a/sources/host-tools/ndk-depends/NOTICE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright (C) 2016 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/sources/host-tools/ndk-depends/build-ndk-depends.sh b/sources/host-tools/ndk-depends/build-ndk-depends.sh
deleted file mode 100755
index 31c992d..0000000
--- a/sources/host-tools/ndk-depends/build-ndk-depends.sh
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/bin/sh
-#
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# This script is used to rebuild the host 'ndk-depends' tool.
-#
-# Note: The tool is installed under prebuilt/$HOST_TAG/bin/ndk-depends
-#       by default.
-#
-PROGDIR=$(dirname $0)
-. $NDK_BUILDTOOLS_PATH/prebuilt-common.sh
-
-PROGRAM_PARAMETERS=""
-PROGRAM_DESCRIPTION=\
-"This script is used to rebuild the host ndk-depends binary program."
-
-register_jobs_option
-
-BUILD_DIR=
-register_var_option "--build-dir=<path>" BUILD_DIR "Specify build directory"
-
-NDK_DIR=$ANDROID_NDK_ROOT
-register_var_option "--ndk-dir=<path>" NDK_DIR "Place binary in NDK installation path"
-
-GNUMAKE=
-register_var_option "--make=<path>" GNUMAKE "Specify GNU Make program"
-
-DEBUG=
-register_var_option "--debug" DEBUG "Build debug version"
-
-SRC_DIR=
-register_var_option "--src-dir=<path>" SRC_DIR "Specify binutils source dir.  Must be set for --with-libbfd"
-
-PACKAGE_DIR=
-register_var_option "--package-dir=<path>" PACKAGE_DIR "Archive binary into specific directory"
-
-register_canadian_option
-register_try64_option
-
-extract_parameters "$@"
-
-prepare_abi_configure_build
-prepare_host_build
-
-rm -rf $BUILD_DIR
-mkdir -p $BUILD_DIR
-
-prepare_canadian_toolchain $BUILD_DIR
-
-CFLAGS=$HOST_CFLAGS" -O2 -s -ffunction-sections -fdata-sections"
-LDFLAGS=$HOST_LDFLAGS
-EXTRA_CONFIG=
-
-if [ "$HOST_OS" != "darwin" -a "$DARWIN" != "yes" ]; then
-    LDFLAGS=$LDFLAGS" -Wl,-gc-sections"
-else
-    # In darwin libbfd has to be built with some *linux* target or it won't understand ELF
-    EXTRA_CONFIG="-target=arm-linux-androideabi"
-fi
-
-if [ "$MINGW" = "yes" ]; then
-    LDFLAGS=$LDFLAGS" -static"
-fi
-
-NAME=$(get_host_exec_name ndk-depends)
-INSTALL_SUBDIR=host-tools/bin
-OUT=$BUILD_DIR/$NAME
-
-# GNU Make
-if [ -z "$GNUMAKE" ]; then
-    GNUMAKE=make
-    log "Auto-config: --make=$GNUMAKE"
-fi
-
-if [ "$PACKAGE_DIR" ]; then
-    mkdir -p "$PACKAGE_DIR"
-    fail_panic "Could not create package directory: $PACKAGE_DIR"
-fi
-
-# Create output directory
-mkdir -p $(dirname $OUT)
-if [ $? != 0 ]; then
-    echo "ERROR: Could not create output directory: $(dirname $OUT)"
-    exit 1
-fi
-
-SRCDIR=$ANDROID_NDK_ROOT/sources/host-tools/ndk-depends
-
-export CFLAGS LDFLAGS
-run $GNUMAKE -C $SRCDIR -f $SRCDIR/GNUmakefile \
-    -B -j$NUM_JOBS \
-    PROGNAME="$OUT" \
-    BUILD_DIR="$BUILD_DIR" \
-    CC="$CC" CXX="$CXX" \
-    STRIP="$STRIP" \
-    DEBUG=$DEBUG
-
-if [ $? != 0 ]; then
-    echo "ERROR: Could not build host program!"
-    exit 1
-fi
-
-log "Done!"
-exit 0
diff --git a/sources/host-tools/ndk-depends/build.py b/sources/host-tools/ndk-depends/build.py
deleted file mode 100755
index 65dc547..0000000
--- a/sources/host-tools/ndk-depends/build.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""Builds ndk-depends."""
-from __future__ import print_function
-
-import os
-import site
-
-site.addsitedir(os.path.join(os.path.dirname(__file__), '../../../build/lib'))
-
-import build_support  # pylint: disable=import-error
-
-
-def main(args):
-    src_dir_arg = '--src-dir={}'.format(build_support.toolchain_path())
-
-    build_cmd = [
-        'bash', 'build-ndk-depends.sh', src_dir_arg,
-    ]
-
-    if args.host in ('windows', 'windows64'):
-        build_cmd.append('--mingw')
-
-    if args.host != 'windows':
-        build_cmd.append('--try-64')
-
-    build_cmd.append(
-        '--build-dir=' + os.path.join(args.out_dir, 'ndk-depends'))
-
-    build_support.build(build_cmd, args)
-
-if __name__ == '__main__':
-    build_support.run(main)
diff --git a/sources/host-tools/ndk-depends/ndk-depends.cc b/sources/host-tools/ndk-depends/ndk-depends.cc
deleted file mode 100644
index 803b4a2..0000000
--- a/sources/host-tools/ndk-depends/ndk-depends.cc
+++ /dev/null
@@ -1,1465 +0,0 @@
-//
-// Copyright (C) 2013 The Android Open Source Project
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//  * Redistributions of source code must retain the above copyright
-//    notice, this list of conditions and the following disclaimer.
-//  * Redistributions in binary form must reproduce the above copyright
-//    notice, this list of conditions and the following disclaimer in
-//    the documentation and/or other materials provided with the
-//    distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-// SUCH DAMAGE.
-//
-
-// A small portable program used to dump the dynamic dependencies of a
-// shared library. Requirements:
-//   - Must support both 32-bit and 64-bit ELF binaries.
-//   - Must support both little and big endian binaries.
-//   - Must be compiled as a Unicode program on Windows.
-//   - Follows Chromium coding-style guide.
-//   - Single source file to make it easier to build anywhere.
-
-//
-// Work-around Windows Unicode support.
-//
-
-// Enable Windows Unicode support by default. Override this by
-// setting WINDOWS_UNICODE at build time.
-#if !defined(WINDOWS_UNICODE) && defined(_WIN32)
-#define WINDOWS_UNICODE 1
-#endif
-
-#ifdef _WIN32
-#undef UNICODE
-#undef _UNICODE
-#ifdef WINDOWS_UNICODE
-#define UNICODE 1
-#define _UNICODE 1
-#endif
-#include <windows.h>
-#include <tchar.h>
-#else
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#endif
-
-#include <string>
-
-// Define String as a typedef for either std::string or std::wstring
-// depending on the platform.
-#if WINDOWS_UNICODE
-typedef std::wstring String;
-#else
-typedef std::string String;
-#endif
-
-// Use the following functions instead of their standard library equivalent.
-#if !WINDOWS_UNICODE
-#define TCHAR char
-#define _T(x) x
-#define _tgetenv   getenv
-#define _tcslen    strlen
-#define _tcschr    strchr
-#define _tcscmp    strcmp
-#define _tcsncmp   strncmp
-#define _tfopen    fopen
-#define _tprintf   printf
-#define _vftprintf vfprintf
-#define _ftprintf  fprintf
-#define _tstat     stat
-#define _vtprintf  vprintf
-#define _stat      stat
-#endif
-
-// Use TO_STRING(xxx) to convert a C-string into the equivalent String.
-#if WINDOWS_UNICODE == 1
-static inline std::wstring __s2ws(const std::string& s) {
-    int s_len = static_cast<int>(s.length() + 1);
-    int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), s_len, 0, 0);
-    std::wstring result(len, L'\0');
-    MultiByteToWideChar(CP_ACP, 0, s.c_str(), s_len, &result[0], len);
-    return result;
-}
-#define TO_STRING(x) __s2ws(x)
-#else
-#define TO_STRING(x)  (x)
-#endif
-
-// Use TO_CONST_TCHAR(xxx) to convert a const char* to a const char/wchar*
-#if WINDOWS_UNICODE == 1
-#define TO_CONST_TCHAR(x) TO_STRING(x).c_str()
-#else
-#define TO_CONST_TCHAR(x)  (x)
-#endif
-
-
-//
-// Start the real program now
-//
-
-#include <errno.h>
-#ifdef __linux__
-#include <glob.h>
-#endif
-#include <limits.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include <algorithm>
-#include <list>
-#include <map>
-#include <string>
-#include <vector>
-
-namespace {
-
-// Utility functions.
-
-enum {
-  MESSAGE_FLAG_PANIC = (1 << 0),
-  MESSAGE_FLAG_ERRNO = (1 << 1),
-};
-
-void vmessage(int flags, const TCHAR* fmt, va_list args) {
-  int old_errno = errno;
-  if (flags & MESSAGE_FLAG_PANIC)
-    fprintf(stderr, "ERROR: ");
-
-  _vftprintf(stderr, fmt, args);
-  if (flags & MESSAGE_FLAG_ERRNO) {
-    fprintf(stderr, ": %s", strerror(old_errno));
-  }
-  fprintf(stderr, "\n");
-
-  if (flags & MESSAGE_FLAG_PANIC)
-    exit(1);
-
-  errno = old_errno;
-}
-
-void panic(const TCHAR* fmt, ...) {
-  va_list args;
-  va_start(args, fmt);
-  vmessage(MESSAGE_FLAG_PANIC, fmt, args);
-  va_end(args);
-}
-
-int g_verbose = 0;
-
-void log_n(int n, const TCHAR* fmt, ...) {
-  if (g_verbose >= n) {
-    va_list args;
-    va_start(args, fmt);
-    _vtprintf(fmt, args);
-    va_end(args);
-  }
-}
-
-#define LOG_N(level,...) \
-  ({ if (g_verbose >= (level)) log_n((level), __VA_ARGS__); })
-
-#define LOG(...)  LOG_N(1,__VA_ARGS__)
-#define LOG2(...) LOG_N(2,__VA_ARGS__)
-
-#ifndef DEBUG
-#define DEBUG 0
-#endif
-
-#if DEBUG
-#define DLOG(...) _tprintf(__VA_ARGS__)
-#else
-#define DLOG(...) ((void)0)
-#endif
-
-// Path utilites
-
-// Return the position of the last directory separator in a path,
-// or std::string::npos if none is found.
-size_t path_last_dirsep(const String& filepath) {
-#ifdef _WIN32
-  size_t sep_slash = filepath.rfind(_T('/'));
-  size_t sep_backslash = filepath.rfind(_T('\\'));
-  size_t sep;
-  if (sep_slash == std::string::npos)
-    sep = sep_backslash;
-  else if (sep_backslash == std::string::npos)
-    sep = sep_slash;
-  else
-    sep = std::max(sep_slash, sep_backslash);
-#else
-  size_t sep = filepath.rfind(_T('/'));
-#endif
-  return sep;
-}
-
-// Return the directory name of a given path.
-String path_dirname(const String& filepath) {
-  size_t sep = path_last_dirsep(filepath);
-  if (sep == std::string::npos)
-    return String(_T("."));
-  else if (sep == 0)
-    return String(_T("/"));
-  else
-    return filepath.substr(0, sep);
-}
-
-// Return the basename of a given path.
-String path_basename(const String& filepath) {
-  size_t sep = path_last_dirsep(filepath);
-  if (sep == std::string::npos)
-    return filepath;
-  else
-    return filepath.substr(sep + 1);
-}
-
-
-// Reading utilities.
-
-uint16_t get_u16_le(const uint8_t* bytes) {
-  return static_cast<uint16_t>(bytes[0] | (bytes[1] << 8));
-}
-
-uint32_t get_u32_le(const uint8_t* bytes) {
-  return static_cast<uint32_t>(
-      bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24));
-}
-
-uint64_t get_u64_le(const uint8_t* bytes) {
-  uint64_t lo = static_cast<uint64_t>(get_u32_le(bytes));
-  uint64_t hi = static_cast<uint64_t>(get_u32_le(bytes + 4));
-  return lo | (hi << 32);
-}
-
-uint16_t get_u16_be(const uint8_t* bytes) {
-  return static_cast<uint16_t>((bytes[0] << 8) | bytes[1]);
-}
-
-uint32_t get_u32_be(const uint8_t* bytes) {
-  return static_cast<uint32_t>(
-      (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]);
-}
-
-uint64_t get_u64_be(const uint8_t* bytes) {
-  uint64_t hi = static_cast<uint64_t>(get_u32_be(bytes));
-  uint64_t lo = static_cast<uint64_t>(get_u32_be(bytes + 4));
-  return lo | (hi << 32);
-}
-
-// FileReader utility classes
-
-class Reader {
-public:
-  Reader() {}
-
-  virtual const uint8_t* GetBytesAt(off_t pos, size_t size) = 0;
-  virtual uint16_t GetU16At(off_t pos) = 0;
-  virtual uint32_t GetU32At(off_t pos) = 0;
-  virtual uint64_t GetU64At(off_t pos) = 0;
-
-  virtual ~Reader() {}
-};
-
-class FileReader : public Reader {
-public:
-  FileReader(FILE* file) : file_(file) {}
-
-  virtual const uint8_t* GetBytesAt(off_t pos, size_t size) {
-    if (size < kMaxBytes &&
-        fseek(file_, pos, SEEK_SET) == 0 &&
-        fread(buffer_, size, 1, file_) == 1) {
-      return buffer_;
-    } else
-      return NULL;
-  }
-
-private:
-  static const size_t kMaxBytes = 32;
-  FILE* file_;
-  uint8_t buffer_[kMaxBytes];
-};
-
-class FileLittleEndianReader : public FileReader {
-public:
-  FileLittleEndianReader(FILE* file) : FileReader(file) {}
-
-  virtual uint16_t GetU16At(off_t pos) {
-    const uint8_t* buf = GetBytesAt(pos, 2);
-    return (buf != NULL) ? get_u16_le(buf) : 0;
-  }
-
-  virtual uint32_t GetU32At(off_t pos) {
-    const uint8_t* buf = GetBytesAt(pos, 4);
-    return (buf != NULL) ? get_u32_le(buf) : 0;
-  }
-
-  virtual uint64_t GetU64At(off_t pos) {
-    const uint8_t* buf = GetBytesAt(pos, 8);
-    return (buf != NULL) ? get_u64_le(buf) : 0ULL;
-  }
-};
-
-class FileBigEndianReader : public FileReader {
-public:
-  FileBigEndianReader(FILE* file) : FileReader(file) {}
-
-  virtual uint16_t GetU16At(off_t pos) {
-    const uint8_t* buf = GetBytesAt(pos, 2);
-    return (buf != NULL) ? get_u16_be(buf) : 0;
-  }
-
-  virtual uint32_t GetU32At(off_t pos) {
-    const uint8_t* buf = GetBytesAt(pos, 4);
-    return (buf != NULL) ? get_u32_be(buf) : 0;
-  }
-
-  virtual uint64_t GetU64At(off_t pos) {
-    const uint8_t* buf = GetBytesAt(pos, 8);
-    return (buf != NULL) ? get_u64_be(buf) : 0ULL;
-  }
-};
-
-// ELF utility functions.
-
-// The first 16 common bytes.
-#define EI_NIDENT 16
-
-#define EI_CLASS   4
-#define ELFCLASS32 1
-#define ELFCLASS64 2
-
-#define EI_DATA     5
-#define ELFDATA2LSB 1
-#define ELFDATA2MSB 2
-
-bool elf_ident_is_elf(const uint8_t* ident) {
-  return ident[0] == 0x7f &&
-         ident[1] == 'E' &&
-         ident[2] == 'L' &&
-         ident[3] == 'F';
-}
-
-bool elf_ident_is_big_endian(const uint8_t* ident) {
-  return ident[EI_DATA] == ELFDATA2MSB;
-}
-
-bool elf_ident_is_64bits(const uint8_t* ident) {
-  return ident[EI_CLASS] == ELFCLASS64;
-}
-
-#define SHT_STRTAB  3
-#define SHT_DYNAMIC 6
-
-// 32-bit ELF definitions.
-
-class Elf32 {
-public:
-  typedef uint16_t Half;
-  typedef uint32_t Word;
-  typedef uint32_t Off;
-  typedef uint32_t Addr;
-  typedef int32_t Sword;
-
-  struct Header {
-    uint8_t e_ident[EI_NIDENT];
-    Half    e_type;
-    Half    e_machine;
-    Word    e_version;
-    Addr    e_entry;
-    Off     e_phoff;
-    Off     e_shoff;
-    Word    e_flags;
-    Half    e_shsize;
-    Half    e_phentsize;
-    Half    e_phnum;
-    Half    e_shentsize;
-    Half    e_shnum;
-    Half    e_shstrndx;
-  };
-
-  struct Shdr {
-    Word sh_name;
-    Word sh_type;
-    Word sh_flags;
-    Addr sh_addr;
-    Off  sh_offset;
-    Word sh_size;
-    Word sh_link;
-    Word sh_info;
-    Word sh_addralign;
-    Word sh_entsize;
-  };
-};
-
-class Elf64 {
-public:
-  typedef uint16_t Half;
-  typedef uint64_t Off;
-  typedef uint64_t Addr;
-  typedef int32_t  Sword;
-  typedef uint32_t Word;
-  typedef uint64_t Xword;
-  typedef int64_t Sxword;
-
-  struct Header {
-    uint8_t e_ident[EI_NIDENT];
-    Half    e_type;
-    Half    e_machine;
-    Word    e_version;
-    Addr    e_entry;
-    Off     e_phoff;
-    Off     e_shoff;
-    Word    e_flags;
-    Half    e_shsize;
-    Half    e_phentsize;
-    Half    e_phnum;
-    Half    e_shentsize;
-    Half    e_shnum;
-    Half    e_shstrndx;
-  };
-
-  struct Shdr {
-    Word  sh_name;
-    Word  sh_type;
-    Xword sh_flags;
-    Addr  sh_addr;
-    Off   sh_offset;
-    Xword sh_size;
-    Word  sh_link;
-    Word  sh_info;
-    Xword sh_addralign;
-    Xword sh_entsize;
-  };
-};
-
-template <class ELF>
-class ElfParser {
-public:
-  ElfParser(Reader& reader) : reader_(reader) {}
-
-  typedef typename ELF::Word Word;
-  typedef typename ELF::Sword Sword;
-  typedef typename ELF::Addr Addr;
-  typedef typename ELF::Off Off;
-  typedef typename ELF::Half Half;
-  typedef typename ELF::Header ElfHeader;
-  typedef typename ELF::Shdr Shdr;
-
-  // Read an ELF::Word at a given position.
-  Word GetWordAt(off_t pos) {
-    return reader_.GetU32At(pos);
-  }
-
-  // Read an ELF::Half at a given position.
-  Half GetHalfAt(off_t pos) {
-    return reader_.GetU16At(pos);
-  }
-
-  // Read an ELF::Sword at a given position.
-  Sword GetSwordAt(off_t pos) {
-    return static_cast<Sword>(GetWordAt(pos));
-  }
-
-  // Read an ELF::Addr at a given position.
-  Addr GetAddrAt(off_t pos);
-
-  // Read an ELF::Off at a given position.
-  Off GetOffAt(off_t pos) {
-    return static_cast<Off>(GetAddrAt(pos));
-  }
-
-  // Helper class to iterate over the section table.
-  class SectionIterator {
-  public:
-    explicit SectionIterator(ElfParser& parser)
-      : parser_(parser) {
-      table_offset_ = parser_.GetOffAt(offsetof(ElfHeader, e_shoff));
-      table_count_ = parser_.GetHalfAt(offsetof(ElfHeader, e_shnum));
-      table_entry_size_ = parser_.GetHalfAt(offsetof(ElfHeader, e_shentsize));
-      if (table_entry_size_ < static_cast<Half>(sizeof(Shdr))) {
-        // malformed binary. Ignore all sections.
-        table_count_ = 0;
-      }
-    }
-
-    Off NextOffset() {
-      if (table_count_ == 0)
-        return 0;
-      Off result = table_offset_;
-      table_offset_ += table_entry_size_;
-      table_count_ -= 1;
-      return result;
-    }
-
-    void Skip(int count) {
-      while (count > 0 && table_count_ > 0) {
-        table_offset_ += table_entry_size_;
-        table_count_--;
-        count--;
-      }
-    }
-
-  private:
-    ElfParser& parser_;
-    Off table_offset_;
-    Half table_count_;
-    Half table_entry_size_;
-  };
-
-  // Return the offset of the first section of a given type, or 0 if not
-  // found. |*size| will be set to the section size in bytes in case of
-  // success.
-  Off GetSectionOffsetByType(int table_type, Off* size) {
-    SectionIterator iter(*this);
-    for (;;) {
-      Off table_offset = iter.NextOffset();
-      if (table_offset == 0)
-        break;
-      Word sh_type = GetWordAt(table_offset + offsetof(Shdr, sh_type));
-      if (sh_type == static_cast<Word>(table_type)) {
-        *size = GetOffAt(table_offset + offsetof(Shdr, sh_size));
-        return GetOffAt(table_offset + offsetof(Shdr, sh_offset));
-      }
-    }
-    return 0;
-  }
-
-  // Return the index of the string table for the dynamic section
-  // in this ELF binary. Or 0 if not found.
-  int GetDynamicStringTableIndex() {
-    SectionIterator iter(*this);
-    for (;;) {
-      Off table_offset = iter.NextOffset();
-      if (table_offset == 0)
-        break;
-      Word sh_type = GetWordAt(table_offset + offsetof(Shdr, sh_type));
-      if (sh_type == SHT_DYNAMIC)
-        return GetWordAt(table_offset + offsetof(Shdr, sh_link));
-    }
-    return 0;
-  }
-
-  // Return the offset of a section identified by its index, or 0 in case
-  // of error (bad index).
-  Off GetSectionOffsetByIndex(int sec_index, Off* size) {
-    SectionIterator iter(*this);
-    iter.Skip(sec_index);
-    Off table_offset = iter.NextOffset();
-    if (table_offset != 0) {
-      *size = GetOffAt(table_offset + offsetof(Shdr, sh_size));
-      return GetOffAt(table_offset + offsetof(Shdr, sh_offset));
-    }
-    return 0;
-  }
-
-  // Return a string identified by its index and its string table
-  // Address. Returns an empty string in case of error.
-  String GetStringByIndex(Off str_index, int str_table_index) {
-    String result;
-
-    if (str_table_index != 0) {
-      Off str_table_size = 0;
-      Off str_table = GetSectionOffsetByIndex(str_table_index,
-                                              &str_table_size);
-      if (str_table != 0 && str_index < str_table_size) {
-        str_table += str_index;
-        str_table_size -= str_index;
-        while (str_table_size > 0) {
-          const uint8_t* p = reader_.GetBytesAt(str_table, 1);
-          if (p == NULL || *p == '\0')
-            break;
-          result.append(1, static_cast<const char>(*p));
-          str_table += 1;
-          str_table_size -= 1;
-        }
-      }
-    }
-    return result;
-  }
-
-private:
-  Reader& reader_;
-};
-
-template <>
-Elf32::Addr ElfParser<Elf32>::GetAddrAt(off_t pos) {
-  return reader_.GetU32At(pos);
-}
-
-template <>
-Elf64::Addr ElfParser<Elf64>::GetAddrAt(off_t pos) {
-  return reader_.GetU64At(pos);
-}
-
-// Helper class to iterate over items of a given type in the dynamic
-// section. A type of 0 (SHT_NULL) means iterate over all items.
-//
-// Examples:
-//    // Iterate over all entries in the table, find the SHT_NEEDED ones.
-//    DynamicIterator<Elf32> iter(parser);
-//    while (iter.GetNext()) {
-//      if (iter.GetTag() == SHT_NEEDED) {
-//         Elf32::Off value = iter.GetValue();
-//         ...
-//      }
-//    }
-template <class ELF>
-class DynamicIterator {
-public:
-  explicit DynamicIterator(ElfParser<ELF>& parser)
-    : parser_(parser),
-      dyn_size_(0),
-      dyn_offset_(0),
-      started_(false) {
-    dyn_offset_ = parser_.GetSectionOffsetByType(SHT_DYNAMIC, &dyn_size_);
-    started_ = (dyn_size_ < kEntrySize);
-  }
-
-  bool GetNext() {
-    if (!started_)
-      started_ = true;
-    else {
-      if (dyn_size_ < kEntrySize)
-        return false;
-      dyn_offset_ += kEntrySize;
-      dyn_size_ -= kEntrySize;
-    }
-    return true;
-  }
-
-  typename ELF::Off GetTag() {
-    return parser_.GetOffAt(dyn_offset_);
-  }
-
-  typename ELF::Off GetValue() {
-    return parser_.GetOffAt(dyn_offset_ + kTagSize);
-  }
-
-private:
-  typedef typename ELF::Off Off;
-  static const Off kTagSize = static_cast<Off>(sizeof(Off));
-  static const Off kValueSize = kTagSize;
-  static const Off kEntrySize = kTagSize + kValueSize;
-
-  ElfParser<ELF>& parser_;
-  Off dyn_size_;
-  Off dyn_offset_;
-  bool started_;
-};
-
-#define DT_NEEDED 1
-#define DT_SONAME 14
-
-template <class ELF>
-String GetLibNameT(Reader& reader) {
-  ElfParser<ELF> parser(reader);
-  int str_table_index = parser.GetDynamicStringTableIndex();
-  DynamicIterator<ELF> iter(parser);
-  while (iter.GetNext()) {
-    if (iter.GetTag() == DT_SONAME) {
-      typename ELF::Off str_index = iter.GetValue();
-      return parser.GetStringByIndex(str_index, str_table_index);
-    }
-  }
-  return String();
-}
-
-template <class ELF>
-int GetNeededLibsT(Reader& reader, std::vector<String>* result) {
-  ElfParser<ELF> parser(reader);
-  int str_table_index = parser.GetDynamicStringTableIndex();
-  DynamicIterator<ELF> iter(parser);
-  int count = 0;
-  while (iter.GetNext()) {
-    if (iter.GetTag() == DT_NEEDED) {
-      typename ELF::Off str_index = iter.GetValue();
-      String lib_name = parser.GetStringByIndex(str_index, str_table_index);
-      if (!lib_name.empty()) {
-        result->push_back(lib_name);
-        count++;
-      }
-    }
-  }
-  return count;
-}
-
-class ElfFile {
-public:
-  ElfFile()
-    : file_(NULL), big_endian_(false), is_64bits_(false), reader_(NULL) {}
-
-  virtual ~ElfFile() {
-    delete reader_;
-    Close();
-  }
-
-  bool Open(const TCHAR* path, String* error) {
-    Close();
-    file_ = _tfopen(path, _T("rb"));
-    if (file_ == NULL) {
-      error->assign(TO_STRING(strerror(errno)));
-      return false;
-    }
-    uint8_t ident[EI_NIDENT];
-    if (fread(ident, sizeof(ident), 1, file_) != 1) {
-      error->assign(TO_STRING(strerror(errno)));
-      Close();
-      return false;
-    }
-    if (!elf_ident_is_elf(ident)) {
-      *error = _T("Not an ELF binary file");
-      Close();
-      return false;
-    }
-    big_endian_ = elf_ident_is_big_endian(ident);
-    is_64bits_ = elf_ident_is_64bits(ident);
-
-    if (big_endian_) {
-      reader_ = new FileBigEndianReader(file_);
-    } else {
-      reader_ = new FileLittleEndianReader(file_);
-    }
-    return true;
-  }
-
-  bool IsOk() { return file_ != NULL; }
-
-  bool IsBigEndian() { return big_endian_; }
-
-  const Reader& GetReader() { return *reader_; };
-
-  // Returns the embedded library name, extracted from the dynamic table.
-  String GetLibName() {
-    if (is_64bits_)
-      return GetLibNameT<Elf64>(*reader_);
-    else
-      return GetLibNameT<Elf32>(*reader_);
-  }
-
-  // Gets the list of needed libraries and appends them to |result|.
-  // Returns the number of library names appended.
-  int GetNeededLibs(std::vector<String>* result) {
-    if (is_64bits_)
-      return GetNeededLibsT<Elf64>(*reader_, result);
-    else
-      return GetNeededLibsT<Elf32>(*reader_, result);
-  }
-
-protected:
-  void Close() {
-    if (file_ != NULL) {
-      fclose(file_);
-      file_ = NULL;
-    }
-  }
-
-  FILE* file_;
-  bool big_endian_;
-  bool is_64bits_;
-  Reader* reader_;
-};
-
-#ifdef __linux__
-static bool IsLdSoConfSeparator(char ch) {
-  // The ldconfig manpage indicates that /etc/ld.so.conf contains a list
-  // of colon, space, tab newline or comma separated directories.
-  return (ch == ' ' || ch == '\t' || ch == '\r' ||
-          ch == '\n' || ch == ',' || ch == ':');
-}
-
-// Parse the content of /etc/ld.so.conf, it contains according to the
-// documentation a 'comma, space, newline, tab separated list of
-// directories'. In practice, it can also include comments, and an
-// include directive and glob patterns, as in:
-//  'include /etc/ld.so.conf.d/*.conf'
-void AddHostLdSoConfPaths(const char* ld_so_conf_path,
-                          std::vector<String>* lib_search_path) {
-  FILE* file = fopen(ld_so_conf_path, "rb");
-  if (!file)
-    return;
-
-  char line[1024];
-  while (fgets(line, sizeof(line), file) != NULL) {
-    const char* begin = line;
-    const char* end = line + strlen(line);
-    while (end > begin && end[-1] == '\n')
-      end--;
-
-    bool prev_is_include = false;
-    while (begin < end) {
-      // Skip over separators
-      while (begin < end && IsLdSoConfSeparator(*begin))
-        begin++;
-
-      if (begin == end || begin[0] == '#') {
-        // Skip empty lines and comments.
-        break;
-      }
-      // Find end of current item
-      const char* next_pos = begin;
-      while (next_pos < end &&
-          !IsLdSoConfSeparator(*next_pos) &&
-          *next_pos != '#')
-        next_pos++;
-
-      size_t len = static_cast<size_t>(next_pos - begin);
-      if (prev_is_include) {
-        // If previous token was an 'include', treat this as a glob
-        // pattern and try to process all matching files.
-        prev_is_include = false;
-        if (len == 0) {
-          // Ignore stand-alone 'include' in a single line.
-          break;
-        }
-        String pattern(begin, len);
-        DLOG("%s: processing include '%s'\n",
-             __FUNCTION__,
-             pattern.c_str());
-
-        glob_t the_glob;
-        memset(&the_glob, 0, sizeof(the_glob));
-        int ret = ::glob(pattern.c_str(), 0, NULL, &the_glob);
-        if (ret == 0) {
-          // Iterate / include all matching files.
-          String filepath;
-          for (size_t n = 0; n < the_glob.gl_pathc; ++n) {
-            filepath.assign(the_glob.gl_pathv[n]);
-            DLOG("%s: Including %s\n", __FUNCTION__, filepath.c_str());
-            AddHostLdSoConfPaths(filepath.c_str(), lib_search_path);
-          }
-        }
-        globfree(&the_glob);
-      } else {
-        // The previous token was not an 'include'. But is the current one?
-        static const char kInclude[] = "include";
-        const size_t kIncludeLen = sizeof(kInclude) - 1;
-        if (len == kIncludeLen && !memcmp(begin, kInclude, len)) {
-          prev_is_include = true;
-        } else if (len > 0) {
-          // No, it must be a directory name.
-          String dirpath(begin, len);
-          struct stat st;
-          if (::stat(dirpath.c_str(), &st) != 0) {
-            LOG("Could not stat(): %s: %s\n", dirpath.c_str(), strerror(errno));
-          } else if (!S_ISDIR(st.st_mode)) {
-            LOG("Not a directory: %s\n", dirpath.c_str());
-          } else {
-            DLOG("%s: Adding %s\n", __FUNCTION__, dirpath.c_str());
-            lib_search_path->push_back(dirpath);
-          }
-        }
-      }
-      // switch to next item in line.
-      begin = next_pos;
-    }
-  }
-  fclose(file);
-}
-#endif  // __linux__
-
-// Add host shared library search path to |lib_search_path|
-void AddHostLibraryPaths(std::vector<String>* lib_search_path) {
-  // Only add libraries form LD_LIBRARY_PATH on ELF-based systems.
-#if defined(__ELF__)
-  // If LD_LIBRARY_PATH is defined, process it
-  const TCHAR* env = _tgetenv(_T("LD_LIBRARY_PATH"));
-  if (env != NULL) {
-    const TCHAR* pos = env;
-    while (*pos) {
-      size_t path_len;
-      const TCHAR* next_pos = _tcschr(pos, ':');
-      if (next_pos == NULL) {
-        path_len = _tcslen(pos);
-        next_pos = pos + path_len;
-      } else {
-        path_len = next_pos - pos;
-        next_pos += 1;
-      }
-
-      if (path_len == 0) {
-        // Per POSIX convention, an empty path item means "current path".
-        // Not that this is generally a very bad idea, security-wise.
-        lib_search_path->push_back(_T("."));
-      } else {
-        lib_search_path->push_back(String(pos, path_len));
-      }
-
-      pos = next_pos;
-    }
-  }
-#ifdef __linux__
-  AddHostLdSoConfPaths("/etc/ld.so.conf", lib_search_path);
-#endif
-  // TODO(digit): What about BSD systems?
-#endif
-}
-
-// Returns true if |libname| is the name of an Android system library.
-bool IsAndroidSystemLib(const String& libname) {
-  static const TCHAR* const kAndroidSystemLibs[] = {
-    _T("libc.so"),
-    _T("libdl.so"),
-    _T("liblog.so"),
-    _T("libm.so"),
-    _T("libstdc++.so"),
-    _T("libz.so"),
-    _T("libandroid.so"),
-    _T("libjnigraphics.so"),
-    _T("libEGL.so"),
-    _T("libGLESv1_CM.so"),
-    _T("libGLESv2.so"),
-    _T("libOpenSLES.so"),
-    _T("libOpenMAXAL.so"),
-    NULL
-  };
-  for (size_t n = 0; kAndroidSystemLibs[n] != NULL; ++n) {
-    if (!libname.compare(kAndroidSystemLibs[n]))
-      return true;
-  }
-  return false;
-}
-
-// Returns true if |libname| is the name of an NDK-compatible shared
-// library. This means its must begin with "lib" and end with "so"
-// (without any version numbers).
-bool IsAndroidNdkCompatibleLib(const String& libname) {
-  return libname.size() > 6 &&
-         !libname.compare(0, 3, _T("lib")) &&
-         !libname.compare(libname.size() - 3, 3, _T(".so"));
-}
-
-// Try to find a library named |libname| in |search_paths|
-// Returns true on success, and sets |result| to the full library path,
-// false otherwise.
-bool FindLibraryPath(const String& libname,
-                     const std::vector<String>& search_paths,
-                     String* result) {
-  // Check in the search paths.
-  LOG2(_T("  looking for library: %s\n"), libname.c_str());
-  for (size_t n = 0; n < search_paths.size(); ++n) {
-    String file_path = search_paths[n];
-    if (file_path.empty())
-      continue;
-    if (file_path[file_path.size() - 1] != _T('/') &&
-        file_path[file_path.size() - 1] != _T('\\')) {
-      file_path.append(_T("/"));
-    }
-    file_path.append(libname);
-
-    LOG2(_T("    in %s: "), file_path.c_str());
-    struct _stat st;
-    if (_tstat(file_path.c_str(), &st) < 0) {
-      LOG2(_T("%s\n"), TO_CONST_TCHAR(strerror(errno)));
-      continue;
-    }
-    if (!S_ISREG(st.st_mode)) {
-      LOG2(_T("Not a regular file!\n"));
-      continue;
-    }
-    // Found the library file.
-    LOG2(_T("OK\n"));
-    result->assign(file_path);
-    return true;
-  }
-
-  return false;
-}
-
-// Recursive support
-
-struct LibNode {
-  // An enumeration listing possible node types, which are:
-  enum Type {
-    NODE_NONE,   // No type yet.
-    NODE_PATH,   // Valid ELF library, |value| is file path.
-    NODE_ERROR,  // Invalid library name, |value| is error string.
-    NODE_SYSTEM, // Android system library, |value| is library name.
-  };
-
-  Type type;
-  String value;
-  std::vector<String> needed_libs;
-
-  LibNode() : type(NODE_NONE), value(), needed_libs() {}
-
-  explicit LibNode(const String& path)
-    : type(NODE_PATH), value(path), needed_libs() {}
-
-  void Set(Type type_p, const String& value_p) {
-    type = type_p;
-    value = value_p;
-  }
-};
-
-typedef std::map<String, LibNode> DependencyGraph;
-typedef std::list<String> WorkQueue;
-
-// Used internally by BuildDependencyGraph().
-void UpdateDependencies(
-    const String& libname,
-    const String& libpath,
-    DependencyGraph& deps,
-    WorkQueue& queue) {
-  DLOG(_T("UPDATE libname=%s path=%s\n"), libname.c_str(), libpath.c_str());
-  // Sanity check: find if the library is already in the graph.
-  if (!libname.empty() && deps.find(libname) != deps.end()) {
-    // Should not happen.
-    panic(_T("INTERNAL: Library already in graph: %s"), libname.c_str());
-  }
-
-  LibNode node;
-  ElfFile libfile;
-  String error;
-  String soname = libname;
-  if (!libfile.Open(libpath.c_str(), &error)) {
-    node.Set(LibNode::NODE_ERROR, error);
-  } else {
-    String soname = libfile.GetLibName();
-    if (soname.empty())
-      soname = libname;
-    else if (soname != libname) {
-      _ftprintf(stderr,
-                _T("WARNING: Library has invalid soname ('%s'): %s\n"),
-                soname.c_str(),
-                libpath.c_str());
-    }
-    // Discovered a new library, get its dependent libraries.
-    node.Set(LibNode::NODE_PATH, libpath);
-    libfile.GetNeededLibs(&node.needed_libs);
-
-    LOG(_T("%s depends on:"), soname.c_str());
-
-    // Add them to the work queue.
-    for (size_t n = 0; n < node.needed_libs.size(); ++n) {
-      LOG(_T(" %s"), node.needed_libs[n].c_str());
-      queue.push_back(node.needed_libs[n]);
-    }
-    LOG(_T("\n"));
-  }
-  deps[soname] = node;
-}
-
-// Build the full dependency graph.
-// |root_libpath| is the path of the root library.
-// |lib_search_path| is the list of library search paths.
-// Returns a new dependency graph object.
-DependencyGraph BuildDependencyGraph(
-    const String& root_libpath,
-    const std::vector<String>& lib_search_path) {
-  DependencyGraph deps;
-  std::list<String> queue;
-
-  // As a first step, build the full dependency graph, starting with the
-  // root library. This records errors in the graph too.
-  UpdateDependencies(path_basename(root_libpath),
-                     root_libpath,
-                     deps, queue);
-
-  while (!queue.empty()) {
-    // Pop first item from queue.
-    String libname = queue.front();
-    queue.pop_front();
-
-    // Is the library already in the graph?
-    DependencyGraph::iterator iter = deps.find(libname);
-    if (iter != deps.end()) {
-      // Library already found, skip it.
-      continue;
-    }
-
-    // Find the library in the current search path.
-    String libpath;
-    if (FindLibraryPath(libname, lib_search_path, &libpath)) {
-      UpdateDependencies(libname, libpath, deps, queue);
-      continue;
-    }
-
-    if (IsAndroidSystemLib(libname)) {
-      LOG(_T("Android system library: %s\n"), libname.c_str());
-      LibNode node;
-      node.Set(LibNode::NODE_SYSTEM, libname);
-      deps[libname] = node;
-      continue;
-    }
-
-    _ftprintf(stderr,
-              _T("WARNING: Could not find library: %s\n"),
-              libname.c_str());
-    LibNode node;
-    node.Set(LibNode::NODE_ERROR, _T("Could not find library"));
-    deps[libname] = node;
-  }
-
-  return deps;
-}
-
-// Print the dependency graph in a human-readable format to stdout.
-void DumpDependencyGraph(const DependencyGraph& deps) {
-  _tprintf(_T("Dependency graph:\n"));
-  DependencyGraph::const_iterator iter = deps.begin();
-  for ( ; iter != deps.end(); ++iter ) {
-    const String& libname = iter->first;
-    const LibNode& node = iter->second;
-    String node_type;
-    switch (node.type) {
-      case LibNode::NODE_NONE:  // should not happen.
-        node_type = _T("NONE??");
-        break;
-      case LibNode::NODE_PATH:
-        node_type = _T("PATH");
-        break;
-      case LibNode::NODE_ERROR:
-        node_type = _T("ERROR");
-        break;
-      case LibNode::NODE_SYSTEM:
-        node_type = _T("SYSTEM");
-    }
-    _tprintf(
-        _T("[%s] %s %s\n"),
-        libname.c_str(),
-        node_type.c_str(),
-        node.value.c_str());
-
-    if (node.type == LibNode::NODE_PATH) {
-      for (size_t n = 0; n < node.needed_libs.size(); ++n) {
-        _tprintf(_T("    %s\n"), node.needed_libs[n].c_str());
-      }
-    }
-  }
-}
-
-// Return the sorted list of libraries from a dependency graph.
-// They are topologically ordered, i.e. a library appears always
-// before any other library it depends on.
-void GetTopologicalSortedLibraries(
-    DependencyGraph& deps,
-    std::vector<String>* result) {
-  result->clear();
-  // First: Compute the number of visitors per library in the graph.
-  typedef std::map<String, int> VisitorMap;
-  VisitorMap visitors;
-  for (DependencyGraph::const_iterator iter = deps.begin();
-      iter != deps.end();
-      ++iter) {
-    if (visitors.find(iter->first) == visitors.end()) {
-      visitors[iter->first] = 0;
-    }
-
-    const std::vector<String>& needed_libs = iter->second.needed_libs;
-    for (size_t n = 0; n < needed_libs.size(); ++n) {
-      const String& libname = needed_libs[n];
-      VisitorMap::iterator lib_iter = visitors.find(libname);
-      if (lib_iter != visitors.end())
-        lib_iter->second += 1;
-      else
-        visitors[libname] = 1;
-    }
-  }
-
-#if DEBUG
-  {
-    VisitorMap::const_iterator iter_end = visitors.end();
-    VisitorMap::const_iterator iter = visitors.begin();
-    for ( ; iter != iter_end; ++iter ) {
-      _tprintf(_T("-- %s %d\n"), iter->first.c_str(), iter->second);
-    }
-  }
-#endif
-
-  while (!visitors.empty()) {
-    // Find the library with the smallest number of visitors.
-    // The value should be 0, unless there are circular dependencies.
-    VisitorMap::const_iterator iter_end = visitors.end();
-    VisitorMap::const_iterator iter;
-    int min_visitors = INT_MAX;
-    String min_libname;
-    for (iter = visitors.begin(); iter != iter_end; ++iter) {
-      // Note: Uses <= instead of < to ensure better diagnostics in
-      // case of circular dependencies. This shall return the latest
-      // node in the cycle, i.e. the first one where a 'back' edge
-      // exists.
-      if (iter->second <= min_visitors) {
-        min_libname = iter->first;
-        min_visitors = iter->second;
-      }
-    }
-
-    if (min_visitors == INT_MAX) {
-      // Should not happen.
-      panic(_T("INTERNAL: Could not find minimum visited node!"));
-    }
-
-    // min_visitors should be 0, unless there are circular dependencies.
-    if (min_visitors != 0) {
-      // Warn about circular dependencies
-      _ftprintf(stderr,
-                _T("WARNING: Circular dependency found from: %s\n"),
-                min_libname.c_str());
-    }
-
-    // Remove minimum node from the graph, and decrement the visitor
-    // count of all its needed libraries. This also breaks dependency
-    // cycles.
-    result->push_back(min_libname);
-    const LibNode& node = deps[min_libname];
-    const std::vector<String> needed_libs = node.needed_libs;
-    visitors.erase(min_libname);
-
-    for (size_t n = 0; n < needed_libs.size(); ++n)
-      visitors[needed_libs[n]]--;
-  }
-}
-
-// Main function
-
-#define PROGNAME "ndk-depends"
-
-void print_usage(int exit_code) {
-  printf(
-    "Usage: %s [options] <elf-file>\n\n"
-
-    "This program is used to print the dependencies of a given ELF\n"
-    "binary (shared library or executable). It supports any architecture,\n"
-    "endianess and bitness.\n\n"
-
-    "By default, all dependencies are printed in topological order,\n"
-    "which means that each item always appear before other items\n"
-    "it depends on. Except in case of circular dependencies, which will\n"
-    "print a warning to stderr.\n\n"
-
-    "The tool will try to find other libraries in the same directory\n"
-    "as the input ELF file. It is possible however to provide\n"
-    "additional search paths with the -L<path>, which adds an explicit path\n"
-    "or --host-libs which adds host-specific library paths, on ELF-based systems\n"
-    "only.\n\n"
-
-    "Use --print-paths to print the path of each ELF binary.\n\n"
-
-    "Use --print-direct to only print the direct dependencies\n"
-    "of the input ELF binary. All other options except --verbose will be ignored.\n\n"
-
-    "Use --print-java to print a Java source fragment that loads the\n"
-    "libraries with System.loadLibrary() in the correct order. This can\n"
-    "be useful when copied into your application's Java source code.\n\n"
-
-    "Use --print-dot to print the dependency graph as a .dot file that can be\n"
-    "parsed by the GraphViz tool. For example, to generate a PNG image of the\n"
-    "graph, use something like:\n\n"
-
-    "  ndk-depends /path/to/libfoo.so --print-dot | dot -Tpng -o /tmp/graph.png\n\n"
-
-    "The --verbose option prints debugging information, which can be useful\n"
-    "to diagnose problems with malformed ELF binaries.\n\n"
-
-    "Valid options:\n"
-    "  --help|-h|-?    Print this message.\n"
-    "  --verbose       Increase verbosity.\n"
-    "  --print-direct  Only print direct dependencies.\n"
-    "  -L<path>        Append <path> to the library search path.\n"
-    "  --host-libs     Append host library search path.\n"
-    "  --print-paths   Print full paths of all libraries.\n"
-    "  --print-java    Print Java library load sequence.\n"
-    "  --print-dot     Print the dependency graph as a Graphviz .dot file.\n"
-    "\n", PROGNAME);
-
-  exit(exit_code);
-}
-
-}  // namespace
-
-
-#ifdef _WIN32
-int main(void) {
-  int argc = 0;
-  TCHAR** argv = CommandLineToArgvW(GetCommandLine(), &argc);
-#else
-int main(int argc, const char** argv) {
-#endif
-
-  enum PrintFormat {
-    PRINT_DEFAULT = 0,
-    PRINT_DIRECT,
-    PRINT_PATHS,
-    PRINT_JAVA,
-    PRINT_DOT_FILE,
-  };
-
-  bool do_help = false;
-  PrintFormat print_format = PRINT_DEFAULT;
-  std::vector<String> lib_search_path;
-  std::vector<String> params;
-
-  // Process options.
-  while (argc > 1) {
-    if (argv[1][0] == _T('-')) {
-      const TCHAR* arg = argv[1];
-      if (!_tcscmp(arg, _T("--help")) ||
-          !_tcscmp(arg, _T("-h")) ||
-          !_tcscmp(arg, _T("-?")))
-        do_help = true;
-      else if (!_tcscmp(arg, _T("--print-direct"))) {
-        print_format = PRINT_DIRECT;
-      } else if (!_tcscmp(arg, _T("-L"))) {
-        if (argc < 3)
-          panic(_T("Option -L requires an argument."));
-        lib_search_path.push_back(String(argv[2]));
-        argc--;
-        argv++;
-      } else if (!_tcsncmp(arg, _T("-L"), 2)) {
-        lib_search_path.push_back(String(arg+2));
-      } else if (!_tcscmp(arg, _T("--host-libs"))) {
-        AddHostLibraryPaths(&lib_search_path);
-      } else if (!_tcscmp(arg, _T("--print-java"))) {
-        print_format = PRINT_JAVA;
-      } else if (!_tcscmp(arg, _T("--print-paths"))) {
-        print_format = PRINT_PATHS;
-      } else if (!_tcscmp(arg, _T("--print-dot"))) {
-        print_format = PRINT_DOT_FILE;
-      } else if (!_tcscmp(arg, _T("--verbose"))) {
-        g_verbose++;
-      } else {
-        panic(_T("Unsupported option '%s', see --help."), arg);
-      }
-    } else {
-      params.push_back(String(argv[1]));
-    }
-    argc--;
-    argv++;
-  }
-
-  if (do_help)
-    print_usage(0);
-
-  if (params.empty())
-    panic(_T("Please provide the path of an ELF shared library or executable."
-             "\nSee --help for usage details."));
-
-  // Insert ELF file directory at the head of the search path.
-  lib_search_path.insert(lib_search_path.begin(), path_dirname(params[0]));
-
-  if (g_verbose >= 1) {
-    _tprintf(_T("Current library search path:\n"));
-    for (size_t n = 0; n < lib_search_path.size(); ++n)
-      _tprintf(_T("  %s\n"), lib_search_path[n].c_str());
-    _tprintf(_T("\n"));
-  }
-
-  // Open main input file.
-  const TCHAR* libfile_path = params[0].c_str();
-
-  ElfFile libfile;
-  String error;
-  if (!libfile.Open(libfile_path, &error)) {
-    panic(_T("Could not open file '%s': %s"), libfile_path, error.c_str());
-  }
-
-  if (print_format == PRINT_DIRECT) {
-    // Simple dump, one line per dependency. No frills, no recursion.
-    std::vector<String> needed_libs;
-    libfile.GetNeededLibs(&needed_libs);
-
-    for (size_t i = 0; i < needed_libs.size(); ++i)
-      _tprintf(_T("%s\n"), needed_libs[i].c_str());
-
-    return 0;
-  }
-
-  // Topological sort of all dependencies.
-  LOG(_T("Building dependency graph...\n"));
-  DependencyGraph deps = BuildDependencyGraph(
-      libfile_path, lib_search_path);
-
-  if (g_verbose >= 2)
-    DumpDependencyGraph(deps);
-
-  LOG(_T("Building sorted list of binaries:\n"));
-  std::vector<String> needed_libs;
-  GetTopologicalSortedLibraries(deps, &needed_libs);
-
-  if (print_format == PRINT_JAVA) {
-    // Print Java libraries in reverse order.
-    std::reverse(needed_libs.begin(), needed_libs.end());
-    for (size_t i = 0; i < needed_libs.size(); ++i) {
-      const String& lib = needed_libs[i];
-      if (IsAndroidSystemLib(lib)) {
-        // Skip system libraries.
-        continue;
-      }
-      if (!IsAndroidNdkCompatibleLib(lib)) {
-        _ftprintf(
-            stderr,
-            _T("WARNING: Non-compatible library name ignored: %s\n"),
-            lib.c_str());
-        continue;
-      }
-      _tprintf(_T("System.loadLibrary(%s);\n"),
-                lib.substr(3, lib.size() - 6).c_str());
-    }
-    return 0;
-  }
-
-  if (print_format == PRINT_DOT_FILE) {
-    // Using the topological order helps generates a more human-friendly
-    // directed graph.
-    _tprintf(_T("digraph {\n"));
-    for (size_t i = 0; i < needed_libs.size(); ++i) {
-      const String& libname = needed_libs[i];
-      const std::vector<String>& libdeps = deps[libname].needed_libs;
-      for (size_t n = 0; n < libdeps.size(); ++n) {
-        // Note: Use quoting to deal with special characters like -
-        // which are not normally part of DOT 'id' tokens.
-        _tprintf(_T("  \"%s\" -> \"%s\"\n"), libname.c_str(), libdeps[n].c_str());
-      }
-    }
-    _tprintf(_T("}\n"));
-    return 0;
-  }
-
-  if (print_format == PRINT_PATHS) {
-    // Print libraries with path.
-    for (size_t i = 0; i < needed_libs.size(); ++i) {
-      const String& lib = needed_libs[i];
-      LibNode& node = deps[lib];
-      const TCHAR* format;
-      switch (node.type) {
-        case LibNode::NODE_PATH:
-          format = _T("%s -> %s\n");
-          break;
-        case LibNode::NODE_SYSTEM:
-          format = _T("%s -> $ /system/lib/%s\n");
-          break;
-        default:
-          format = _T("%s -> !! %s\n");
-      }
-      _tprintf(format, lib.c_str(), deps[lib].value.c_str());
-    }
-    return 0;
-  }
-
-  // Print simple library names.
-  for (size_t i = 0; i < needed_libs.size(); ++i) {
-    const String& lib = needed_libs[i];
-    _tprintf(_T("%s\n"), lib.c_str());
-  }
-  return 0;
-}