| ... | @@ -1,613 +1,165 @@ | ... | @@ -1,613 +1,165 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | | |
| 3 | const io = std.io; | | |
| 4 | const os = std.os; | | |
| 5 | const heap = std.heap; | | |
| 6 | const warn = std.debug.warn; | | |
| 7 | const assert = std.debug.assert; | | |
| 8 | const target = @import("target.zig"); | | |
| 9 | const Target = target.Target; | | |
| 10 | const Module = @import("module.zig").Module; | | |
| 11 | const ErrColor = Module.ErrColor; | | |
| 12 | const Emit = Module.Emit; | | |
| 13 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 14 | const ArrayList = std.ArrayList; | | |
| 15 | const c = @import("c.zig"); | | |
| 16 | | 3 | |
| 17 | const default_zig_cache_name = "zig-cache"; | 4 | const os = std.os; |
| | 5 | const io = std.io; |
| | 6 | const mem = std.mem; |
| | 7 | const Allocator = mem.Allocator; |
| | 8 | const ArrayList = std.ArrayList; |
| | 9 | const Buffer = std.Buffer; |
| 18 | | 10 | |
| 19 | const Cmd = enum { | 11 | const arg = @import("arg.zig"); |
| 20 | None, | 12 | const c = @import("c.zig"); |
| 21 | Build, | 13 | const introspect = @import("introspect.zig"); |
| 22 | Test, | 14 | const Args = arg.Args; |
| 23 | Version, | 15 | const Flag = arg.Flag; |
| 24 | Zen, | 16 | const Module = @import("module.zig").Module; |
| 25 | TranslateC, | 17 | const Target = @import("target.zig").Target; |
| 26 | Targets, | 18 | |
| | 19 | var stderr: &io.OutStream(io.FileOutStream.Error) = undefined; |
| | 20 | var stdout: &io.OutStream(io.FileOutStream.Error) = undefined; |
| | 21 | |
| | 22 | const usage = |
| | 23 | \\usage: zig [command] [options] |
| | 24 | \\ |
| | 25 | \\Commands: |
| | 26 | \\ |
| | 27 | \\ build Build project from build.zig |
| | 28 | \\ build-exe [source] Create executable from source or object files |
| | 29 | \\ build-lib [source] Create library from source or object files |
| | 30 | \\ build-obj [source] Create object from source or assembly |
| | 31 | \\ fmt [source] Parse file and render in canonical zig format |
| | 32 | \\ run [source] Create executable and run immediately |
| | 33 | \\ targets List available compilation targets |
| | 34 | \\ test [source] Create and run a test build |
| | 35 | \\ translate-c [source] Convert c code to zig code |
| | 36 | \\ version Print version number and exit |
| | 37 | \\ zen Print zen of zig and exit |
| | 38 | \\ |
| | 39 | \\ |
| | 40 | ; |
| | 41 | |
| | 42 | const Command = struct { |
| | 43 | name: []const u8, |
| | 44 | exec: fn(&Allocator, []const []const u8) error!void, |
| 27 | }; | 45 | }; |
| 28 | | 46 | |
| 29 | fn badArgs(comptime format: []const u8, args: ...) noreturn { | | |
| 30 | var stderr = io.getStdErr() catch std.os.exit(1); | | |
| 31 | var stderr_stream_adapter = io.FileOutStream.init(&stderr); | | |
| 32 | const stderr_stream = &stderr_stream_adapter.stream; | | |
| 33 | stderr_stream.print(format ++ "\n\n", args) catch std.os.exit(1); | | |
| 34 | printUsage(&stderr_stream_adapter.stream) catch std.os.exit(1); | | |
| 35 | std.os.exit(1); | | |
| 36 | } | | |
| 37 | | | |
| 38 | pub fn main() !void { | 47 | pub fn main() !void { |
| 39 | const allocator = std.heap.c_allocator; | 48 | var allocator = std.heap.c_allocator; |
| | 49 | |
| | 50 | var stdout_file = try std.io.getStdOut(); |
| | 51 | var stdout_out_stream = std.io.FileOutStream.init(&stdout_file); |
| | 52 | stdout = &stdout_out_stream.stream; |
| | 53 | |
| | 54 | var stderr_file = try std.io.getStdErr(); |
| | 55 | var stderr_out_stream = std.io.FileOutStream.init(&stderr_file); |
| | 56 | stderr = &stderr_out_stream.stream; |
| 40 | | 57 | |
| 41 | const args = try os.argsAlloc(allocator); | 58 | const args = try os.argsAlloc(allocator); |
| 42 | defer os.argsFree(allocator, args); | 59 | defer os.argsFree(allocator, args); |
| 43 | | 60 | |
| 44 | if (args.len >= 2 and mem.eql(u8, args[1], "build")) { | 61 | if (args.len <= 1) { |
| 45 | return buildMain(allocator, args[2..]); | 62 | try stderr.write(usage); |
| 46 | } | 63 | os.exit(1); |
| 47 | | | |
| 48 | if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) { | | |
| 49 | return fmtMain(allocator, args[2..]); | | |
| 50 | } | | |
| 51 | | | |
| 52 | var cmd = Cmd.None; | | |
| 53 | var build_kind: Module.Kind = undefined; | | |
| 54 | var build_mode: builtin.Mode = builtin.Mode.Debug; | | |
| 55 | var color = ErrColor.Auto; | | |
| 56 | var emit_file_type = Emit.Binary; | | |
| 57 | | | |
| 58 | var strip = false; | | |
| 59 | var is_static = false; | | |
| 60 | var verbose_tokenize = false; | | |
| 61 | var verbose_ast_tree = false; | | |
| 62 | var verbose_ast_fmt = false; | | |
| 63 | var verbose_link = false; | | |
| 64 | var verbose_ir = false; | | |
| 65 | var verbose_llvm_ir = false; | | |
| 66 | var verbose_cimport = false; | | |
| 67 | var mwindows = false; | | |
| 68 | var mconsole = false; | | |
| 69 | var rdynamic = false; | | |
| 70 | var each_lib_rpath = false; | | |
| 71 | var timing_info = false; | | |
| 72 | | | |
| 73 | var in_file_arg: ?[]u8 = null; | | |
| 74 | var out_file: ?[]u8 = null; | | |
| 75 | var out_file_h: ?[]u8 = null; | | |
| 76 | var out_name_arg: ?[]u8 = null; | | |
| 77 | var libc_lib_dir_arg: ?[]u8 = null; | | |
| 78 | var libc_static_lib_dir_arg: ?[]u8 = null; | | |
| 79 | var libc_include_dir_arg: ?[]u8 = null; | | |
| 80 | var msvc_lib_dir_arg: ?[]u8 = null; | | |
| 81 | var kernel32_lib_dir_arg: ?[]u8 = null; | | |
| 82 | var zig_install_prefix: ?[]u8 = null; | | |
| 83 | var dynamic_linker_arg: ?[]u8 = null; | | |
| 84 | var cache_dir_arg: ?[]const u8 = null; | | |
| 85 | var target_arch: ?[]u8 = null; | | |
| 86 | var target_os: ?[]u8 = null; | | |
| 87 | var target_environ: ?[]u8 = null; | | |
| 88 | var mmacosx_version_min: ?[]u8 = null; | | |
| 89 | var mios_version_min: ?[]u8 = null; | | |
| 90 | var linker_script_arg: ?[]u8 = null; | | |
| 91 | var test_name_prefix_arg: ?[]u8 = null; | | |
| 92 | | | |
| 93 | var test_filters = ArrayList([]const u8).init(allocator); | | |
| 94 | defer test_filters.deinit(); | | |
| 95 | | | |
| 96 | var lib_dirs = ArrayList([]const u8).init(allocator); | | |
| 97 | defer lib_dirs.deinit(); | | |
| 98 | | | |
| 99 | var clang_argv = ArrayList([]const u8).init(allocator); | | |
| 100 | defer clang_argv.deinit(); | | |
| 101 | | | |
| 102 | var llvm_argv = ArrayList([]const u8).init(allocator); | | |
| 103 | defer llvm_argv.deinit(); | | |
| 104 | | | |
| 105 | var link_libs = ArrayList([]const u8).init(allocator); | | |
| 106 | defer link_libs.deinit(); | | |
| 107 | | | |
| 108 | var frameworks = ArrayList([]const u8).init(allocator); | | |
| 109 | defer frameworks.deinit(); | | |
| 110 | | | |
| 111 | var objects = ArrayList([]const u8).init(allocator); | | |
| 112 | defer objects.deinit(); | | |
| 113 | | | |
| 114 | var asm_files = ArrayList([]const u8).init(allocator); | | |
| 115 | defer asm_files.deinit(); | | |
| 116 | | | |
| 117 | var rpath_list = ArrayList([]const u8).init(allocator); | | |
| 118 | defer rpath_list.deinit(); | | |
| 119 | | | |
| 120 | var ver_major: u32 = 0; | | |
| 121 | var ver_minor: u32 = 0; | | |
| 122 | var ver_patch: u32 = 0; | | |
| 123 | | | |
| 124 | var arg_i: usize = 1; | | |
| 125 | while (arg_i < args.len) : (arg_i += 1) { | | |
| 126 | const arg = args[arg_i]; | | |
| 127 | | | |
| 128 | if (arg.len != 0 and arg[0] == '-') { | | |
| 129 | if (mem.eql(u8, arg, "--release-fast")) { | | |
| 130 | build_mode = builtin.Mode.ReleaseFast; | | |
| 131 | } else if (mem.eql(u8, arg, "--release-safe")) { | | |
| 132 | build_mode = builtin.Mode.ReleaseSafe; | | |
| 133 | } else if (mem.eql(u8, arg, "--strip")) { | | |
| 134 | strip = true; | | |
| 135 | } else if (mem.eql(u8, arg, "--static")) { | | |
| 136 | is_static = true; | | |
| 137 | } else if (mem.eql(u8, arg, "--verbose-tokenize")) { | | |
| 138 | verbose_tokenize = true; | | |
| 139 | } else if (mem.eql(u8, arg, "--verbose-ast-tree")) { | | |
| 140 | verbose_ast_tree = true; | | |
| 141 | } else if (mem.eql(u8, arg, "--verbose-ast-fmt")) { | | |
| 142 | verbose_ast_fmt = true; | | |
| 143 | } else if (mem.eql(u8, arg, "--verbose-link")) { | | |
| 144 | verbose_link = true; | | |
| 145 | } else if (mem.eql(u8, arg, "--verbose-ir")) { | | |
| 146 | verbose_ir = true; | | |
| 147 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { | | |
| 148 | verbose_llvm_ir = true; | | |
| 149 | } else if (mem.eql(u8, arg, "--verbose-cimport")) { | | |
| 150 | verbose_cimport = true; | | |
| 151 | } else if (mem.eql(u8, arg, "-mwindows")) { | | |
| 152 | mwindows = true; | | |
| 153 | } else if (mem.eql(u8, arg, "-mconsole")) { | | |
| 154 | mconsole = true; | | |
| 155 | } else if (mem.eql(u8, arg, "-rdynamic")) { | | |
| 156 | rdynamic = true; | | |
| 157 | } else if (mem.eql(u8, arg, "--each-lib-rpath")) { | | |
| 158 | each_lib_rpath = true; | | |
| 159 | } else if (mem.eql(u8, arg, "--enable-timing-info")) { | | |
| 160 | timing_info = true; | | |
| 161 | } else if (mem.eql(u8, arg, "--test-cmd-bin")) { | | |
| 162 | @panic("TODO --test-cmd-bin"); | | |
| 163 | } else if (arg[1] == 'L' and arg.len > 2) { | | |
| 164 | // alias for --library-path | | |
| 165 | try lib_dirs.append(arg[1..]); | | |
| 166 | } else if (mem.eql(u8, arg, "--pkg-begin")) { | | |
| 167 | @panic("TODO --pkg-begin"); | | |
| 168 | } else if (mem.eql(u8, arg, "--pkg-end")) { | | |
| 169 | @panic("TODO --pkg-end"); | | |
| 170 | } else if (arg_i + 1 >= args.len) { | | |
| 171 | badArgs("expected another argument after {}", arg); | | |
| 172 | } else { | | |
| 173 | arg_i += 1; | | |
| 174 | if (mem.eql(u8, arg, "--output")) { | | |
| 175 | out_file = args[arg_i]; | | |
| 176 | } else if (mem.eql(u8, arg, "--output-h")) { | | |
| 177 | out_file_h = args[arg_i]; | | |
| 178 | } else if (mem.eql(u8, arg, "--color")) { | | |
| 179 | if (mem.eql(u8, args[arg_i], "auto")) { | | |
| 180 | color = ErrColor.Auto; | | |
| 181 | } else if (mem.eql(u8, args[arg_i], "on")) { | | |
| 182 | color = ErrColor.On; | | |
| 183 | } else if (mem.eql(u8, args[arg_i], "off")) { | | |
| 184 | color = ErrColor.Off; | | |
| 185 | } else { | | |
| 186 | badArgs("--color options are 'auto', 'on', or 'off'"); | | |
| 187 | } | | |
| 188 | } else if (mem.eql(u8, arg, "--emit")) { | | |
| 189 | if (mem.eql(u8, args[arg_i], "asm")) { | | |
| 190 | emit_file_type = Emit.Assembly; | | |
| 191 | } else if (mem.eql(u8, args[arg_i], "bin")) { | | |
| 192 | emit_file_type = Emit.Binary; | | |
| 193 | } else if (mem.eql(u8, args[arg_i], "llvm-ir")) { | | |
| 194 | emit_file_type = Emit.LlvmIr; | | |
| 195 | } else { | | |
| 196 | badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'"); | | |
| 197 | } | | |
| 198 | } else if (mem.eql(u8, arg, "--name")) { | | |
| 199 | out_name_arg = args[arg_i]; | | |
| 200 | } else if (mem.eql(u8, arg, "--libc-lib-dir")) { | | |
| 201 | libc_lib_dir_arg = args[arg_i]; | | |
| 202 | } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) { | | |
| 203 | libc_static_lib_dir_arg = args[arg_i]; | | |
| 204 | } else if (mem.eql(u8, arg, "--libc-include-dir")) { | | |
| 205 | libc_include_dir_arg = args[arg_i]; | | |
| 206 | } else if (mem.eql(u8, arg, "--msvc-lib-dir")) { | | |
| 207 | msvc_lib_dir_arg = args[arg_i]; | | |
| 208 | } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) { | | |
| 209 | kernel32_lib_dir_arg = args[arg_i]; | | |
| 210 | } else if (mem.eql(u8, arg, "--zig-install-prefix")) { | | |
| 211 | zig_install_prefix = args[arg_i]; | | |
| 212 | } else if (mem.eql(u8, arg, "--dynamic-linker")) { | | |
| 213 | dynamic_linker_arg = args[arg_i]; | | |
| 214 | } else if (mem.eql(u8, arg, "-isystem")) { | | |
| 215 | try clang_argv.append("-isystem"); | | |
| 216 | try clang_argv.append(args[arg_i]); | | |
| 217 | } else if (mem.eql(u8, arg, "-dirafter")) { | | |
| 218 | try clang_argv.append("-dirafter"); | | |
| 219 | try clang_argv.append(args[arg_i]); | | |
| 220 | } else if (mem.eql(u8, arg, "-mllvm")) { | | |
| 221 | try clang_argv.append("-mllvm"); | | |
| 222 | try clang_argv.append(args[arg_i]); | | |
| 223 | | | |
| 224 | try llvm_argv.append(args[arg_i]); | | |
| 225 | } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) { | | |
| 226 | try lib_dirs.append(args[arg_i]); | | |
| 227 | } else if (mem.eql(u8, arg, "--library")) { | | |
| 228 | try link_libs.append(args[arg_i]); | | |
| 229 | } else if (mem.eql(u8, arg, "--object")) { | | |
| 230 | try objects.append(args[arg_i]); | | |
| 231 | } else if (mem.eql(u8, arg, "--assembly")) { | | |
| 232 | try asm_files.append(args[arg_i]); | | |
| 233 | } else if (mem.eql(u8, arg, "--cache-dir")) { | | |
| 234 | cache_dir_arg = args[arg_i]; | | |
| 235 | } else if (mem.eql(u8, arg, "--target-arch")) { | | |
| 236 | target_arch = args[arg_i]; | | |
| 237 | } else if (mem.eql(u8, arg, "--target-os")) { | | |
| 238 | target_os = args[arg_i]; | | |
| 239 | } else if (mem.eql(u8, arg, "--target-environ")) { | | |
| 240 | target_environ = args[arg_i]; | | |
| 241 | } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { | | |
| 242 | mmacosx_version_min = args[arg_i]; | | |
| 243 | } else if (mem.eql(u8, arg, "-mios-version-min")) { | | |
| 244 | mios_version_min = args[arg_i]; | | |
| 245 | } else if (mem.eql(u8, arg, "-framework")) { | | |
| 246 | try frameworks.append(args[arg_i]); | | |
| 247 | } else if (mem.eql(u8, arg, "--linker-script")) { | | |
| 248 | linker_script_arg = args[arg_i]; | | |
| 249 | } else if (mem.eql(u8, arg, "-rpath")) { | | |
| 250 | try rpath_list.append(args[arg_i]); | | |
| 251 | } else if (mem.eql(u8, arg, "--test-filter")) { | | |
| 252 | try test_filters.append(args[arg_i]); | | |
| 253 | } else if (mem.eql(u8, arg, "--test-name-prefix")) { | | |
| 254 | test_name_prefix_arg = args[arg_i]; | | |
| 255 | } else if (mem.eql(u8, arg, "--ver-major")) { | | |
| 256 | ver_major = try std.fmt.parseUnsigned(u32, args[arg_i], 10); | | |
| 257 | } else if (mem.eql(u8, arg, "--ver-minor")) { | | |
| 258 | ver_minor = try std.fmt.parseUnsigned(u32, args[arg_i], 10); | | |
| 259 | } else if (mem.eql(u8, arg, "--ver-patch")) { | | |
| 260 | ver_patch = try std.fmt.parseUnsigned(u32, args[arg_i], 10); | | |
| 261 | } else if (mem.eql(u8, arg, "--test-cmd")) { | | |
| 262 | @panic("TODO --test-cmd"); | | |
| 263 | } else { | | |
| 264 | badArgs("invalid argument: {}", arg); | | |
| 265 | } | | |
| 266 | } | | |
| 267 | } else if (cmd == Cmd.None) { | | |
| 268 | if (mem.eql(u8, arg, "build-obj")) { | | |
| 269 | cmd = Cmd.Build; | | |
| 270 | build_kind = Module.Kind.Obj; | | |
| 271 | } else if (mem.eql(u8, arg, "build-exe")) { | | |
| 272 | cmd = Cmd.Build; | | |
| 273 | build_kind = Module.Kind.Exe; | | |
| 274 | } else if (mem.eql(u8, arg, "build-lib")) { | | |
| 275 | cmd = Cmd.Build; | | |
| 276 | build_kind = Module.Kind.Lib; | | |
| 277 | } else if (mem.eql(u8, arg, "version")) { | | |
| 278 | cmd = Cmd.Version; | | |
| 279 | } else if (mem.eql(u8, arg, "zen")) { | | |
| 280 | cmd = Cmd.Zen; | | |
| 281 | } else if (mem.eql(u8, arg, "translate-c")) { | | |
| 282 | cmd = Cmd.TranslateC; | | |
| 283 | } else if (mem.eql(u8, arg, "test")) { | | |
| 284 | cmd = Cmd.Test; | | |
| 285 | build_kind = Module.Kind.Exe; | | |
| 286 | } else { | | |
| 287 | badArgs("unrecognized command: {}", arg); | | |
| 288 | } | | |
| 289 | } else switch (cmd) { | | |
| 290 | Cmd.Build, Cmd.TranslateC, Cmd.Test => { | | |
| 291 | if (in_file_arg == null) { | | |
| 292 | in_file_arg = arg; | | |
| 293 | } else { | | |
| 294 | badArgs("unexpected extra parameter: {}", arg); | | |
| 295 | } | | |
| 296 | }, | | |
| 297 | Cmd.Version, Cmd.Zen, Cmd.Targets => { | | |
| 298 | badArgs("unexpected extra parameter: {}", arg); | | |
| 299 | }, | | |
| 300 | Cmd.None => unreachable, | | |
| 301 | } | | |
| 302 | } | 64 | } |
| 303 | | 65 | |
| 304 | target.initializeAll(); | 66 | const commands = []Command { |
| 305 | | 67 | Command { .name = "build", .exec = cmdBuild }, |
| 306 | // TODO | 68 | Command { .name = "build-exe", .exec = cmdBuildExe }, |
| 307 | // ZigTarget alloc_target; | 69 | Command { .name = "build-lib", .exec = cmdBuildLib }, |
| 308 | // ZigTarget *target; | 70 | Command { .name = "build-obj", .exec = cmdBuildObj }, |
| 309 | // if (!target_arch && !target_os && !target_environ) { | 71 | Command { .name = "fmt", .exec = cmdFmt }, |
| 310 | // target = nullptr; | 72 | Command { .name = "run", .exec = cmdRun }, |
| 311 | // } else { | 73 | Command { .name = "targets", .exec = cmdTargets }, |
| 312 | // target = &alloc_target; | 74 | Command { .name = "test", .exec = cmdTest }, |
| 313 | // get_unknown_target(target); | 75 | Command { .name = "translate-c", .exec = cmdTranslateC }, |
| 314 | // if (target_arch) { | 76 | Command { .name = "version", .exec = cmdVersion }, |
| 315 | // if (parse_target_arch(target_arch, &target->arch)) { | 77 | Command { .name = "zen", .exec = cmdZen }, |
| 316 | // fprintf(stderr, "invalid --target-arch argument\n"); | 78 | |
| 317 | // return usage(arg0); | 79 | // undocumented commands |
| 318 | // } | 80 | Command { .name = "help", .exec = cmdHelp }, |
| 319 | // } | 81 | Command { .name = "internal", .exec = cmdInternal }, |
| 320 | // if (target_os) { | 82 | }; |
| 321 | // if (parse_target_os(target_os, &target->os)) { | 83 | |
| 322 | // fprintf(stderr, "invalid --target-os argument\n"); | 84 | for (commands) |command| { |
| 323 | // return usage(arg0); | 85 | if (mem.eql(u8, command.name, args[1])) { |
| 324 | // } | 86 | try command.exec(allocator, args[2..]); |
| 325 | // } | 87 | return; |
| 326 | // if (target_environ) { | 88 | } |
| 327 | // if (parse_target_environ(target_environ, &target->env_type)) { | | |
| 328 | // fprintf(stderr, "invalid --target-environ argument\n"); | | |
| 329 | // return usage(arg0); | | |
| 330 | // } | | |
| 331 | // } | | |
| 332 | // } | | |
| 333 | | | |
| 334 | switch (cmd) { | | |
| 335 | Cmd.None => badArgs("expected command"), | | |
| 336 | Cmd.Zen => return printZen(), | | |
| 337 | Cmd.Build, Cmd.Test, Cmd.TranslateC => { | | |
| 338 | if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) { | | |
| 339 | badArgs("expected source file argument or at least one --object or --assembly argument"); | | |
| 340 | } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) { | | |
| 341 | badArgs("expected source file argument"); | | |
| 342 | } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) { | | |
| 343 | badArgs("When building an object file, --object arguments are invalid"); | | |
| 344 | } | | |
| 345 | | | |
| 346 | const root_name = switch (cmd) { | | |
| 347 | Cmd.Build, Cmd.TranslateC => x: { | | |
| 348 | if (out_name_arg) |out_name| { | | |
| 349 | break :x out_name; | | |
| 350 | } else if (in_file_arg) |in_file_path| { | | |
| 351 | const basename = os.path.basename(in_file_path); | | |
| 352 | var it = mem.split(basename, "."); | | |
| 353 | break :x it.next() ?? badArgs("file name cannot be empty"); | | |
| 354 | } else { | | |
| 355 | badArgs("--name [name] not provided and unable to infer"); | | |
| 356 | } | | |
| 357 | }, | | |
| 358 | Cmd.Test => "test", | | |
| 359 | else => unreachable, | | |
| 360 | }; | | |
| 361 | | | |
| 362 | const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg; | | |
| 363 | | | |
| 364 | const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name; | | |
| 365 | const full_cache_dir = try os.path.resolve(allocator, ".", chosen_cache_dir); | | |
| 366 | defer allocator.free(full_cache_dir); | | |
| 367 | | | |
| 368 | const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix); | | |
| 369 | errdefer allocator.free(zig_lib_dir); | | |
| 370 | | | |
| 371 | const module = try Module.create(allocator, root_name, zig_root_source_file, | | |
| 372 | Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir); | | |
| 373 | defer module.destroy(); | | |
| 374 | | | |
| 375 | module.version_major = ver_major; | | |
| 376 | module.version_minor = ver_minor; | | |
| 377 | module.version_patch = ver_patch; | | |
| 378 | | | |
| 379 | module.is_test = cmd == Cmd.Test; | | |
| 380 | if (linker_script_arg) |linker_script| { | | |
| 381 | module.linker_script = linker_script; | | |
| 382 | } | | |
| 383 | module.each_lib_rpath = each_lib_rpath; | | |
| 384 | module.clang_argv = clang_argv.toSliceConst(); | | |
| 385 | module.llvm_argv = llvm_argv.toSliceConst(); | | |
| 386 | module.strip = strip; | | |
| 387 | module.is_static = is_static; | | |
| 388 | | | |
| 389 | if (libc_lib_dir_arg) |libc_lib_dir| { | | |
| 390 | module.libc_lib_dir = libc_lib_dir; | | |
| 391 | } | | |
| 392 | if (libc_static_lib_dir_arg) |libc_static_lib_dir| { | | |
| 393 | module.libc_static_lib_dir = libc_static_lib_dir; | | |
| 394 | } | | |
| 395 | if (libc_include_dir_arg) |libc_include_dir| { | | |
| 396 | module.libc_include_dir = libc_include_dir; | | |
| 397 | } | | |
| 398 | if (msvc_lib_dir_arg) |msvc_lib_dir| { | | |
| 399 | module.msvc_lib_dir = msvc_lib_dir; | | |
| 400 | } | | |
| 401 | if (kernel32_lib_dir_arg) |kernel32_lib_dir| { | | |
| 402 | module.kernel32_lib_dir = kernel32_lib_dir; | | |
| 403 | } | | |
| 404 | if (dynamic_linker_arg) |dynamic_linker| { | | |
| 405 | module.dynamic_linker = dynamic_linker; | | |
| 406 | } | | |
| 407 | module.verbose_tokenize = verbose_tokenize; | | |
| 408 | module.verbose_ast_tree = verbose_ast_tree; | | |
| 409 | module.verbose_ast_fmt = verbose_ast_fmt; | | |
| 410 | module.verbose_link = verbose_link; | | |
| 411 | module.verbose_ir = verbose_ir; | | |
| 412 | module.verbose_llvm_ir = verbose_llvm_ir; | | |
| 413 | module.verbose_cimport = verbose_cimport; | | |
| 414 | | | |
| 415 | module.err_color = color; | | |
| 416 | | | |
| 417 | module.lib_dirs = lib_dirs.toSliceConst(); | | |
| 418 | module.darwin_frameworks = frameworks.toSliceConst(); | | |
| 419 | module.rpath_list = rpath_list.toSliceConst(); | | |
| 420 | | | |
| 421 | for (link_libs.toSliceConst()) |name| { | | |
| 422 | _ = try module.addLinkLib(name, true); | | |
| 423 | } | | |
| 424 | | | |
| 425 | module.windows_subsystem_windows = mwindows; | | |
| 426 | module.windows_subsystem_console = mconsole; | | |
| 427 | module.linker_rdynamic = rdynamic; | | |
| 428 | | | |
| 429 | if (mmacosx_version_min != null and mios_version_min != null) { | | |
| 430 | badArgs("-mmacosx-version-min and -mios-version-min options not allowed together"); | | |
| 431 | } | | |
| 432 | | | |
| 433 | if (mmacosx_version_min) |ver| { | | |
| 434 | module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver }; | | |
| 435 | } else if (mios_version_min) |ver| { | | |
| 436 | module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver }; | | |
| 437 | } | | |
| 438 | | | |
| 439 | module.test_filters = test_filters.toSliceConst(); | | |
| 440 | module.test_name_prefix = test_name_prefix_arg; | | |
| 441 | module.out_h_path = out_file_h; | | |
| 442 | | | |
| 443 | // TODO | | |
| 444 | //add_package(g, cur_pkg, g->root_package); | | |
| 445 | | | |
| 446 | switch (cmd) { | | |
| 447 | Cmd.Build => { | | |
| 448 | module.emit_file_type = emit_file_type; | | |
| 449 | | | |
| 450 | module.link_objects = objects.toSliceConst(); | | |
| 451 | module.assembly_files = asm_files.toSliceConst(); | | |
| 452 | | | |
| 453 | try module.build(); | | |
| 454 | try module.link(out_file); | | |
| 455 | }, | | |
| 456 | Cmd.TranslateC => @panic("TODO translate-c"), | | |
| 457 | Cmd.Test => @panic("TODO test cmd"), | | |
| 458 | else => unreachable, | | |
| 459 | } | | |
| 460 | }, | | |
| 461 | Cmd.Version => { | | |
| 462 | var stdout_file = try io.getStdErr(); | | |
| 463 | try stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING)); | | |
| 464 | try stdout_file.write("\n"); | | |
| 465 | }, | | |
| 466 | Cmd.Targets => @panic("TODO zig targets"), | | |
| 467 | } | 89 | } |
| 468 | } | | |
| 469 | | 90 | |
| 470 | fn printUsage(stream: var) !void { | 91 | try stderr.print("unknown command: {}\n\n", args[1]); |
| 471 | try stream.write( | 92 | try stderr.write(usage); |
| 472 | \\Usage: zig [command] [options] | | |
| 473 | \\ | | |
| 474 | \\Commands: | | |
| 475 | \\ build build project from build.zig | | |
| 476 | \\ build-exe [source] create executable from source or object files | | |
| 477 | \\ build-lib [source] create library from source or object files | | |
| 478 | \\ build-obj [source] create object from source or assembly | | |
| 479 | \\ fmt [file] parse file and render in canonical zig format | | |
| 480 | \\ translate-c [source] convert c code to zig code | | |
| 481 | \\ targets list available compilation targets | | |
| 482 | \\ test [source] create and run a test build | | |
| 483 | \\ version print version number and exit | | |
| 484 | \\ zen print zen of zig and exit | | |
| 485 | \\Compile Options: | | |
| 486 | \\ --assembly [source] add assembly file to build | | |
| 487 | \\ --cache-dir [path] override the cache directory | | |
| 488 | \\ --color [auto|off|on] enable or disable colored error messages | | |
| 489 | \\ --emit [filetype] emit a specific file format as compilation output | | |
| 490 | \\ --enable-timing-info print timing diagnostics | | |
| 491 | \\ --libc-include-dir [path] directory where libc stdlib.h resides | | |
| 492 | \\ --name [name] override output name | | |
| 493 | \\ --output [file] override destination path | | |
| 494 | \\ --output-h [file] override generated header file path | | |
| 495 | \\ --pkg-begin [name] [path] make package available to import and push current pkg | | |
| 496 | \\ --pkg-end pop current pkg | | |
| 497 | \\ --release-fast build with optimizations on and safety off | | |
| 498 | \\ --release-safe build with optimizations on and safety on | | |
| 499 | \\ --static output will be statically linked | | |
| 500 | \\ --strip exclude debug symbols | | |
| 501 | \\ --target-arch [name] specify target architecture | | |
| 502 | \\ --target-environ [name] specify target environment | | |
| 503 | \\ --target-os [name] specify target operating system | | |
| 504 | \\ --verbose-tokenize enable compiler debug info: tokenization | | |
| 505 | \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview) | | |
| 506 | \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source) | | |
| 507 | \\ --verbose-cimport enable compiler debug info: C imports | | |
| 508 | \\ --verbose-ir enable compiler debug info: Zig IR | | |
| 509 | \\ --verbose-llvm-ir enable compiler debug info: LLVM IR | | |
| 510 | \\ --verbose-link enable compiler debug info: linking | | |
| 511 | \\ --zig-install-prefix [path] override directory where zig thinks it is installed | | |
| 512 | \\ -dirafter [dir] same as -isystem but do it last | | |
| 513 | \\ -isystem [dir] add additional search path for other .h files | | |
| 514 | \\ -mllvm [arg] additional arguments to forward to LLVM's option processing | | |
| 515 | \\Link Options: | | |
| 516 | \\ --ar-path [path] set the path to ar | | |
| 517 | \\ --dynamic-linker [path] set the path to ld.so | | |
| 518 | \\ --each-lib-rpath add rpath for each used dynamic library | | |
| 519 | \\ --libc-lib-dir [path] directory where libc crt1.o resides | | |
| 520 | \\ --libc-static-lib-dir [path] directory where libc crtbegin.o resides | | |
| 521 | \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides | | |
| 522 | \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides | | |
| 523 | \\ --library [lib] link against lib | | |
| 524 | \\ --library-path [dir] add a directory to the library search path | | |
| 525 | \\ --linker-script [path] use a custom linker script | | |
| 526 | \\ --object [obj] add object file to build | | |
| 527 | \\ -L[dir] alias for --library-path | | |
| 528 | \\ -rdynamic add all symbols to the dynamic symbol table | | |
| 529 | \\ -rpath [path] add directory to the runtime library search path | | |
| 530 | \\ -mconsole (windows) --subsystem console to the linker | | |
| 531 | \\ -mwindows (windows) --subsystem windows to the linker | | |
| 532 | \\ -framework [name] (darwin) link against framework | | |
| 533 | \\ -mios-version-min [ver] (darwin) set iOS deployment target | | |
| 534 | \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target | | |
| 535 | \\ --ver-major [ver] dynamic library semver major version | | |
| 536 | \\ --ver-minor [ver] dynamic library semver minor version | | |
| 537 | \\ --ver-patch [ver] dynamic library semver patch version | | |
| 538 | \\Test Options: | | |
| 539 | \\ --test-filter [text] skip tests that do not match filter | | |
| 540 | \\ --test-name-prefix [text] add prefix to all tests | | |
| 541 | \\ --test-cmd [arg] specify test execution command one arg at a time | | |
| 542 | \\ --test-cmd-bin appends test binary path to test cmd args | | |
| 543 | \\ | | |
| 544 | ); | | |
| 545 | } | | |
| 546 | | | |
| 547 | fn printZen() !void { | | |
| 548 | var stdout_file = try io.getStdErr(); | | |
| 549 | try stdout_file.write( | | |
| 550 | \\ | | |
| 551 | \\ * Communicate intent precisely. | | |
| 552 | \\ * Edge cases matter. | | |
| 553 | \\ * Favor reading code over writing code. | | |
| 554 | \\ * Only one obvious way to do things. | | |
| 555 | \\ * Runtime crashes are better than bugs. | | |
| 556 | \\ * Compile errors are better than runtime crashes. | | |
| 557 | \\ * Incremental improvements. | | |
| 558 | \\ * Avoid local maximums. | | |
| 559 | \\ * Reduce the amount one must remember. | | |
| 560 | \\ * Minimize energy spent on coding style. | | |
| 561 | \\ * Together we serve end users. | | |
| 562 | \\ | | |
| 563 | \\ | | |
| 564 | ); | | |
| 565 | } | 93 | } |
| 566 | | 94 | |
| 567 | fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void { | 95 | // cmd:build /////////////////////////////////////////////////////////////////////////////////////// |
| 568 | var build_file: [] const u8 = "build.zig"; | 96 | |
| 569 | var cache_dir: ?[] const u8 = null; | 97 | const usage_build = |
| 570 | var zig_install_prefix: ?[] const u8 = null; | 98 | \\usage: zig build <options> |
| 571 | var asked_for_help = false; | 99 | \\ |
| 572 | var asked_for_init = false; | 100 | \\General Options: |
| 573 | | 101 | \\ --help Print this help and exit |
| 574 | var args = ArrayList([] const u8).init(allocator); | 102 | \\ --init Generate a build.zig template |
| 575 | defer args.deinit(); | 103 | \\ --build-file [file] Override path to build.zig |
| 576 | | 104 | \\ --cache-dir [path] Override path to cache directory |
| 577 | var zig_exe_path = try os.selfExePath(allocator); | 105 | \\ --verbose Print commands before executing them |
| 578 | defer allocator.free(zig_exe_path); | 106 | \\ --prefix [path] Override default install prefix |
| 579 | | 107 | \\ |
| 580 | try args.append(""); // Placeholder for zig-cache/build | 108 | \\Project-Specific Options: |
| 581 | try args.append(""); // Placeholder for zig_exe_path | 109 | \\ |
| 582 | try args.append(""); // Placeholder for build_file_dirname | 110 | \\ Project-specific options become available when the build file is found. |
| 583 | try args.append(""); // Placeholder for full_cache_dir | 111 | \\ |
| | 112 | \\Advanced Options: |
| | 113 | \\ --build-file [file] Override path to build.zig |
| | 114 | \\ --cache-dir [path] Override path to cache directory |
| | 115 | \\ --verbose-tokenize Enable compiler debug output for tokenization |
| | 116 | \\ --verbose-ast Enable compiler debug output for parsing into an AST |
| | 117 | \\ --verbose-link Enable compiler debug output for linking |
| | 118 | \\ --verbose-ir Enable compiler debug output for Zig IR |
| | 119 | \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR |
| | 120 | \\ --verbose-cimport Enable compiler debug output for C imports |
| | 121 | \\ |
| | 122 | \\ |
| | 123 | ; |
| | 124 | |
| | 125 | const args_build_spec = []Flag { |
| | 126 | Flag.Bool("--help"), |
| | 127 | Flag.Bool("--init"), |
| | 128 | Flag.Arg1("--build-file"), |
| | 129 | Flag.Arg1("--cache-dir"), |
| | 130 | Flag.Bool("--verbose"), |
| | 131 | Flag.Arg1("--prefix"), |
| | 132 | |
| | 133 | Flag.Arg1("--build-file"), |
| | 134 | Flag.Arg1("--cache-dir"), |
| | 135 | Flag.Bool("--verbose-tokenize"), |
| | 136 | Flag.Bool("--verbose-ast"), |
| | 137 | Flag.Bool("--verbose-link"), |
| | 138 | Flag.Bool("--verbose-ir"), |
| | 139 | Flag.Bool("--verbose-llvm-ir"), |
| | 140 | Flag.Bool("--verbose-cimport"), |
| | 141 | }; |
| 584 | | 142 | |
| 585 | var i: usize = 0; | 143 | const missing_build_file = |
| 586 | while (i < argv.len) : (i += 1) { | 144 | \\No 'build.zig' file found. |
| 587 | var arg = argv[i]; | 145 | \\ |
| 588 | if (mem.eql(u8, arg, "--help")) { | 146 | \\Initialize a 'build.zig' template file with `zig build --init`, |
| 589 | asked_for_help = true; | 147 | \\or build an executable directly with `zig build-exe $FILENAME.zig`. |
| 590 | try args.append(argv[i]); | 148 | \\ |
| 591 | } else if (mem.eql(u8, arg, "--init")) { | 149 | \\See: `zig build --help` or `zig help` for more options. |
| 592 | asked_for_init = true; | 150 | \\ |
| 593 | try args.append(argv[i]); | 151 | ; |
| 594 | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--build-file")) { | 152 | |
| 595 | build_file = argv[i + 1]; | 153 | fn cmdBuild(allocator: &Allocator, args: []const []const u8) !void { |
| 596 | i += 1; | 154 | var flags = try Args.parse(allocator, args_build_spec, args); |
| 597 | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--cache-dir")) { | 155 | defer flags.deinit(); |
| 598 | cache_dir = argv[i + 1]; | 156 | |
| 599 | i += 1; | 157 | if (flags.present("help")) { |
| 600 | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) { | 158 | try stderr.write(usage_build); |
| 601 | try args.append(arg); | 159 | os.exit(0); |
| 602 | i += 1; | | |
| 603 | zig_install_prefix = argv[i]; | | |
| 604 | try args.append(argv[i]); | | |
| 605 | } else { | | |
| 606 | try args.append(arg); | | |
| 607 | } | | |
| 608 | } | 160 | } |
| 609 | | 161 | |
| 610 | const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix); | 162 | const zig_lib_dir = try introspect.resolveZigLibDir(allocator); |
| 611 | defer allocator.free(zig_lib_dir); | 163 | defer allocator.free(zig_lib_dir); |
| 612 | | 164 | |
| 613 | const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std"); | 165 | const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std"); |
| ... | @@ -619,113 +171,502 @@ fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void { | ... | @@ -619,113 +171,502 @@ fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void { |
| 619 | const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig"); | 171 | const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig"); |
| 620 | defer allocator.free(build_runner_path); | 172 | defer allocator.free(build_runner_path); |
| 621 | | 173 | |
| 622 | // g = codegen_create(build_runner_path, ...) | 174 | const build_file = flags.single("build-file") ?? "build.zig"; |
| 623 | // codegen_set_out_name(g, "build") | | |
| 624 | | | |
| 625 | const build_file_abs = try os.path.resolve(allocator, ".", build_file); | 175 | const build_file_abs = try os.path.resolve(allocator, ".", build_file); |
| 626 | defer allocator.free(build_file_abs); | 176 | defer allocator.free(build_file_abs); |
| 627 | | 177 | |
| 628 | const build_file_basename = os.path.basename(build_file_abs); | 178 | const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false; |
| 629 | const build_file_dirname = os.path.dirname(build_file_abs); | | |
| 630 | | 179 | |
| 631 | var full_cache_dir: []u8 = undefined; | 180 | if (flags.present("init")) { |
| 632 | if (cache_dir == null) { | 181 | if (build_file_exists) { |
| 633 | full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache"); | 182 | try stderr.print("build.zig already exists\n"); |
| 634 | } else { | 183 | os.exit(1); |
| 635 | full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir); | 184 | } |
| 636 | } | | |
| 637 | defer allocator.free(full_cache_dir); | | |
| 638 | | 185 | |
| 639 | const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build"); | 186 | // need a new scope for proper defer scope finalization on exit |
| 640 | defer allocator.free(path_to_build_exe); | 187 | { |
| 641 | // codegen_set_cache_dir(g, full_cache_dir) | 188 | const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig"); |
| | 189 | defer allocator.free(build_template_path); |
| 642 | | 190 | |
| 643 | args.items[0] = path_to_build_exe; | 191 | try os.copyFile(allocator, build_template_path, build_file_abs); |
| 644 | args.items[1] = zig_exe_path; | 192 | try stderr.print("wrote build.zig template\n"); |
| 645 | args.items[2] = build_file_dirname; | 193 | } |
| 646 | args.items[3] = full_cache_dir; | | |
| 647 | | 194 | |
| 648 | var build_file_exists: bool = undefined; | 195 | os.exit(0); |
| 649 | if (os.File.openRead(allocator, build_file_abs)) |*file| { | | |
| 650 | file.close(); | | |
| 651 | build_file_exists = true; | | |
| 652 | } else |_| { | | |
| 653 | build_file_exists = false; | | |
| 654 | } | 196 | } |
| 655 | | 197 | |
| 656 | if (!build_file_exists and asked_for_help) { | 198 | if (!build_file_exists) { |
| 657 | // TODO(bnoordhuis) Print help message from std/special/build_runner.zig | 199 | try stderr.write(missing_build_file); |
| 658 | return; | 200 | os.exit(1); |
| 659 | } | 201 | } |
| 660 | | 202 | |
| 661 | if (!build_file_exists and asked_for_init) { | 203 | // TODO: Invoke build.zig entrypoint directly? |
| 662 | const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig"); | 204 | var zig_exe_path = try os.selfExePath(allocator); |
| 663 | defer allocator.free(build_template_path); | 205 | defer allocator.free(zig_exe_path); |
| 664 | | | |
| 665 | var srcfile = try os.File.openRead(allocator, build_template_path); | | |
| 666 | defer srcfile.close(); | | |
| 667 | | 206 | |
| 668 | var dstfile = try os.File.openWrite(allocator, build_file_abs); | 207 | var build_args = ArrayList([]const u8).init(allocator); |
| 669 | defer dstfile.close(); | 208 | defer build_args.deinit(); |
| 670 | | 209 | |
| 671 | while (true) { | 210 | const build_file_basename = os.path.basename(build_file_abs); |
| 672 | var buffer: [4096]u8 = undefined; | 211 | const build_file_dirname = os.path.dirname(build_file_abs); |
| 673 | const n = try srcfile.read(buffer[0..]); | | |
| 674 | if (n == 0) break; | | |
| 675 | try dstfile.write(buffer[0..n]); | | |
| 676 | } | | |
| 677 | | 212 | |
| 678 | return; | 213 | var full_cache_dir: []u8 = undefined; |
| | 214 | if (flags.single("cache-dir")) |cache_dir| { |
| | 215 | full_cache_dir = try os.path.resolve(allocator, ".", cache_dir, full_cache_dir); |
| | 216 | } else { |
| | 217 | full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache"); |
| 679 | } | 218 | } |
| | 219 | defer allocator.free(full_cache_dir); |
| 680 | | 220 | |
| 681 | if (!build_file_exists) { | 221 | const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build"); |
| 682 | warn( | 222 | defer allocator.free(path_to_build_exe); |
| 683 | \\No 'build.zig' file found. | | |
| 684 | \\Initialize a 'build.zig' template file with `zig build --init`, | | |
| 685 | \\or build an executable directly with `zig build-exe $FILENAME.zig`. | | |
| 686 | \\See: `zig build --help` or `zig help` for more options. | | |
| 687 | \\ | | |
| 688 | ); | | |
| 689 | os.exit(1); | | |
| 690 | } | | |
| 691 | | 223 | |
| 692 | // codegen_build(g) | 224 | try build_args.append(path_to_build_exe); |
| 693 | // codegen_link(g, path_to_build_exe) | 225 | try build_args.append(zig_exe_path); |
| 694 | // codegen_destroy(g) | 226 | try build_args.append(build_file_dirname); |
| | 227 | try build_args.append(full_cache_dir); |
| 695 | | 228 | |
| 696 | var proc = try os.ChildProcess.init(args.toSliceConst(), allocator); | 229 | var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator); |
| 697 | defer proc.deinit(); | 230 | defer proc.deinit(); |
| 698 | | 231 | |
| 699 | var term = try proc.spawnAndWait(); | 232 | var term = try proc.spawnAndWait(); |
| 700 | switch (term) { | 233 | switch (term) { |
| 701 | os.ChildProcess.Term.Exited => |status| { | 234 | os.ChildProcess.Term.Exited => |status| { |
| 702 | if (status != 0) { | 235 | if (status != 0) { |
| 703 | warn("{} exited with status {}\n", args.at(0), status); | 236 | try stderr.print("{} exited with status {}\n", build_args.at(0), status); |
| 704 | os.exit(1); | 237 | os.exit(1); |
| 705 | } | 238 | } |
| 706 | }, | 239 | }, |
| 707 | os.ChildProcess.Term.Signal => |signal| { | 240 | os.ChildProcess.Term.Signal => |signal| { |
| 708 | warn("{} killed by signal {}\n", args.at(0), signal); | 241 | try stderr.print("{} killed by signal {}\n", build_args.at(0), signal); |
| 709 | os.exit(1); | 242 | os.exit(1); |
| 710 | }, | 243 | }, |
| 711 | os.ChildProcess.Term.Stopped => |signal| { | 244 | os.ChildProcess.Term.Stopped => |signal| { |
| 712 | warn("{} stopped by signal {}\n", args.at(0), signal); | 245 | try stderr.print("{} stopped by signal {}\n", build_args.at(0), signal); |
| 713 | os.exit(1); | 246 | os.exit(1); |
| 714 | }, | 247 | }, |
| 715 | os.ChildProcess.Term.Unknown => |status| { | 248 | os.ChildProcess.Term.Unknown => |status| { |
| 716 | warn("{} encountered unknown failure {}\n", args.at(0), status); | 249 | try stderr.print("{} encountered unknown failure {}\n", build_args.at(0), status); |
| | 250 | os.exit(1); |
| | 251 | }, |
| | 252 | } |
| | 253 | } |
| | 254 | |
| | 255 | // cmd:build-exe /////////////////////////////////////////////////////////////////////////////////// |
| | 256 | |
| | 257 | const usage_build_generic = |
| | 258 | \\usage: zig build-exe <options> [file] |
| | 259 | \\ zig build-lib <options> [file] |
| | 260 | \\ zig build-obj <options> [file] |
| | 261 | \\ |
| | 262 | \\General Options: |
| | 263 | \\ --help Print this help and exit |
| | 264 | \\ --color [auto|off|on] Enable or disable colored error messages |
| | 265 | \\ |
| | 266 | \\Compile Options: |
| | 267 | \\ --assembly [source] Add assembly file to build |
| | 268 | \\ --cache-dir [path] Override the cache directory |
| | 269 | \\ --emit [filetype] Emit a specific file format as compilation output |
| | 270 | \\ --enable-timing-info Print timing diagnostics |
| | 271 | \\ --libc-include-dir [path] Directory where libc stdlib.h resides |
| | 272 | \\ --name [name] Override output name |
| | 273 | \\ --output [file] Override destination path |
| | 274 | \\ --output-h [file] Override generated header file path |
| | 275 | \\ --pkg-begin [name] [path] Make package available to import and push current pkg |
| | 276 | \\ --pkg-end Pop current pkg |
| | 277 | \\ --release-fast Build with optimizations on and safety off |
| | 278 | \\ --release-safe Build with optimizations on and safety on |
| | 279 | \\ --static Output will be statically linked |
| | 280 | \\ --strip Exclude debug symbols |
| | 281 | \\ --target-arch [name] Specify target architecture |
| | 282 | \\ --target-environ [name] Specify target environment |
| | 283 | \\ --target-os [name] Specify target operating system |
| | 284 | \\ --verbose-tokenize Turn on compiler debug output for tokenization |
| | 285 | \\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view) |
| | 286 | \\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source) |
| | 287 | \\ --verbose-link Turn on compiler debug output for linking |
| | 288 | \\ --verbose-ir Turn on compiler debug output for Zig IR |
| | 289 | \\ --verbose-llvm-ir Turn on compiler debug output for LLVM IR |
| | 290 | \\ --verbose-cimport Turn on compiler debug output for C imports |
| | 291 | \\ -dirafter [dir] Same as -isystem but do it last |
| | 292 | \\ -isystem [dir] Add additional search path for other .h files |
| | 293 | \\ -mllvm [arg] Additional arguments to forward to LLVM's option processing |
| | 294 | \\ |
| | 295 | \\Link Options: |
| | 296 | \\ --ar-path [path] Set the path to ar |
| | 297 | \\ --dynamic-linker [path] Set the path to ld.so |
| | 298 | \\ --each-lib-rpath Add rpath for each used dynamic library |
| | 299 | \\ --libc-lib-dir [path] Directory where libc crt1.o resides |
| | 300 | \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides |
| | 301 | \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides |
| | 302 | \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides |
| | 303 | \\ --library [lib] Link against lib |
| | 304 | \\ --forbid-library [lib] Make it an error to link against lib |
| | 305 | \\ --library-path [dir] Add a directory to the library search path |
| | 306 | \\ --linker-script [path] Use a custom linker script |
| | 307 | \\ --object [obj] Add object file to build |
| | 308 | \\ -rdynamic Add all symbols to the dynamic symbol table |
| | 309 | \\ -rpath [path] Add directory to the runtime library search path |
| | 310 | \\ -mconsole (windows) --subsystem console to the linker |
| | 311 | \\ -mwindows (windows) --subsystem windows to the linker |
| | 312 | \\ -framework [name] (darwin) link against framework |
| | 313 | \\ -mios-version-min [ver] (darwin) set iOS deployment target |
| | 314 | \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target |
| | 315 | \\ --ver-major [ver] Dynamic library semver major version |
| | 316 | \\ --ver-minor [ver] Dynamic library semver minor version |
| | 317 | \\ --ver-patch [ver] Dynamic library semver patch version |
| | 318 | \\ |
| | 319 | \\ |
| | 320 | ; |
| | 321 | |
| | 322 | const args_build_generic = []Flag { |
| | 323 | Flag.Bool("--help"), |
| | 324 | Flag.Option("--color", []const []const u8 { "auto", "off", "on" }), |
| | 325 | |
| | 326 | Flag.ArgMergeN("--assembly", 1), |
| | 327 | Flag.Arg1("--cache-dir"), |
| | 328 | Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }), |
| | 329 | Flag.Bool("--enable-timing-info"), |
| | 330 | Flag.Arg1("--libc-include-dir"), |
| | 331 | Flag.Arg1("--name"), |
| | 332 | Flag.Arg1("--output"), |
| | 333 | Flag.Arg1("--output-h"), |
| | 334 | // NOTE: Parsed manually after initial check |
| | 335 | Flag.ArgN("--pkg-begin", 2), |
| | 336 | Flag.Bool("--pkg-end"), |
| | 337 | Flag.Bool("--release-fast"), |
| | 338 | Flag.Bool("--release-safe"), |
| | 339 | Flag.Bool("--static"), |
| | 340 | Flag.Bool("--strip"), |
| | 341 | Flag.Arg1("--target-arch"), |
| | 342 | Flag.Arg1("--target-environ"), |
| | 343 | Flag.Arg1("--target-os"), |
| | 344 | Flag.Bool("--verbose-tokenize"), |
| | 345 | Flag.Bool("--verbose-ast-tree"), |
| | 346 | Flag.Bool("--verbose-ast-fmt"), |
| | 347 | Flag.Bool("--verbose-link"), |
| | 348 | Flag.Bool("--verbose-ir"), |
| | 349 | Flag.Bool("--verbose-llvm-ir"), |
| | 350 | Flag.Bool("--verbose-cimport"), |
| | 351 | Flag.Arg1("-dirafter"), |
| | 352 | Flag.ArgMergeN("-isystem", 1), |
| | 353 | Flag.Arg1("-mllvm"), |
| | 354 | |
| | 355 | Flag.Arg1("--ar-path"), |
| | 356 | Flag.Arg1("--dynamic-linker"), |
| | 357 | Flag.Bool("--each-lib-rpath"), |
| | 358 | Flag.Arg1("--libc-lib-dir"), |
| | 359 | Flag.Arg1("--libc-static-lib-dir"), |
| | 360 | Flag.Arg1("--msvc-lib-dir"), |
| | 361 | Flag.Arg1("--kernel32-lib-dir"), |
| | 362 | Flag.ArgMergeN("--library", 1), |
| | 363 | Flag.ArgMergeN("--forbid-library", 1), |
| | 364 | Flag.ArgMergeN("--library-path", 1), |
| | 365 | Flag.Arg1("--linker-script"), |
| | 366 | Flag.ArgMergeN("--object", 1), |
| | 367 | // NOTE: Removed -L since it would need to be special-cased and we have an alias in library-path |
| | 368 | Flag.Bool("-rdynamic"), |
| | 369 | Flag.Arg1("-rpath"), |
| | 370 | Flag.Bool("-mconsole"), |
| | 371 | Flag.Bool("-mwindows"), |
| | 372 | Flag.ArgMergeN("-framework", 1), |
| | 373 | Flag.Arg1("-mios-version-min"), |
| | 374 | Flag.Arg1("-mmacosx-version-min"), |
| | 375 | Flag.Arg1("--ver-major"), |
| | 376 | Flag.Arg1("--ver-minor"), |
| | 377 | Flag.Arg1("--ver-patch"), |
| | 378 | }; |
| | 379 | |
| | 380 | fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Module.Kind) !void { |
| | 381 | var flags = try Args.parse(allocator, args_build_generic, args); |
| | 382 | defer flags.deinit(); |
| | 383 | |
| | 384 | if (flags.present("help")) { |
| | 385 | try stderr.write(usage_build_generic); |
| | 386 | os.exit(0); |
| | 387 | } |
| | 388 | |
| | 389 | var build_mode = builtin.Mode.Debug; |
| | 390 | if (flags.present("release-fast")) { |
| | 391 | build_mode = builtin.Mode.ReleaseFast; |
| | 392 | } else if (flags.present("release-safe")) { |
| | 393 | build_mode = builtin.Mode.ReleaseSafe; |
| | 394 | } |
| | 395 | |
| | 396 | var color = Module.ErrColor.Auto; |
| | 397 | if (flags.single("color")) |color_flag| { |
| | 398 | if (mem.eql(u8, color_flag, "auto")) { |
| | 399 | color = Module.ErrColor.Auto; |
| | 400 | } else if (mem.eql(u8, color_flag, "on")) { |
| | 401 | color = Module.ErrColor.On; |
| | 402 | } else if (mem.eql(u8, color_flag, "off")) { |
| | 403 | color = Module.ErrColor.Off; |
| | 404 | } else { |
| | 405 | unreachable; |
| | 406 | } |
| | 407 | } |
| | 408 | |
| | 409 | var emit_type = Module.Emit.Binary; |
| | 410 | if (flags.single("emit")) |emit_flag| { |
| | 411 | if (mem.eql(u8, emit_flag, "asm")) { |
| | 412 | emit_type = Module.Emit.Assembly; |
| | 413 | } else if (mem.eql(u8, emit_flag, "bin")) { |
| | 414 | emit_type = Module.Emit.Binary; |
| | 415 | } else if (mem.eql(u8, emit_flag, "llvm-ir")) { |
| | 416 | emit_type = Module.Emit.LlvmIr; |
| | 417 | } else { |
| | 418 | unreachable; |
| | 419 | } |
| | 420 | } |
| | 421 | |
| | 422 | var cur_pkg = try Module.CliPkg.init(allocator, "", "", null); // TODO: Need a path, name? |
| | 423 | defer cur_pkg.deinit(); |
| | 424 | |
| | 425 | var i: usize = 0; |
| | 426 | while (i < args.len) : (i += 1) { |
| | 427 | const arg_name = args[i]; |
| | 428 | if (mem.eql(u8, "--pkg-begin", arg_name)) { |
| | 429 | // following two arguments guaranteed to exist due to arg parsing |
| | 430 | i += 1; |
| | 431 | const new_pkg_name = args[i]; |
| | 432 | i += 1; |
| | 433 | const new_pkg_path = args[i]; |
| | 434 | |
| | 435 | var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg); |
| | 436 | try cur_pkg.children.append(new_cur_pkg); |
| | 437 | cur_pkg = new_cur_pkg; |
| | 438 | } else if (mem.eql(u8, "--pkg-end", arg_name)) { |
| | 439 | if (cur_pkg.parent == null) { |
| | 440 | try stderr.print("encountered --pkg-end with no matching --pkg-begin\n"); |
| | 441 | os.exit(1); |
| | 442 | } |
| | 443 | cur_pkg = ??cur_pkg.parent; |
| | 444 | } |
| | 445 | } |
| | 446 | |
| | 447 | if (cur_pkg.parent != null) { |
| | 448 | try stderr.print("unmatched --pkg-begin\n"); |
| | 449 | os.exit(1); |
| | 450 | } |
| | 451 | |
| | 452 | var in_file: ?[]const u8 = undefined; |
| | 453 | switch (flags.positionals.len) { |
| | 454 | 0 => { |
| | 455 | try stderr.write("--name [name] not provided and unable to infer\n"); |
| 717 | os.exit(1); | 456 | os.exit(1); |
| 718 | }, | 457 | }, |
| | 458 | 1 => { |
| | 459 | in_file = flags.positionals.at(0); |
| | 460 | }, |
| | 461 | else => { |
| | 462 | try stderr.write("only one zig input file is accepted during build\n"); |
| | 463 | os.exit(1); |
| | 464 | }, |
| | 465 | } |
| | 466 | |
| | 467 | const basename = os.path.basename(??in_file); |
| | 468 | var it = mem.split(basename, "."); |
| | 469 | const root_name = it.next() ?? { |
| | 470 | try stderr.write("file name cannot be empty\n"); |
| | 471 | os.exit(1); |
| | 472 | }; |
| | 473 | |
| | 474 | const asm_a= flags.many("assembly"); |
| | 475 | const obj_a = flags.many("object"); |
| | 476 | if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) { |
| | 477 | try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); |
| | 478 | os.exit(1); |
| | 479 | } |
| | 480 | |
| | 481 | if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) { |
| | 482 | try stderr.write("When building an object file, --object arguments are invalid\n"); |
| | 483 | os.exit(1); |
| | 484 | } |
| | 485 | |
| | 486 | const zig_root_source_file = in_file; |
| | 487 | |
| | 488 | const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch { |
| | 489 | os.exit(1); |
| | 490 | }; |
| | 491 | defer allocator.free(full_cache_dir); |
| | 492 | |
| | 493 | const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1); |
| | 494 | defer allocator.free(zig_lib_dir); |
| | 495 | |
| | 496 | var module = |
| | 497 | try Module.create( |
| | 498 | allocator, |
| | 499 | root_name, |
| | 500 | zig_root_source_file, |
| | 501 | Target.Native, |
| | 502 | out_type, |
| | 503 | build_mode, |
| | 504 | zig_lib_dir, |
| | 505 | full_cache_dir |
| | 506 | ); |
| | 507 | defer module.destroy(); |
| | 508 | |
| | 509 | module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10); |
| | 510 | module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10); |
| | 511 | module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10); |
| | 512 | |
| | 513 | module.is_test = false; |
| | 514 | |
| | 515 | if (flags.single("linker-script")) |linker_script| { |
| | 516 | module.linker_script = linker_script; |
| | 517 | } |
| | 518 | |
| | 519 | module.each_lib_rpath = flags.present("each-lib-rpath"); |
| | 520 | |
| | 521 | var clang_argv_buf = ArrayList([]const u8).init(allocator); |
| | 522 | defer clang_argv_buf.deinit(); |
| | 523 | if (flags.many("mllvm")) |mllvm_flags| { |
| | 524 | for (mllvm_flags) |mllvm| { |
| | 525 | try clang_argv_buf.append("-mllvm"); |
| | 526 | try clang_argv_buf.append(mllvm); |
| | 527 | } |
| | 528 | |
| | 529 | module.llvm_argv = mllvm_flags; |
| | 530 | module.clang_argv = clang_argv_buf.toSliceConst(); |
| | 531 | } |
| | 532 | |
| | 533 | module.strip = flags.present("strip"); |
| | 534 | module.is_static = flags.present("static"); |
| | 535 | |
| | 536 | if (flags.single("libc-lib-dir")) |libc_lib_dir| { |
| | 537 | module.libc_lib_dir = libc_lib_dir; |
| | 538 | } |
| | 539 | if (flags.single("libc-static-lib-dir")) |libc_static_lib_dir| { |
| | 540 | module.libc_static_lib_dir = libc_static_lib_dir; |
| | 541 | } |
| | 542 | if (flags.single("libc-include-dir")) |libc_include_dir| { |
| | 543 | module.libc_include_dir = libc_include_dir; |
| | 544 | } |
| | 545 | if (flags.single("msvc-lib-dir")) |msvc_lib_dir| { |
| | 546 | module.msvc_lib_dir = msvc_lib_dir; |
| | 547 | } |
| | 548 | if (flags.single("kernel32-lib-dir")) |kernel32_lib_dir| { |
| | 549 | module.kernel32_lib_dir = kernel32_lib_dir; |
| | 550 | } |
| | 551 | if (flags.single("dynamic-linker")) |dynamic_linker| { |
| | 552 | module.dynamic_linker = dynamic_linker; |
| | 553 | } |
| | 554 | |
| | 555 | module.verbose_tokenize = flags.present("verbose-tokenize"); |
| | 556 | module.verbose_ast_tree = flags.present("verbose-ast-tree"); |
| | 557 | module.verbose_ast_fmt = flags.present("verbose-ast-fmt"); |
| | 558 | module.verbose_link = flags.present("verbose-link"); |
| | 559 | module.verbose_ir = flags.present("verbose-ir"); |
| | 560 | module.verbose_llvm_ir = flags.present("verbose-llvm-ir"); |
| | 561 | module.verbose_cimport = flags.present("verbose-cimport"); |
| | 562 | |
| | 563 | module.err_color = color; |
| | 564 | |
| | 565 | if (flags.many("library-path")) |lib_dirs| { |
| | 566 | module.lib_dirs = lib_dirs; |
| | 567 | } |
| | 568 | |
| | 569 | if (flags.many("framework")) |frameworks| { |
| | 570 | module.darwin_frameworks = frameworks; |
| | 571 | } |
| | 572 | |
| | 573 | if (flags.many("rpath")) |rpath_list| { |
| | 574 | module.rpath_list = rpath_list; |
| 719 | } | 575 | } |
| | 576 | |
| | 577 | if (flags.single("output-h")) |output_h| { |
| | 578 | module.out_h_path = output_h; |
| | 579 | } |
| | 580 | |
| | 581 | module.windows_subsystem_windows = flags.present("mwindows"); |
| | 582 | module.windows_subsystem_console = flags.present("mconsole"); |
| | 583 | module.linker_rdynamic = flags.present("rdynamic"); |
| | 584 | |
| | 585 | if (flags.single("mmacosx-version-min") != null and flags.single("mios-version-min") != null) { |
| | 586 | try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n"); |
| | 587 | os.exit(1); |
| | 588 | } |
| | 589 | |
| | 590 | if (flags.single("mmacosx-version-min")) |ver| { |
| | 591 | module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver }; |
| | 592 | } |
| | 593 | if (flags.single("mios-version-min")) |ver| { |
| | 594 | module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver }; |
| | 595 | } |
| | 596 | |
| | 597 | module.emit_file_type = emit_type; |
| | 598 | if (flags.many("object")) |objects| { |
| | 599 | module.link_objects = objects; |
| | 600 | } |
| | 601 | if (flags.many("assembly")) |assembly_files| { |
| | 602 | module.assembly_files = assembly_files; |
| | 603 | } |
| | 604 | |
| | 605 | try module.build(); |
| | 606 | try module.link(flags.single("out-file") ?? null); |
| | 607 | |
| | 608 | if (flags.present("print-timing-info")) { |
| | 609 | // codegen_print_timing_info(g, stderr); |
| | 610 | } |
| | 611 | |
| | 612 | try stderr.print("building {}: {}\n", @tagName(out_type), in_file); |
| | 613 | } |
| | 614 | |
| | 615 | fn cmdBuildExe(allocator: &Allocator, args: []const []const u8) !void { |
| | 616 | try buildOutputType(allocator, args, Module.Kind.Exe); |
| 720 | } | 617 | } |
| 721 | | 618 | |
| 722 | fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { | 619 | // cmd:build-lib /////////////////////////////////////////////////////////////////////////////////// |
| 723 | for (file_paths) |file_path| { | 620 | |
| | 621 | fn cmdBuildLib(allocator: &Allocator, args: []const []const u8) !void { |
| | 622 | try buildOutputType(allocator, args, Module.Kind.Lib); |
| | 623 | } |
| | 624 | |
| | 625 | // cmd:build-obj /////////////////////////////////////////////////////////////////////////////////// |
| | 626 | |
| | 627 | fn cmdBuildObj(allocator: &Allocator, args: []const []const u8) !void { |
| | 628 | try buildOutputType(allocator, args, Module.Kind.Obj); |
| | 629 | } |
| | 630 | |
| | 631 | // cmd:fmt ///////////////////////////////////////////////////////////////////////////////////////// |
| | 632 | |
| | 633 | const usage_fmt = |
| | 634 | \\usage: zig fmt [file]... |
| | 635 | \\ |
| | 636 | \\ Formats the input files and modifies them in-place. |
| | 637 | \\ |
| | 638 | \\Options: |
| | 639 | \\ --help Print this help and exit |
| | 640 | \\ --keep-backups Retain backup entries for every file |
| | 641 | \\ |
| | 642 | \\ |
| | 643 | ; |
| | 644 | |
| | 645 | const args_fmt_spec = []Flag { |
| | 646 | Flag.Bool("--help"), |
| | 647 | Flag.Bool("--keep-backups"), |
| | 648 | }; |
| | 649 | |
| | 650 | fn cmdFmt(allocator: &Allocator, args: []const []const u8) !void { |
| | 651 | var flags = try Args.parse(allocator, args_fmt_spec, args); |
| | 652 | defer flags.deinit(); |
| | 653 | |
| | 654 | if (flags.present("help")) { |
| | 655 | try stderr.write(usage_fmt); |
| | 656 | os.exit(0); |
| | 657 | } |
| | 658 | |
| | 659 | if (flags.positionals.len == 0) { |
| | 660 | try stderr.write("expected at least one source file argument\n"); |
| | 661 | os.exit(1); |
| | 662 | } |
| | 663 | |
| | 664 | for (flags.positionals.toSliceConst()) |file_path| { |
| 724 | var file = try os.File.openRead(allocator, file_path); | 665 | var file = try os.File.openRead(allocator, file_path); |
| 725 | defer file.close(); | 666 | defer file.close(); |
| 726 | | 667 | |
| 727 | const source_code = io.readFileAlloc(allocator, file_path) catch |err| { | 668 | const source_code = io.readFileAlloc(allocator, file_path) catch |err| { |
| 728 | warn("unable to open '{}': {}", file_path, err); | 669 | try stderr.print("unable to open '{}': {}", file_path, err); |
| 729 | continue; | 670 | continue; |
| 730 | }; | 671 | }; |
| 731 | defer allocator.free(source_code); | 672 | defer allocator.free(source_code); |
| ... | @@ -734,72 +675,312 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { | ... | @@ -734,72 +675,312 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { |
| 734 | var parser = std.zig.Parser.init(&tokenizer, allocator, file_path); | 675 | var parser = std.zig.Parser.init(&tokenizer, allocator, file_path); |
| 735 | defer parser.deinit(); | 676 | defer parser.deinit(); |
| 736 | | 677 | |
| 737 | var tree = try parser.parse(); | 678 | var tree = parser.parse() catch |err| { |
| | 679 | try stderr.print("error parsing file '{}': {}\n", file_path, err); |
| | 680 | continue; |
| | 681 | }; |
| 738 | defer tree.deinit(); | 682 | defer tree.deinit(); |
| 739 | | 683 | |
| 740 | const baf = try io.BufferedAtomicFile.create(allocator, file_path); | 684 | var original_file_backup = try Buffer.init(allocator, file_path); |
| 741 | defer baf.destroy(); | 685 | defer original_file_backup.deinit(); |
| | 686 | try original_file_backup.append(".backup"); |
| | 687 | |
| | 688 | try os.rename(allocator, file_path, original_file_backup.toSliceConst()); |
| 742 | | 689 | |
| 743 | try parser.renderSource(baf.stream(), tree.root_node); | 690 | try stderr.print("{}\n", file_path); |
| 744 | try baf.finish(); | 691 | |
| | 692 | // TODO: BufferedAtomicFile has some access problems. |
| | 693 | var out_file = try os.File.openWrite(allocator, file_path); |
| | 694 | defer out_file.close(); |
| | 695 | |
| | 696 | var out_file_stream = io.FileOutStream.init(&out_file); |
| | 697 | try parser.renderSource(out_file_stream.stream, tree.root_node); |
| | 698 | |
| | 699 | if (!flags.present("keep-backups")) { |
| | 700 | try os.deleteFile(allocator, original_file_backup.toSliceConst()); |
| | 701 | } |
| 745 | } | 702 | } |
| 746 | } | 703 | } |
| 747 | | 704 | |
| 748 | /// Caller must free result | 705 | // cmd:targets ///////////////////////////////////////////////////////////////////////////////////// |
| 749 | fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 { | 706 | |
| 750 | if (zig_install_prefix_arg) |zig_install_prefix| { | 707 | fn cmdTargets(allocator: &Allocator, args: []const []const u8) !void { |
| 751 | return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| { | 708 | try stdout.write("Architectures:\n"); |
| 752 | warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); | 709 | { |
| 753 | return error.ZigInstallationNotFound; | 710 | comptime var i: usize = 0; |
| 754 | }; | 711 | inline while (i < @memberCount(builtin.Arch)) : (i += 1) { |
| 755 | } else { | 712 | comptime const arch_tag = @memberName(builtin.Arch, i); |
| 756 | return findZigLibDir(allocator) catch |err| { | 713 | // NOTE: Cannot use empty string, see #918. |
| 757 | warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n", | 714 | comptime const native_str = |
| 758 | @errorName(err)); | 715 | if (comptime mem.eql(u8, arch_tag, @tagName(builtin.arch))) " (native)\n" else "\n"; |
| 759 | return error.ZigLibDirNotFound; | 716 | |
| 760 | }; | 717 | try stdout.print(" {}{}", arch_tag, native_str); |
| | 718 | } |
| | 719 | } |
| | 720 | try stdout.write("\n"); |
| | 721 | |
| | 722 | try stdout.write("Operating Systems:\n"); |
| | 723 | { |
| | 724 | comptime var i: usize = 0; |
| | 725 | inline while (i < @memberCount(builtin.Os)) : (i += 1) { |
| | 726 | comptime const os_tag = @memberName(builtin.Os, i); |
| | 727 | // NOTE: Cannot use empty string, see #918. |
| | 728 | comptime const native_str = |
| | 729 | if (comptime mem.eql(u8, os_tag, @tagName(builtin.os))) " (native)\n" else "\n"; |
| | 730 | |
| | 731 | try stdout.print(" {}{}", os_tag, native_str); |
| | 732 | } |
| | 733 | } |
| | 734 | try stdout.write("\n"); |
| | 735 | |
| | 736 | try stdout.write("Environments:\n"); |
| | 737 | { |
| | 738 | comptime var i: usize = 0; |
| | 739 | inline while (i < @memberCount(builtin.Environ)) : (i += 1) { |
| | 740 | comptime const environ_tag = @memberName(builtin.Environ, i); |
| | 741 | // NOTE: Cannot use empty string, see #918. |
| | 742 | comptime const native_str = |
| | 743 | if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n"; |
| | 744 | |
| | 745 | try stdout.print(" {}{}", environ_tag, native_str); |
| | 746 | } |
| 761 | } | 747 | } |
| 762 | } | 748 | } |
| 763 | | 749 | |
| 764 | /// Caller must free result | 750 | // cmd:version ///////////////////////////////////////////////////////////////////////////////////// |
| 765 | fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 { | 751 | |
| 766 | const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig"); | 752 | fn cmdVersion(allocator: &Allocator, args: []const []const u8) !void { |
| 767 | errdefer allocator.free(test_zig_dir); | 753 | try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING)); |
| | 754 | } |
| 768 | | 755 | |
| 769 | const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig"); | 756 | // cmd:test //////////////////////////////////////////////////////////////////////////////////////// |
| 770 | defer allocator.free(test_index_file); | | |
| 771 | | 757 | |
| 772 | var file = try os.File.openRead(allocator, test_index_file); | 758 | const usage_test = |
| 773 | file.close(); | 759 | \\usage: zig test [file]... |
| | 760 | \\ |
| | 761 | \\Options: |
| | 762 | \\ --help Print this help and exit |
| | 763 | \\ |
| | 764 | \\ |
| | 765 | ; |
| | 766 | |
| | 767 | const args_test_spec = []Flag { |
| | 768 | Flag.Bool("--help"), |
| | 769 | }; |
| | 770 | |
| | 771 | |
| | 772 | fn cmdTest(allocator: &Allocator, args: []const []const u8) !void { |
| | 773 | var flags = try Args.parse(allocator, args_build_spec, args); |
| | 774 | defer flags.deinit(); |
| | 775 | |
| | 776 | if (flags.present("help")) { |
| | 777 | try stderr.write(usage_test); |
| | 778 | os.exit(0); |
| | 779 | } |
| 774 | | 780 | |
| 775 | return test_zig_dir; | 781 | if (flags.positionals.len != 1) { |
| | 782 | try stderr.write("expected exactly one zig source file\n"); |
| | 783 | os.exit(1); |
| | 784 | } |
| | 785 | |
| | 786 | // compile the test program into the cache and run |
| | 787 | |
| | 788 | // NOTE: May be overlap with buildOutput, take the shared part out. |
| | 789 | try stderr.print("testing file {}\n", flags.positionals.at(0)); |
| 776 | } | 790 | } |
| 777 | | 791 | |
| 778 | /// Caller must free result | 792 | // cmd:run ///////////////////////////////////////////////////////////////////////////////////////// |
| 779 | fn findZigLibDir(allocator: &mem.Allocator) ![]u8 { | 793 | |
| 780 | const self_exe_path = try os.selfExeDirPath(allocator); | 794 | // Run should be simple and not expose the full set of arguments provided by build-exe. If specific |
| 781 | defer allocator.free(self_exe_path); | 795 | // build requirements are need, the user should `build-exe` then `run` manually. |
| | 796 | const usage_run = |
| | 797 | \\usage: zig run [file] -- <runtime args> |
| | 798 | \\ |
| | 799 | \\Options: |
| | 800 | \\ --help Print this help and exit |
| | 801 | \\ |
| | 802 | \\ |
| | 803 | ; |
| | 804 | |
| | 805 | const args_run_spec = []Flag { |
| | 806 | Flag.Bool("--help"), |
| | 807 | }; |
| 782 | | 808 | |
| 783 | var cur_path: []const u8 = self_exe_path; | | |
| 784 | while (true) { | | |
| 785 | const test_dir = os.path.dirname(cur_path); | | |
| 786 | | 809 | |
| 787 | if (mem.eql(u8, test_dir, cur_path)) { | 810 | fn cmdRun(allocator: &Allocator, args: []const []const u8) !void { |
| | 811 | var compile_args = args; |
| | 812 | var runtime_args: []const []const u8 = []const []const u8 {}; |
| | 813 | |
| | 814 | for (args) |argv, i| { |
| | 815 | if (mem.eql(u8, argv, "--")) { |
| | 816 | compile_args = args[0..i]; |
| | 817 | runtime_args = args[i+1..]; |
| 788 | break; | 818 | break; |
| 789 | } | 819 | } |
| | 820 | } |
| | 821 | var flags = try Args.parse(allocator, args_run_spec, compile_args); |
| | 822 | defer flags.deinit(); |
| 790 | | 823 | |
| 791 | return testZigInstallPrefix(allocator, test_dir) catch |err| { | 824 | if (flags.present("help")) { |
| 792 | cur_path = test_dir; | 825 | try stderr.write(usage_run); |
| 793 | continue; | 826 | os.exit(0); |
| 794 | }; | 827 | } |
| | 828 | |
| | 829 | if (flags.positionals.len != 1) { |
| | 830 | try stderr.write("expected exactly one zig source file\n"); |
| | 831 | os.exit(1); |
| | 832 | } |
| | 833 | |
| | 834 | try stderr.print("runtime args:\n"); |
| | 835 | for (runtime_args) |cargs| { |
| | 836 | try stderr.print("{}\n", cargs); |
| | 837 | } |
| | 838 | } |
| | 839 | |
| | 840 | // cmd:translate-c ///////////////////////////////////////////////////////////////////////////////// |
| | 841 | |
| | 842 | const usage_translate_c = |
| | 843 | \\usage: zig translate-c [file] |
| | 844 | \\ |
| | 845 | \\Options: |
| | 846 | \\ --help Print this help and exit |
| | 847 | \\ --enable-timing-info Print timing diagnostics |
| | 848 | \\ --output [path] Output file to write generated zig file (default: stdout) |
| | 849 | \\ |
| | 850 | \\ |
| | 851 | ; |
| | 852 | |
| | 853 | const args_translate_c_spec = []Flag { |
| | 854 | Flag.Bool("--help"), |
| | 855 | Flag.Bool("--enable-timing-info"), |
| | 856 | Flag.Arg1("--libc-include-dir"), |
| | 857 | Flag.Arg1("--output"), |
| | 858 | }; |
| | 859 | |
| | 860 | fn cmdTranslateC(allocator: &Allocator, args: []const []const u8) !void { |
| | 861 | var flags = try Args.parse(allocator, args_translate_c_spec, args); |
| | 862 | defer flags.deinit(); |
| | 863 | |
| | 864 | if (flags.present("help")) { |
| | 865 | try stderr.write(usage_translate_c); |
| | 866 | os.exit(0); |
| | 867 | } |
| | 868 | |
| | 869 | if (flags.positionals.len != 1) { |
| | 870 | try stderr.write("expected exactly one c source file\n"); |
| | 871 | os.exit(1); |
| | 872 | } |
| | 873 | |
| | 874 | // set up codegen |
| | 875 | |
| | 876 | const zig_root_source_file = null; |
| | 877 | |
| | 878 | // NOTE: translate-c shouldn't require setting up the full codegen instance as it does in |
| | 879 | // the C++ compiler. |
| | 880 | |
| | 881 | // codegen_create(g); |
| | 882 | // codegen_set_out_name(g, null); |
| | 883 | // codegen_translate_c(g, flags.positional.at(0)) |
| | 884 | |
| | 885 | var output_stream = stdout; |
| | 886 | if (flags.single("output")) |output_file| { |
| | 887 | var file = try os.File.openWrite(allocator, output_file); |
| | 888 | defer file.close(); |
| | 889 | |
| | 890 | var file_stream = io.FileOutStream.init(&file); |
| | 891 | // TODO: Not being set correctly, still stdout |
| | 892 | output_stream = &file_stream.stream; |
| 795 | } | 893 | } |
| 796 | | 894 | |
| 797 | // TODO look in hard coded installation path from configuration | 895 | // ast_render(g, output_stream, g->root_import->root, 4); |
| 798 | //if (ZIG_INSTALL_PREFIX != nullptr) { | 896 | try output_stream.write("pub const example = 10;\n"); |
| 799 | // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { | 897 | |
| 800 | // return 0; | 898 | if (flags.present("enable-timing-info")) { |
| 801 | // } | 899 | // codegen_print_timing_info(g, stdout); |
| 802 | //} | 900 | try stderr.write("printing timing info for translate-c\n"); |
| | 901 | } |
| | 902 | } |
| | 903 | |
| | 904 | // cmd:help //////////////////////////////////////////////////////////////////////////////////////// |
| 803 | | 905 | |
| 804 | return error.FileNotFound; | 906 | fn cmdHelp(allocator: &Allocator, args: []const []const u8) !void { |
| | 907 | try stderr.write(usage); |
| | 908 | } |
| | 909 | |
| | 910 | // cmd:zen ///////////////////////////////////////////////////////////////////////////////////////// |
| | 911 | |
| | 912 | const info_zen = |
| | 913 | \\ |
| | 914 | \\ * Communicate intent precisely. |
| | 915 | \\ * Edge cases matter. |
| | 916 | \\ * Favor reading code over writing code. |
| | 917 | \\ * Only one obvious way to do things. |
| | 918 | \\ * Runtime crashes are better than bugs. |
| | 919 | \\ * Compile errors are better than runtime crashes. |
| | 920 | \\ * Incremental improvements. |
| | 921 | \\ * Avoid local maximums. |
| | 922 | \\ * Reduce the amount one must remember. |
| | 923 | \\ * Minimize energy spent on coding style. |
| | 924 | \\ * Together we serve end users. |
| | 925 | \\ |
| | 926 | \\ |
| | 927 | ; |
| | 928 | |
| | 929 | fn cmdZen(allocator: &Allocator, args: []const []const u8) !void { |
| | 930 | try stdout.write(info_zen); |
| | 931 | } |
| | 932 | |
| | 933 | // cmd:internal //////////////////////////////////////////////////////////////////////////////////// |
| | 934 | |
| | 935 | const usage_internal = |
| | 936 | \\usage: zig internal [subcommand] |
| | 937 | \\ |
| | 938 | \\Sub-Commands: |
| | 939 | \\ build-info Print static compiler build-info |
| | 940 | \\ |
| | 941 | \\ |
| | 942 | ; |
| | 943 | |
| | 944 | fn cmdInternal(allocator: &Allocator, args: []const []const u8) !void { |
| | 945 | if (args.len == 0) { |
| | 946 | try stderr.write(usage_internal); |
| | 947 | os.exit(1); |
| | 948 | } |
| | 949 | |
| | 950 | const sub_commands = []Command { |
| | 951 | Command { .name = "build-info", .exec = cmdInternalBuildInfo }, |
| | 952 | }; |
| | 953 | |
| | 954 | for (sub_commands) |sub_command| { |
| | 955 | if (mem.eql(u8, sub_command.name, args[0])) { |
| | 956 | try sub_command.exec(allocator, args[1..]); |
| | 957 | return; |
| | 958 | } |
| | 959 | } |
| | 960 | |
| | 961 | try stderr.print("unknown sub command: {}\n\n", args[0]); |
| | 962 | try stderr.write(usage_internal); |
| | 963 | } |
| | 964 | |
| | 965 | fn cmdInternalBuildInfo(allocator: &Allocator, args: []const []const u8) !void { |
| | 966 | try stdout.print( |
| | 967 | \\ZIG_CMAKE_BINARY_DIR {} |
| | 968 | \\ZIG_CXX_COMPILER {} |
| | 969 | \\ZIG_LLVM_CONFIG_EXE {} |
| | 970 | \\ZIG_LLD_INCLUDE_PATH {} |
| | 971 | \\ZIG_LLD_LIBRARIES {} |
| | 972 | \\ZIG_STD_FILES {} |
| | 973 | \\ZIG_C_HEADER_FILES {} |
| | 974 | \\ZIG_DIA_GUIDS_LIB {} |
| | 975 | \\ |
| | 976 | , |
| | 977 | std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), |
| | 978 | std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), |
| | 979 | std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE), |
| | 980 | std.cstr.toSliceConst(c.ZIG_LLD_INCLUDE_PATH), |
| | 981 | std.cstr.toSliceConst(c.ZIG_LLD_LIBRARIES), |
| | 982 | std.cstr.toSliceConst(c.ZIG_STD_FILES), |
| | 983 | std.cstr.toSliceConst(c.ZIG_C_HEADER_FILES), |
| | 984 | std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), |
| | 985 | ); |
| 805 | } | 986 | } |