javac编译选项-Option

前言

javac有很多选项,在jdk1.8中,通过javac -help 可以看到如下信息的输出:

javac编译选项-Option_第1张图片

关于这个option所对应的类就是Option.接下来我们就来看一下这个类

解析

Option类是一个枚举,代表javac的选项.处理命令行选项的特定选项是通过按顺序搜索此枚举的成员来标识的,找到第一个匹配的.

其中,Option又分为OptionKind,OptionGroup,ChoiceKind不同的类型.这三种也是枚举,定义如下:

OptionKind

该类代表命令行参数的类型,通过-help 和 -X来使用的.

public enum OptionKind {
    // 标准的选项,被-help所文档化
    STANDARD,
    // 扩展的选项,被-X所文档化
    EXTENDED,
    // 隐藏的选项,没有被文档化
    HIDDEN,
}

OptionGroup

OptionGroup --> option的组别,这决定了该option在什么情况下是可被接受的.

enum OptionGroup {
    // 基本的option,可以通过命令行或者编译器api来使用
    BASIC,
	 // 一个javac 标准的JavaFileManager的选项,其他的file manager可能不支持这个选项
    FILEMANAGER,
   	// 一个请求信息的命令行选项,比如 -help
    INFO,
    // 一个代表文件或者类名的命令行选项
    OPERAND
}

ChoiceKind

ChoiceKind --> 关于 选择的类型.

    enum ChoiceKind {
        // 在可供选择的选项中有确定的值
        ONEOF,
        // 选项值需要都存在
        ANYOF
    }

举例说明如下:

-Xpkginfo: 这个编译选项是处理package-info 文件的,该选项的值是{always,legacy,nonempty} 中的任意一个,此时ChoiceKind为ONEOF.

-g: 这个编译选项是生成某些调试信息(lines,vars,source). 这个选项只能是(lines,vars,source),不能是其他的值.如果传入的参数值为 -g:vars,-g:xx,则最终不会进行编译

关于这两个选项的区别,可以通过查看源码的方式来观察:

	// com.sun.tools.javac.main.Option.matches(String)
    public boolean matches(String option) {
        if (!hasSuffix)
            return option.equals(text);

        if (!option.startsWith(text))
            return false;

        if (choices != null) {
            String arg = option.substring(text.length());
            if (choiceKind == ChoiceKind.ONEOF)
                return choices.keySet().contains(arg);
            else {
                for (String a: arg.split(",+")) {
                    if (!choices.keySet().contains(a))
                        return false;
                }
            }
        }

        return true;
    }

可以看到,如果choiceKind为ONEOF,则只要在选项集中有对应的值即可,而ANYOF,则要求选项值需要在选项集中都存在.

Option的字段,构造函数如下:

    public final String text; // 选项所对应的文本

    final OptionKind kind; // 选项的类型

    final OptionGroup group; // 选项的组别

    final String argsNameKey; // 有关参数的文档key

    final String descrKey; // 该选项的说明所对应的key

    final boolean hasSuffix; // 该选项是否有后缀. 当选择是=或者:结尾的,则认为该选项是有后缀的,如: (-foo=bar or -foo:bar)

    final ChoiceKind choiceKind; // 选择的类型

    final Map choices; // 选项的值集合


    Option(String text, String descrKey,
            OptionKind kind, OptionGroup group) {
        this(text, null, descrKey, kind, group, null, null, false);
    }

    Option(String text, String argsNameKey, String descrKey,
            OptionKind kind, OptionGroup group) {
        this(text, argsNameKey, descrKey, kind, group, null, null, false);
    }

    Option(String text, String argsNameKey, String descrKey,
            OptionKind kind, OptionGroup group, boolean doHasSuffix) {
        this(text, argsNameKey, descrKey, kind, group, null, null, doHasSuffix);
    }

    Option(String text, String descrKey,
            OptionKind kind, OptionGroup group,
            ChoiceKind choiceKind, Map choices) {
        this(text, null, descrKey, kind, group, choiceKind, choices, false);
    }

    Option(String text, String descrKey,
            OptionKind kind, OptionGroup group,
            ChoiceKind choiceKind, String... choices) {
        this(text, null, descrKey, kind, group, choiceKind,
                createChoices(choices), false);
    }
    // where
        private static Map createChoices(String... choices) {
            Map map = new LinkedHashMap();
            for (String c: choices)
                map.put(c, false);
            return map;
        }

    private Option(String text, String argsNameKey, String descrKey,
            OptionKind kind, OptionGroup group,
            ChoiceKind choiceKind, Map choices,
            boolean doHasSuffix) {
        this.text = text;
        this.argsNameKey = argsNameKey;
        this.descrKey = descrKey;
        this.kind = kind;
        this.group = group;
        this.choiceKind = choiceKind;
        this.choices = choices;
        char lastChar = text.charAt(text.length()-1);
        this.hasSuffix = doHasSuffix || lastChar == ':' || lastChar == '=';
    }

下面举例来说明 text,argsNameKey,descrKey的作用,以-cp选项为例:

CP("-cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER) {
    @Override
    public boolean process(OptionHelper helper, String option, String arg) {
        return super.process(helper, "-classpath", arg);
    }
}

