int compiler_main(int argc, char* argv[]) { init_colors(); init_symbols(syms); po::options_description common("common options"); common.add_options() ("help", "print help message") ("version", "print version message") ("input,i", po::value<String_seq>(), "specify build inputs") ("output,o", po::value<String>(), "specify the build output file") ("keep,k", "keep temporary files"); // FIXME: These really define the compilation mode. // Here are some rules: // // -s implies -c // -c implies no linking // // -b [archive|library|program] // po::options_description compiler("compile options"); compiler.add_options() ("assemble,s", "compile to native assembly") ("compile,c", "compile but do not link") ("target,t", po::value<String>()->default_value("program"), "produce an archive, module, or program"); po::positional_options_description pos; pos.add("input", -1); po::options_description all; all.add(common) .add(compiler); // Parse command line options. Config conf; po::variables_map vm; try { po::store( po::command_line_parser(argc, argv) .options(all) .positional(pos) .run(), vm); po::notify(vm); } catch(std::exception& err) { std::cerr << "error: " << err.what() << "\n\n"; usage(std::cerr, all); return -1; } // Check for obvious flags first. if (vm.count("help")) { usage(std::cout, all); return 0; } if (vm.count ("version")) { // TODO: Generate the version number from the build. std::cout << "beaker v0.0" << '\n'; return 0; } // Check options. if (vm.count("compile")) conf.compile = true; if (vm.count("assemble")) { conf.assemble = true; conf.compile = true; } if (vm.count("target")) { String t = vm["target"].as<String>(); if (t == "program") { conf.target = program_tgt; } else if (t == "module") { conf.target = module_tgt; } else { std::cerr << "error: invalid build target\n"; usage(std::cerr, all); return -1; } } // Validate the input files. if (!vm.count("input")) { std::cerr << "error: no input files given\n"; usage(std::cerr, all); return -1; } Path_seq inputs; for (String const& s : vm["input"].as<String_seq>()) inputs.push_back(s); // Look for an output file. If not given, assume that // the end result is going to be a native binary. Note // that this is the end goal for inputs of any variety. String output; if (!vm.count("output")) { // TODO: This should depend on the compilation mode. output = "a.out"; } else { output = vm["output"].as<String>(); } // Parse all of the input files into the translation module. // // FIXME: We should collect a set of output files from // parsing since we could potentially pass .ll/.bc/.s/.o // files to the next phase of transdlation. // // FIXME: Clean up temporary files. Path ir = to_ir_file(output); if (!parse(inputs, ir, conf)) return -1; Path as = to_asm_file(output); if (!lower(ir, as, conf)) return -1; if (conf.assemble) return 0; Path obj = to_object_file(output); if (!assemble(as, obj, conf)) return -1; if (conf.compile) return 0; // Generate the linked result. if (conf.target == program_tgt) return executable({obj}, output, conf); if (conf.target == module_tgt) return module({obj}, output, conf); return 0; }
int translator_main(int argc, char* argv[]) { // Intitialize various subsystems. // // TODO: Always initialize parsing components? init_colors(); init_symbols(syms); // TODO: Support extraction to other intermediate formats? // Maybe C, for example? Gimple? // // Note that an introspection tool would have a considerably // different interface. po::options_description common("options"); common.add_options() ("help", "print help message") ("version", "print version message") ("input,i", po::value<String>(), "specify the input file") ("output,o", po::value<String>(), "specify the output file") ("keep,k", "keep temporary files"); po::positional_options_description pos; pos.add("input", 1); po::options_description all; all.add(common); // Parse command line options. po::variables_map vm; try { po::store( po::command_line_parser(argc, argv) .options(all) .positional(pos) .run(), vm); po::notify(vm); } catch(std::exception& err) { std::cerr << "error: " << err.what() << "\n\n"; usage(std::cerr, all); return -1; } // Check for obvious flags first. if (vm.count("help")) { usage(std::cout, all); return 0; } if (vm.count ("version")) { // TODO: Generate the version number from the // build. std::cout << "beaker v0.0" << '\n'; return 0; } // Validate the input. if (!vm.count("input")) { std::cerr << "error: no input file given\n"; usage(std::cerr, all); return -1; } Path input = vm["input"].as<String>(); // Look for an output file. If not given, the default // will be to produce .asm. Note that the default output // file is generated in the current directory. Path output; if (!vm.count("output")) output = to_asm_file(input.filename()); else output = vm["output"].as<String>(); // Compile the input into LLVM. Path temp; if (get_file_kind(input) == beaker_file) { temp = to_ir_file(input.filename()); if (!compile(input, temp)) return -1; input = temp; } // Lower llvm input to assembly. if (!lower(input, output)) return -1; // Remove the temporary file. if (!temp.empty() && !vm.count("keep")) fs::remove(temp); return 0; }