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