可以看到,-cp对应的是CP,其text = -cp, argsNameKey = opt.arg.path, descrKey = opt.classpath.

这里补充一点,javac中的任何信息的输出都是本地化了的,其对应的资源文件在com/sun/tools/javac/resources下,如图:

javac编译选项-Option_第2张图片

当我们输入javac -help时,对于-cp,输出的内容如下:

-cp <路径> 指定查找用户类文件和注释处理程序的位置

那么这是如何实现的呢?

首先是输出CP的text,然后在javac_zh_CN.properties 中获得javac.opt.arg.path 对应的value,当前为 javac.opt.arg.path=<路径>, 然后再获得javac.opt.classpath的value,当前为 javac.opt.classpath=指定查找用户类文件和注释处理程序的位置.

这部分所对应的源码如下:

	// com.sun.tools.javac.main.Option.helpSynopsis(Log)
    private String helpSynopsis(Log log) {
        StringBuilder sb = new StringBuilder();
        sb.append(text);
        if (argsNameKey == null) {
            if (choices != null) {
                String sep = "{";
                for (Map.Entry e: choices.entrySet()) {
                    if (!e.getValue()) {
                        sb.append(sep);
                        sb.append(e.getKey());
                        sep = ",";
                    }
                }
                sb.append("}");
            }
        } else {
            if (!hasSuffix)
                sb.append(" ");
            sb.append(log.localize(PrefixKind.JAVAC, argsNameKey));

        }

        return sb.toString();
    }

在Option中还定义了一个process函数,是用来处理编译器选项的.如下:

public boolean process(OptionHelper helper, String option) {
    if (hasSuffix)
        return process(helper, text, option.substring(text.length()));
    else
        return process(helper, option, option);
}

public boolean process(OptionHelper helper, String option, String arg) {
    if (choices != null) {
        if (choiceKind == ChoiceKind.ONEOF) {
            // some clients like to see just one of option+choice set
            for (String s: choices.keySet())
                helper.remove(option + s);
            String opt = option + arg;
            helper.put(opt, opt);
            // some clients like to see option (without trailing ":")
            // set to arg
            String nm = option.substring(0, option.length() - 1);
            helper.put(nm, arg);
        } else {
            // set option+word for each word in arg
            for (String a: arg.split(",+")) {
                String opt = option + a;
                helper.put(opt, opt);
            }
        }
    }
    helper.put(option, arg);
    return false;
}

经过这个函数的处理,就将选项值加入到了Main中的OptionHelper.关于这部分的代码我们后续在讲解.

总结

现通过表格的方式,将Option的所有选项列出:

