main.ha (4469B)
1 // SPDX-License-Identifier: GPL-3.0-only 2 // (c) Hare authors <https://harelang.org> 3 4 use cmd::hare::build; 5 use fmt; 6 use fs; 7 use getopt; 8 use hare::module; 9 use hare::parse; 10 use io; 11 use os; 12 use os::exec; 13 use path; 14 use strconv; 15 16 def VERSION: str = "unknown"; 17 def HAREPATH: str = "."; 18 19 const help: []getopt::help = [ 20 "compile, run, and test Hare programs", 21 "<subcommand>", 22 "args...", 23 ("build", [ 24 "compiles a Hare program or module", 25 // XXX: once cross-compiling to different targets (linux, 26 // freebsd, etc) is supported, we can probably merge -F with it 27 ('F', "build for freestanding environment"), 28 ('q', "build silently"), 29 ('v', "print executed commands (specify twice to print arguments)"), 30 ('a', "arch", "set target architecture"), 31 ('D', "ident[:type]=value", "define a constant"), 32 ('j', "jobs", "set parallelism for build"), 33 ('L', "libdir", "add directory to linker library search path"), 34 ('l', "libname", "link with a system library"), 35 ('N', "namespace", "override namespace for module"), 36 ('o', "path", "set output file name"), 37 ('R', "build in release mode"), 38 ('T', "tagset", "set/unset build tags"), 39 ('t', "type", "build type (s/o/bin)"), 40 "[path]" 41 ]: []getopt::help), 42 ("cache", [ 43 "manages the build cache", 44 ('c', "clears the cache"), 45 ]: []getopt::help), 46 ("deps", [ 47 "prints dependency information for a Hare program", 48 ('d', "print dot syntax for use with graphviz"), 49 ('T', "tagset", "set/unset build tags"), 50 "[path|module]", 51 ]: []getopt::help), 52 ("run", [ 53 "compiles and runs a Hare program or module", 54 ('q', "build silently"), 55 ('v', "print executed commands (specify twice to print arguments)"), 56 ('a', "arch", "set target architecture"), 57 ('D', "ident[:type]=value", "define a constant"), 58 ('j', "jobs", "set parallelism for build"), 59 ('L', "libdir", "add directory to linker library search path"), 60 ('l', "libname", "link with a system library"), 61 ('R', "build in release mode"), 62 ('T', "tagset", "set/unset build tags"), 63 "[path [args...]]", 64 ]: []getopt::help), 65 ("test", [ 66 "compiles and runs tests for Hare code", 67 ('q', "build silently"), 68 ('v', "print executed commands (specify twice to print arguments)"), 69 ('a', "arch", "set target architecture"), 70 ('D', "ident[:type]=value", "define a constant"), 71 ('j', "jobs", "set parallelism for build"), 72 ('L', "libdir", "add directory to linker library search path"), 73 ('l', "libname", "link with a system library"), 74 ('o', "path", "set output file name"), 75 ('R', "build in release mode"), 76 ('T', "tagset", "set/unset build tags"), 77 "[path]" 78 ]: []getopt::help), 79 ("version", [ 80 "provides version information for the Hare environment", 81 ('v', "print build parameters"), 82 ]: []getopt::help), 83 ]; 84 85 export fn main() void = { 86 const cmd = getopt::parse(os::args, help...); 87 defer getopt::finish(&cmd); 88 match (cmd.subcmd) { 89 case void => 90 getopt::printusage(os::stderr, os::args[0], help...)!; 91 os::exit(os::status::FAILURE); 92 case let subcmd: (str, *getopt::command) => 93 const task = switch (subcmd.0) { 94 case "build", "run", "test" => 95 yield &build; 96 case "cache" => 97 yield &cache; 98 case "deps" => 99 yield &deps; 100 case "version" => 101 yield &version; 102 case => abort(); 103 }; 104 match (task(subcmd.0, subcmd.1)) { 105 case void => void; 106 case let e: exec::error => 107 fmt::fatal("Error:", exec::strerror(e)); 108 case let e: fs::error => 109 fmt::fatal("Error:", fs::strerror(e)); 110 case let e: io::error => 111 fmt::fatal("Error:", io::strerror(e)); 112 case let e: module::error => 113 fmt::fatal("Error:", module::strerror(e)); 114 case let e: path::error => 115 fmt::fatal("Error:", path::strerror(e)); 116 case let e: parse::error => 117 fmt::fatal("Error:", parse::strerror(e)); 118 case let e: strconv::error => 119 fmt::fatal("Error:", strconv::strerror(e)); 120 case let e: unknown_arch => 121 fmt::fatalf("Error: Unknown arch: {}", e); 122 case let e: build::unknown_platform => 123 fmt::fatalf("Error: Unknown platform: {}", e); 124 case unknown_output => 125 fmt::fatal("Error: Can't guess output in root directory"); 126 case let e: unknown_type => 127 fmt::fatalf("Error: Unknown build type: {}", e); 128 case let e: output_exists => 129 fmt::fatalf("Error: Output path '{}' already exists, but isn't an executable file", 130 e); 131 case let e: output_failed => 132 fmt::fatalf("Error: Could not open output '{}': {}", 133 e.0, fs::strerror(e.1)); 134 case let e: invalid_namespace => 135 fmt::fatalf("Error: Invalid namespace: {}", e); 136 }; 137 }; 138 };