1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.command;
18
19import com.android.dx.Version;
20
21/**
22 * Main class for dx. It recognizes enough options to be able to dispatch
23 * to the right "actual" main.
24 */
25public class Main {
26    private static final String USAGE_MESSAGE =
27        "usage:\n" +
28        "  dx --dex [--debug] [--verbose] [--positions=<style>] [--no-locals]\n" +
29        "  [--no-optimize] [--statistics] [--[no-]optimize-list=<file>] [--no-strict]\n" +
30        "  [--keep-classes] [--output=<file>] [--dump-to=<file>] [--dump-width=<n>]\n" +
31        "  [--dump-method=<name>[*]] [--verbose-dump] [--no-files] [--core-library]\n" +
32        "  [--num-threads=<n>] [--incremental] [--force-jumbo] [--no-warning]\n" +
33        "  [--multi-dex [--main-dex-list=<file> [--minimal-main-dex]]\n" +
34        "  [--input-list=<file>] [--min-sdk-version=<n>]\n" +
35        "  [<file>.class | <file>.{zip,jar,apk} | <directory>] ...\n" +
36        "    Convert a set of classfiles into a dex file, optionally embedded in a\n" +
37        "    jar/zip. Output name must end with one of: .dex .jar .zip .apk or be a\n" +
38        "    directory.\n" +
39        "    Positions options: none, important, lines.\n" +
40        "    --multi-dex: allows to generate several dex files if needed. This option is\n" +
41        "    exclusive with --incremental, causes --num-threads to be ignored and only\n" +
42        "    supports folder or archive output.\n" +
43        "    --main-dex-list=<file>: <file> is a list of class file names, classes\n" +
44        "    defined by those class files are put in classes.dex.\n" +
45        "    --minimal-main-dex: only classes selected by --main-dex-list are to be put\n" +
46        "    in the main dex.\n" +
47        "    --input-list: <file> is a list of inputs.\n" +
48        "    Each line in <file> must end with one of: .class .jar .zip .apk or be a\n" +
49        "    directory.\n" +
50        "    --min-sdk-version=<n>: Enable dex file features that require at least sdk\n" +
51        "    version <n>.\n" +
52        "  dx --annotool --annotation=<class> [--element=<element types>]\n" +
53        "  [--print=<print types>]\n" +
54        "  dx --dump [--debug] [--strict] [--bytes] [--optimize]\n" +
55        "  [--basic-blocks | --rop-blocks | --ssa-blocks | --dot] [--ssa-step=<step>]\n" +
56        "  [--width=<n>] [<file>.class | <file>.txt] ...\n" +
57        "    Dump classfiles, or transformations thereof, in a human-oriented format.\n" +
58        "  dx --find-usages <file.dex> <declaring type> <member>\n" +
59        "    Find references and declarations to a field or method.\n" +
60        "    <declaring type> is a class name in internal form, like Ljava/lang/Object;\n" +
61        "    <member> is a field or method name, like hashCode.\n" +
62        "  dx -J<option> ... <arguments, in one of the above forms>\n" +
63        "    Pass VM-specific options to the virtual machine that runs dx.\n" +
64        "  dx --version\n" +
65        "    Print the version of this tool (" + Version.VERSION + ").\n" +
66        "  dx --help\n" +
67        "    Print this message.";
68
69    /**
70     * This class is uninstantiable.
71     */
72    private Main() {
73        // This space intentionally left blank.
74    }
75
76    /**
77     * Run!
78     */
79    public static void main(String[] args) {
80        boolean gotCmd = false;
81        boolean showUsage = false;
82
83        try {
84            for (int i = 0; i < args.length; i++) {
85                String arg = args[i];
86                if (arg.equals("--") || !arg.startsWith("--")) {
87                    gotCmd = false;
88                    showUsage = true;
89                    break;
90                }
91
92                gotCmd = true;
93                if (arg.equals("--dex")) {
94                    com.android.dx.command.dexer.Main.main(without(args, i));
95                    break;
96                } else if (arg.equals("--dump")) {
97                    com.android.dx.command.dump.Main.main(without(args, i));
98                    break;
99                } else if (arg.equals("--annotool")) {
100                    com.android.dx.command.annotool.Main.main(
101                            without(args, i));
102                    break;
103                } else if (arg.equals("--find-usages")) {
104                    com.android.dx.command.findusages.Main.main(without(args, i));
105                    break;
106                } else if (arg.equals("--version")) {
107                    version();
108                    break;
109                } else if (arg.equals("--help")) {
110                    showUsage = true;
111                    break;
112                } else {
113                    gotCmd = false;
114                }
115            }
116        } catch (UsageException ex) {
117            showUsage = true;
118        } catch (RuntimeException ex) {
119            System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
120            ex.printStackTrace();
121            System.exit(2);
122        } catch (Throwable ex) {
123            System.err.println("\nUNEXPECTED TOP-LEVEL ERROR:");
124            ex.printStackTrace();
125            if ((ex instanceof NoClassDefFoundError)
126                    || (ex instanceof NoSuchMethodError)) {
127                System.err.println(
128                        "Note: You may be using an incompatible " +
129                        "virtual machine or class library.\n" +
130                        "(This program is known to be incompatible " +
131                        "with recent releases of GCJ.)");
132            }
133            System.exit(3);
134        }
135
136        if (!gotCmd) {
137            System.err.println("error: no command specified");
138            showUsage = true;
139        }
140
141        if (showUsage) {
142            usage();
143            System.exit(1);
144        }
145    }
146
147    /**
148     * Prints the version message.
149     */
150    private static void version() {
151        System.err.println("dx version " + Version.VERSION);
152        System.exit(0);
153    }
154
155    /**
156     * Prints the usage message.
157     */
158    private static void usage() {
159        System.err.println(USAGE_MESSAGE);
160    }
161
162    /**
163     * Returns a copy of the given args array, but without the indicated
164     * element.
165     *
166     * @param orig {@code non-null;} original array
167     * @param n which element to omit
168     * @return {@code non-null;} new array
169     */
170    private static String[] without(String[] orig, int n) {
171        int len = orig.length - 1;
172        String[] newa = new String[len];
173        System.arraycopy(orig, 0, newa, 0, n);
174        System.arraycopy(orig, n + 1, newa, n, len - n);
175        return newa;
176    }
177}
178