选项值 argsNameKey descrKey 类型 组别 选择类型 选项值集 是否有后缀 作用
-g null javac.opt.g STANDARD BASIC null null false 生成所有调试信息
-g:none null javac.opt.g.none STANDARD BASIC null null false 不生成任何调试信息
-g: null javac.opt.g.lines.vars.source STANDARD BASIC ANYOF {lines,vars,source} true 只生成某些调试信息
-Xlint: null javac.opt.Xlint.suboptlist EXTENDED BASIC ANYOF LintCategory对应的枚举值 true 启用或禁用特定的警告
-Xdoclint: null javac.opt.Xdoclint EXTENDED BASIC null null false 为javadoc注释中的问题启用建议的检查
-Xdoclint: javac.opt.Xdoclint.subopts javac.opt.Xdoclint.custom EXTENDED BASIC null null false 为 javadoc 注释中的问题启用或禁用特定检查
-nowarn null javac.opt.nowarn STANDARD BASIC null null false 不生成任何警告(保留命令行向后兼容性)
-verbose null javac.opt.verbose STANDARD BASIC null null false 输出有关编译器正在执行的操作的消息
-deprecation null javac.opt.deprecation STANDARD BASIC null null false 输出使用已过时的 API 的源位置(保留命令行向后兼容性)
-classpath javac.opt.arg.path javac.opt.classpath STANDARD FILEMANAGER null null false 指定查找用户类文件和注释处理程序的位置
-cp javac.opt.arg.path javac.opt.classpath STANDARD FILEMANAGER null null false 指定查找用户类文件和注释处理程序的位置(这个选项是-classpath的简写)
-sourcepath javac.opt.arg.path javac.opt.sourcepath STANDARD FILEMANAGER null null false 指定查找输入源文件的位置
-bootclasspath javac.opt.arg.path javac.opt.bootclasspath STANDARD FILEMANAGER null null false 覆盖引导类文件的位置
-Xbootclasspath/p: javac.opt.arg.path javac.opt.Xbootclasspath.p EXTENDED FILEMANAGER null null false 置于引导类路径之前
-Xbootclasspath/a: javac.opt.arg.path javac.opt.Xbootclasspath.a EXTENDED FILEMANAGER null null false 置于引导类路径之后
-Xbootclasspath: javac.opt.arg.path javac.opt.bootclasspath EXTENDED FILEMANAGER null null false 覆盖引导类文件的位置(这个选项是和-bootclasspath一样的)
-extdirs javac.opt.arg.dirs javac.opt.extdirs STANDARD FILEMANAGER null null false 覆盖所安装扩展的位置
-Djava.ext.dirs= javac.opt.arg.dirs javac.opt.extdirs EXTENDED FILEMANAGER null null false 覆盖所安装扩展的位置(和-extdirs一样)
-proc: null javac.opt.proc.none.only STANDARD BASIC ONEOF none,only false 控制是否执行注释处理和/或编译
-processor javac.opt.arg.class.list javac.opt.processor STANDARD BASIC null null false 要运行的注释处理程序的名称; 绕过默认的搜索进程
-processorpath javac.opt.arg.path javac.opt.processorpath STANDARD FILEMANAGER null null false 指定查找注释处理程序的位置
-parameters null javac.opt.parameters STANDARD BASIC null null false 生成元数据以用于方法参数的反射
-d javac.opt.arg.directory javac.opt.d STANDARD FILEMANAGER null null false 指定放置生成的类文件的位置
-s javac.opt.arg.directory javac.opt.sourceDest STANDARD FILEMANAGER null null false 指定放置生成的源文件的位置
-h javac.opt.arg.directory javac.opt.headerDest STANDARD FILEMANAGER null null false 指定放置生成的本机标头文件的位置
-implicit: null javac.opt.implicit STANDARD BASIC ONEOF none,class false 指定是否为隐式引用文件生成类文件
-encoding javac.opt.arg.encoding javac.opt.encoding STANDARD FILEMANAGER null null false 指定源文件使用的字符编码
-source javac.opt.arg.release javac.opt.source STANDARD BASIC null null false 提供与指定发行版的源兼容性
-target javac.opt.arg.release javac.opt.target STANDARD BASIC null null false 生成特定 VM 版本的类文件
-profile javac.opt.arg.profile javac.opt.profile STANDARD BASIC null null false 确保使用的 API 在指定的配置文件中可用
-version null javac.opt.version STANDARD INFO null null false 输出版本信息
-fullversion null null HIDDEN INFO null null false 输出版本信息
-XDdiags= null null HIDDEN INFO null null false 这是编译器选项的后门
-help null javac.opt.help STANDARD INFO null null false 输出标准选项的提要
-A javac.opt.arg.key.equals.value javac.opt.A STANDARD BASIC null null true 传递给注释处理器的选项
-X null javac.opt.X STANDARD BASIC null null false 输出非标准选项的提要
-J javac.opt.arg.flag javac.opt.J STANDARD BASIC null null true 直接将 <标记> 传递给运行时系统,如果在命令行中使用,则抛出异常
-moreinfo null null HIDDEN BASIC null null false 输出更多的信息
-Werror null javac.opt.Werror STANDARD BASIC null null false 出现警告时终止编译
-prompt null null HIDDEN BASIC null null false
-prompt null null HIDDEN BASIC null null false 每次错误后提示
-doe null null HIDDEN BASIC null null false 在发生错误时dump堆栈信息
-printsource null null HIDDEN BASIC null null false 在类型擦除后输出source
-warnunchecked null null HIDDEN BASIC null null false 在对泛型进行未检查的操作时发出警告信息
-Xmaxerrs javac.opt.arg.number javac.opt.maxerrs EXTENDED BASIC null null false 设置要输出的错误的最大数目
-Xmaxwarns javac.opt.arg.number javac.opt.maxwarns EXTENDED BASIC null null false 设置要输出的警告的最大数目
-Xstdout javac.opt.arg.file javac.opt.Xstdout EXTENDED INFO null null false 重定向标准输出
-Xprint null javac.opt.print EXTENDED BASIC null null false 输出指定类型的文本表示
-XprintRounds null javac.opt.printRounds EXTENDED BASIC null null false 输出有关注释处理循环的信息
-XprintProcessorInfo null javac.opt.printProcessorInfo EXTENDED BASIC null null false 输出有关请求处理程序处理哪些注释的信息
-Xprefer null javac.opt.prefer EXTENDED BASIC ONEOF source,newer false 指定读取文件, 当同时找到隐式编译类的源文件和类文件时
-Xpkginfo: null javac.opt.pkginfo EXTENDED BASIC ONEOF always,legacy,nonempty false 指定读取文件, 当同时找到隐式编译类的源文件和类文件时
-O null null HIDDEN BASIC null null false 不进行任何操作,后向兼容性
-Xjcov null null HIDDEN BASIC null null false 生成jcov(代码覆盖)所需要的table
-Xplugin: javac.opt.arg.plugin javac.opt.plugin EXTENDED BASIC null null false 要运行的插件的名称和可选参数
-Xdiags: null javac.opt.diags EXTENDED BASIC ONEOF compact,verbose false 选择诊断模式
-XD null null HIDDEN BASIC null null false 这是编译器选项的后门,-XDx=y 将选项x的值设置为y
@ javac.opt.arg.file javac.opt.arg.file STANDARD INFO null null true 从文件读取选项和文件名,由CommandLine实现
sourcefile null null HIDDEN INFO null null false

你可能感兴趣的:(javac,javac,javac,编译器,源码)