cbc/net/loveruby/cflat/compiler/Options.java

370 lines
13 KiB
Java

package net.loveruby.cflat.compiler;
import net.loveruby.cflat.parser.LibraryLoader;
import net.loveruby.cflat.type.TypeTable;
import net.loveruby.cflat.asm.*;
import net.loveruby.cflat.sysdep.*;
import net.loveruby.cflat.utils.ErrorHandler;
import net.loveruby.cflat.exception.*;
import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.Arrays;
import java.io.PrintStream;
class Options {
static Options parse(String[] args) {
Options opts = new Options();
opts.parseArgs(args);
return opts;
}
private CompilerMode mode;
private Platform platform = new X86Linux();
private String outputFileName;
private boolean verbose = false;
private LibraryLoader loader = new LibraryLoader();
private boolean debugParser = false;
private CodeGeneratorOptions genOptions = new CodeGeneratorOptions();
private AssemblerOptions asOptions = new AssemblerOptions();
private LinkerOptions ldOptions = new LinkerOptions();
private List<LdArg> ldArgs;
private List<SourceFile> sourceFiles;
CompilerMode mode() {
return mode;
}
boolean isAssembleRequired() {
return mode.requires(CompilerMode.Assemble);
}
boolean isLinkRequired() {
return mode.requires(CompilerMode.Link);
}
List<SourceFile> sourceFiles() {
return sourceFiles;
}
String asmFileNameOf(SourceFile src) {
if (outputFileName != null && mode == CompilerMode.Compile) {
return outputFileName;
}
return src.asmFileName();
}
String objFileNameOf(SourceFile src) {
if (outputFileName != null && mode == CompilerMode.Assemble) {
return outputFileName;
}
return src.objFileName();
}
String exeFileName() {
return linkedFileName("");
}
String soFileName() {
return linkedFileName(".so");
}
static private final String DEFAULT_LINKER_OUTPUT = "a.out";
private String linkedFileName(String newExt) {
if (outputFileName != null) {
return outputFileName;
}
if (sourceFiles.size() == 1) {
return sourceFiles.get(0).linkedFileName(newExt);
}
else {
return DEFAULT_LINKER_OUTPUT;
}
}
String outputFileName() {
return this.outputFileName;
}
boolean isVerboseMode() {
return this.verbose;
}
boolean doesDebugParser() {
return this.debugParser;
}
LibraryLoader loader() {
return this.loader;
}
TypeTable typeTable() {
return platform.typeTable();
}
CodeGenerator codeGenerator(ErrorHandler h) {
return platform.codeGenerator(genOptions, h);
}
Assembler assembler(ErrorHandler h) {
return platform.assembler(h);
}
AssemblerOptions asOptions() {
return asOptions;
}
Linker linker(ErrorHandler h) {
return platform.linker(h);
}
LinkerOptions ldOptions() {
return ldOptions;
}
List<String> ldArgs() {
List<String> result = new ArrayList<String>();
for (LdArg arg : ldArgs) {
result.add(arg.toString());
}
return result;
}
boolean isGeneratingSharedLibrary() {
return ldOptions.generatingSharedLibrary;
}
void parseArgs(String[] origArgs) {
sourceFiles = new ArrayList<SourceFile>();
ldArgs = new ArrayList<LdArg>();
ListIterator<String> args = Arrays.asList(origArgs).listIterator();
while (args.hasNext()) {
String arg = args.next();
if (arg.equals("--")) {
// "--" Stops command line processing
break;
}
else if (arg.startsWith("-")) {
if (CompilerMode.isModeOption(arg)) {
if (mode != null) {
parseError(mode.toOption() + " option and "
+ arg + " option is exclusive");
}
mode = CompilerMode.fromOption(arg);
}
else if (arg.startsWith("-I")) {
loader.addLoadPath(getOptArg(arg, args));
}
else if (arg.equals("--debug-parser")) {
debugParser = true;
}
else if (arg.startsWith("-o")) {
outputFileName = getOptArg(arg, args);
}
else if (arg.equals("-fpic")
|| arg.equals("-fPIC")) {
genOptions.generatePIC();
}
else if (arg.equals("-fpie")
|| arg.equals("-fPIE")) {
genOptions.generatePIE();
}
else if (arg.startsWith("-O")) {
String type = arg.substring(2);
if (! type.matches("^([0123s]|)$")) {
parseError("unknown optimization switch: " + arg);
}
genOptions.setOptimizationLevel(type.equals("0") ? 0 : 1);
}
else if (arg.equals("--verbose-asm")
|| arg.equals("-fverbose-asm")) {
genOptions.generateVerboseAsm();
}
else if (arg.startsWith("-Wa,")) {
for (String a : parseCommaSeparatedOptions(arg)) {
asOptions.addArg(a);
}
}
else if (arg.equals("-Xassembler")) {
asOptions.addArg(nextArg(arg, args));
}
else if (arg.equals("-static")) {
addLdArg(arg);
}
else if (arg.equals("-shared")) {
ldOptions.generatingSharedLibrary = true;
}
else if (arg.equals("-pie")) {
ldOptions.generatingPIE = true;
}
else if (arg.equals("--readonly-plt")) {
addLdArg("-z");
addLdArg("combreloc");
addLdArg("-z");
addLdArg("now");
addLdArg("-z");
addLdArg("relro");
}
else if (arg.startsWith("-L")) {
addLdArg("-L" + getOptArg(arg, args));
}
else if (arg.startsWith("-l")) {
addLdArg("-l" + getOptArg(arg, args));
}
else if (arg.equals("-nostartfiles")) {
ldOptions.noStartFiles = true;
}
else if (arg.equals("-nodefaultlibs")) {
ldOptions.noDefaultLibs = true;
}
else if (arg.equals("-nostdlib")) {
ldOptions.noStartFiles = true;
ldOptions.noDefaultLibs = true;
}
else if (arg.startsWith("-Wl,")) {
for (String opt : parseCommaSeparatedOptions(arg)) {
addLdArg(opt);
}
}
else if (arg.equals("-Xlinker")) {
addLdArg(nextArg(arg, args));
}
else if (arg.equals("-v")) {
verbose = true;
asOptions.verbose = true;
ldOptions.verbose = true;
}
else if (arg.equals("--version")) {
System.out.printf("%s version %s",
Compiler.ProgramName, Compiler.Version);
System.exit(0);
}
else if (arg.equals("--help")) {
printUsage(System.out);
System.exit(0);
}
else {
parseError("unknown option: " + arg);
}
}
else {
ldArgs.add(new SourceFile(arg));
}
}
// args has more arguments when "--" is appeared.
while (args.hasNext()) {
ldArgs.add(new SourceFile(args.next()));
}
if (mode == null) {
mode = CompilerMode.Link;
}
sourceFiles = selectSourceFiles(ldArgs);
if (sourceFiles.isEmpty()) {
parseError("no input file");
}
if (outputFileName != null
&& sourceFiles.size() > 1
&& ! isLinkRequired()) {
parseError("-o option requires only 1 input (except linking)");
}
}
private void parseError(String msg) {
throw new OptionParseError(msg);
}
private void addLdArg(String arg) {
ldArgs.add(new LdOption(arg));
}
private List<SourceFile> selectSourceFiles(List<LdArg> args) {
List<SourceFile> result = new ArrayList<SourceFile>();
for (LdArg arg : args) {
if (arg.isSourceFile()) {
result.add((SourceFile)arg);
}
}
return result;
}
private String getOptArg(String opt, ListIterator<String> args) {
String path = opt.substring(2);
if (path.length() != 0) { // -Ipath
return path;
}
else { // -I path
return nextArg(opt, args);
}
}
private String nextArg(String opt, ListIterator<String> args) {
if (! args.hasNext()) {
parseError("missing argument for " + opt);
}
return args.next();
}
/** "-Wl,-rpath,/usr/local/lib" -> ["-rpath", "/usr/local/lib"] */
private List<String> parseCommaSeparatedOptions(String opt) {
List<String> opts = Arrays.asList(opt.split(","));
opts.remove(0); // remove "-Wl" etc.
if (opts.isEmpty()) {
parseError("missing argument for " + opt);
}
return opts;
}
void printUsage(PrintStream out) {
out.println("Usage: cbc [options] file...");
out.println("Global Options:");
out.println(" --check-syntax Checks syntax and quit.");
out.println(" --dump-tokens Dumps tokens and quit.");
// --dump-stmt is a hidden option.
// --dump-expr is a hidden option.
out.println(" --dump-ast Dumps AST and quit.");
out.println(" --dump-semantic Dumps AST after semantic check and quit.");
// --dump-reference is a hidden option.
out.println(" --dump-ir Dumps IR and quit.");
out.println(" --dump-asm Prints an assembly source and quit.");
out.println(" -S Generates an assembly file and quit.");
out.println(" -c Generates an object file and quit.");
out.println(" -o PATH Places output in file PATH.");
out.println(" -v Turn on verbose mode.");
out.println(" --version Shows compiler version and quit.");
out.println(" --help Prints this message and quit.");
out.println("");
out.println("Parser Options:");
out.println(" -I PATH Adds PATH as import file directory.");
out.println(" --debug-parser Dumps parsing process.");
out.println("");
out.println("Code Generator Options:");
out.println(" -O Enables optimization.");
out.println(" -O1, -O2, -O3 Equivalent to -O.");
out.println(" -Os Equivalent to -O.");
out.println(" -O0 Disables optimization (default).");
out.println(" -fPIC Generates PIC assembly.");
out.println(" -fpic Equivalent to -fPIC.");
out.println(" -fPIE Generates PIE assembly.");
out.println(" -fpie Equivalent to -fPIE.");
out.println(" --verbose-asm Generate assembly with verbose comments.");
out.println("");
out.println("Assembler Options:");
out.println(" -Wa,OPT Passes OPT to the assembler (as).");
out.println(" -Xassembler OPT Passes OPT to the assembler (as).");
out.println("");
out.println("Linker Options:");
out.println(" -l LIB Links the library LIB.");
out.println(" -L PATH Adds PATH as library directory.");
out.println(" -shared Generates shared library rather than executable.");
out.println(" -static Linkes only with static libraries.");
out.println(" -pie Generates PIE.");
out.println(" --readonly-plt Generates read-only PLT.");
out.println(" -nostartfiles Do not link startup files.");
out.println(" -nodefaultlibs Do not link default libraries.");
out.println(" -nostdlib Enables -nostartfiles and -nodefaultlibs.");
out.println(" -Wl,OPT Passes OPT to the linker (ld).");
out.println(" -Xlinker OPT Passes OPT to the linker (ld).");
}
}