| ... | ... | @@ -1,731 +1,720 @@ |
| 1 | 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 | 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 { |
| 20 | | None, |
| 21 | | Build, |
| 22 | | Test, |
| 23 | | Version, |
| 24 | | Zen, |
| 25 | | TranslateC, |
| 26 | | Targets, |
| 11 | const arg = @import("arg.zig"); |
| 12 | const c = @import("c.zig"); |
| 13 | const introspect = @import("introspect.zig"); |
| 14 | const Args = arg.Args; |
| 15 | const Flag = arg.Flag; |
| 16 | const Module = @import("module.zig").Module; |
| 17 | const Target = @import("target.zig").Target; |
| 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 | 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 | 59 | const args = try os.argsAlloc(allocator); |
| 42 | 60 | defer os.argsFree(allocator, args); |
| 43 | 61 | |
| 44 | | if (args.len >= 2 and mem.eql(u8, args[1], "build")) { |
| 45 | | return buildMain(allocator, args[2..]); |
| 46 | | } |
| 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, |
| 62 | if (args.len <= 1) { |
| 63 | try stderr.write(usage); |
| 64 | os.exit(1); |
| 65 | } |
| 66 | |
| 67 | const commands = []Command { |
| 68 | Command { .name = "build", .exec = cmdBuild }, |
| 69 | Command { .name = "build-exe", .exec = cmdBuildExe }, |
| 70 | Command { .name = "build-lib", .exec = cmdBuildLib }, |
| 71 | Command { .name = "build-obj", .exec = cmdBuildObj }, |
| 72 | Command { .name = "cc", .exec = cmdCc }, |
| 73 | Command { .name = "fmt", .exec = cmdFmt }, |
| 74 | Command { .name = "run", .exec = cmdRun }, |
| 75 | Command { .name = "targets", .exec = cmdTargets }, |
| 76 | Command { .name = "test", .exec = cmdTest }, |
| 77 | Command { .name = "translate-c", .exec = cmdTranslateC }, |
| 78 | Command { .name = "version", .exec = cmdVersion }, |
| 79 | Command { .name = "zen", .exec = cmdZen }, |
| 80 | |
| 81 | // undocumented commands |
| 82 | Command { .name = "help", .exec = cmdHelp }, |
| 83 | Command { .name = "internal", .exec = cmdInternal }, |
| 84 | }; |
| 85 | |
| 86 | for (commands) |command| { |
| 87 | if (mem.eql(u8, command.name, args[1])) { |
| 88 | try command.exec(allocator, args[2..]); |
| 89 | return; |
| 301 | 90 | } |
| 302 | 91 | } |
| 303 | 92 | |
| 304 | | target.initializeAll(); |
| 305 | | |
| 306 | | // TODO |
| 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 | | } |
| 93 | try stderr.print("unknown command: {}\n\n", args[1]); |
| 94 | try stderr.write(usage); |
| 95 | } |
| 345 | 96 | |
| 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 | | } |
| 97 | // cmd:build /////////////////////////////////////////////////////////////////////////////////////// |
| 98 | |
| 99 | const usage_build = |
| 100 | \\usage: zig build <options> |
| 101 | \\ |
| 102 | \\General Options: |
| 103 | \\ --help Print this help and exit |
| 104 | \\ --init Generate a build.zig template |
| 105 | \\ --build-file [file] Override path to build.zig |
| 106 | \\ --cache-dir [path] Override path to cache directory |
| 107 | \\ --verbose Print commands before executing them |
| 108 | \\ --prefix [path] Override default install prefix |
| 109 | \\ --zig-install-prefix [path] Override directory where zig thinks it is installed |
| 110 | \\ |
| 111 | \\Project-Specific Options: |
| 112 | \\ |
| 113 | \\ Project-specific options become available when the build file is found. |
| 114 | \\ |
| 115 | \\Advanced Options: |
| 116 | \\ --build-file [file] Override path to build.zig |
| 117 | \\ --cache-dir [path] Override path to cache directory |
| 118 | \\ --verbose-tokenize Enable compiler debug output for tokenization |
| 119 | \\ --verbose-ast Enable compiler debug output for parsing into an AST |
| 120 | \\ --verbose-link Enable compiler debug output for linking |
| 121 | \\ --verbose-ir Enable compiler debug output for Zig IR |
| 122 | \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR |
| 123 | \\ --verbose-cimport Enable compiler debug output for C imports |
| 124 | \\ |
| 125 | \\ |
| 126 | ; |
| 127 | |
| 128 | const args_build_spec = []Flag { |
| 129 | Flag.Bool("--help"), |
| 130 | Flag.Bool("--init"), |
| 131 | Flag.Arg1("--build-file"), |
| 132 | Flag.Arg1("--cache-dir"), |
| 133 | Flag.Bool("--verbose"), |
| 134 | Flag.Arg1("--prefix"), |
| 135 | Flag.Arg1("--zig-install-prefix"), |
| 136 | |
| 137 | Flag.Arg1("--build-file"), |
| 138 | Flag.Arg1("--cache-dir"), |
| 139 | Flag.Bool("--verbose-tokenize"), |
| 140 | Flag.Bool("--verbose-ast"), |
| 141 | Flag.Bool("--verbose-link"), |
| 142 | Flag.Bool("--verbose-ir"), |
| 143 | Flag.Bool("--verbose-llvm-ir"), |
| 144 | Flag.Bool("--verbose-cimport"), |
| 145 | }; |
| 424 | 146 | |
| 425 | | module.windows_subsystem_windows = mwindows; |
| 426 | | module.windows_subsystem_console = mconsole; |
| 427 | | module.linker_rdynamic = rdynamic; |
| 147 | const missing_build_file = |
| 148 | \\No 'build.zig' file found. |
| 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) { |
| 430 | | badArgs("-mmacosx-version-min and -mios-version-min options not allowed together"); |
| 431 | | } |
| 166 | const zig_lib_dir = try introspect.resolveZigLibDir(allocator, flags.single("zig-install-prefix") ?? null); |
| 167 | defer allocator.free(zig_lib_dir); |
| 432 | 168 | |
| 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 | | } |
| 169 | const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std"); |
| 170 | defer allocator.free(zig_std_dir); |
| 171 | |
| 172 | const special_dir = try os.path.join(allocator, zig_std_dir, "special"); |
| 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(); |
| 440 | | module.test_name_prefix = test_name_prefix_arg; |
| 441 | | module.out_h_path = out_file_h; |
| 225 | const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build"); |
| 226 | defer allocator.free(path_to_build_exe); |
| 442 | 227 | |
| 443 | | // TODO |
| 444 | | //add_package(g, cur_pkg, g->root_package); |
| 228 | try build_args.append(path_to_build_exe); |
| 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) { |
| 447 | | Cmd.Build => { |
| 448 | | module.emit_file_type = emit_file_type; |
| 233 | if (flags.single("zig-install-prefix")) |zig_install_prefix| { |
| 234 | try build_args.append(zig_install_prefix); |
| 235 | } |
| 449 | 236 | |
| 450 | | module.link_objects = objects.toSliceConst(); |
| 451 | | module.assembly_files = asm_files.toSliceConst(); |
| 237 | var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator); |
| 238 | defer proc.deinit(); |
| 452 | 239 | |
| 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, |
| 240 | var term = try proc.spawnAndWait(); |
| 241 | switch (term) { |
| 242 | os.ChildProcess.Term.Exited => |status| { |
| 243 | if (status != 0) { |
| 244 | try stderr.print("{} exited with status {}\n", build_args.at(0), status); |
| 245 | os.exit(1); |
| 459 | 246 | } |
| 460 | 247 | }, |
| 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"); |
| 248 | os.ChildProcess.Term.Signal => |signal| { |
| 249 | try stderr.print("{} killed by signal {}\n", build_args.at(0), signal); |
| 250 | os.exit(1); |
| 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 { |
| 471 | | try stream.write( |
| 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 | | } |
| 263 | // cmd:build-exe /////////////////////////////////////////////////////////////////////////////////// |
| 264 | |
| 265 | const usage_build_generic = |
| 266 | \\usage: zig build-exe <options> [file] |
| 267 | \\ zig build-lib <options> [file] |
| 268 | \\ zig build-obj <options> [file] |
| 269 | \\ |
| 270 | \\General Options: |
| 271 | \\ --help Print this help and exit |
| 272 | \\ --color [auto|off|on] Enable or disable colored error messages |
| 273 | \\ |
| 274 | \\Compile Options: |
| 275 | \\ --assembly [source] Add assembly file to build |
| 276 | \\ --cache-dir [path] Override the cache directory |
| 277 | \\ --emit [filetype] Emit a specific file format as compilation output |
| 278 | \\ --enable-timing-info Print timing diagnostics |
| 279 | \\ --libc-include-dir [path] Directory where libc stdlib.h resides |
| 280 | \\ --name [name] Override output name |
| 281 | \\ --output [file] Override destination path |
| 282 | \\ --output-h [file] Override generated header file path |
| 283 | \\ --pkg-begin [name] [path] Make package available to import and push current pkg |
| 284 | \\ --pkg-end Pop current pkg |
| 285 | \\ --release-fast Build with optimizations on and safety off |
| 286 | \\ --release-safe Build with optimizations on and safety on |
| 287 | \\ --static Output will be statically linked |
| 288 | \\ --strip Exclude debug symbols |
| 289 | \\ --target-arch [name] Specify target architecture |
| 290 | \\ --target-environ [name] Specify target environment |
| 291 | \\ --target-os [name] Specify target operating system |
| 292 | \\ --verbose-tokenize Turn on compiler debug output for tokenization |
| 293 | \\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view) |
| 294 | \\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source) |
| 295 | \\ --verbose-link Turn on compiler debug output for linking |
| 296 | \\ --verbose-ir Turn on compiler debug output for Zig IR |
| 297 | \\ --verbose-llvm-ir Turn on compiler debug output for LLVM IR |
| 298 | \\ --verbose-cimport Turn on compiler debug output for C imports |
| 299 | \\ --zig-install-prefix [path] Override directory where zig thinks it is installed |
| 300 | \\ -dirafter [dir] Same as -isystem but do it last |
| 301 | \\ -isystem [dir] Add additional search path for other .h files |
| 302 | \\ -mllvm [arg] Additional arguments to forward to LLVM's option processing |
| 303 | \\ |
| 304 | \\Link Options: |
| 305 | \\ --ar-path [path] Set the path to ar |
| 306 | \\ --dynamic-linker [path] Set the path to ld.so |
| 307 | \\ --each-lib-rpath Add rpath for each used dynamic library |
| 308 | \\ --libc-lib-dir [path] Directory where libc crt1.o resides |
| 309 | \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides |
| 310 | \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides |
| 311 | \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides |
| 312 | \\ --library [lib] Link against lib |
| 313 | \\ --forbid-library [lib] Make it an error to link against lib |
| 314 | \\ --library-path [dir] Add a directory to the library search path |
| 315 | \\ --linker-script [path] Use a custom linker script |
| 316 | \\ --object [obj] Add object file to build |
| 317 | \\ -rdynamic Add all symbols to the dynamic symbol table |
| 318 | \\ -rpath [path] Add directory to the runtime library search path |
| 319 | \\ -mconsole (windows) --subsystem console to the linker |
| 320 | \\ -mwindows (windows) --subsystem windows to the linker |
| 321 | \\ -framework [name] (darwin) link against framework |
| 322 | \\ -mios-version-min [ver] (darwin) set iOS deployment target |
| 323 | \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target |
| 324 | \\ --ver-major [ver] Dynamic library semver major version |
| 325 | \\ --ver-minor [ver] Dynamic library semver minor version |
| 326 | \\ --ver-patch [ver] Dynamic library semver patch version |
| 327 | \\ |
| 328 | \\ |
| 329 | ; |
| 330 | |
| 331 | const args_build_generic = []Flag { |
| 332 | Flag.Bool("--help"), |
| 333 | Flag.Option("--color", []const []const u8 { "auto", "off", "on" }), |
| 334 | |
| 335 | Flag.ArgMergeN("--assembly", 1), |
| 336 | Flag.Arg1("--cache-dir"), |
| 337 | Flag.Option("--emit", []const []const u8 { "asm", "bin", "llvm-ir" }), |
| 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 { |
| 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 | | } |
| 390 | fn buildOutputType(allocator: &Allocator, args: []const []const u8, out_type: Module.Kind) !void { |
| 391 | var flags = try Args.parse(allocator, args_build_generic, args); |
| 392 | defer flags.deinit(); |
| 566 | 393 | |
| 567 | | fn buildMain(allocator: &mem.Allocator, argv: []const []const u8) !void { |
| 568 | | var build_file: [] const u8 = "build.zig"; |
| 569 | | var cache_dir: ?[] const u8 = null; |
| 570 | | var zig_install_prefix: ?[] const u8 = null; |
| 571 | | var asked_for_help = false; |
| 572 | | var asked_for_init = false; |
| 394 | if (flags.present("help")) { |
| 395 | try stderr.write(usage_build_generic); |
| 396 | os.exit(0); |
| 397 | } |
| 573 | 398 | |
| 574 | | var args = ArrayList([] const u8).init(allocator); |
| 575 | | defer args.deinit(); |
| 399 | var build_mode = builtin.Mode.Debug; |
| 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); |
| 578 | | defer allocator.free(zig_exe_path); |
| 406 | var color = Module.ErrColor.Auto; |
| 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 |
| 581 | | try args.append(""); // Placeholder for zig_exe_path |
| 582 | | try args.append(""); // Placeholder for build_file_dirname |
| 583 | | try args.append(""); // Placeholder for full_cache_dir |
| 419 | var emit_type = Module.Emit.Binary; |
| 420 | if (flags.single("emit")) |emit_flag| { |
| 421 | if (mem.eql(u8, emit_flag, "asm")) { |
| 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 | 435 | var i: usize = 0; |
| 586 | | while (i < argv.len) : (i += 1) { |
| 587 | | var arg = argv[i]; |
| 588 | | if (mem.eql(u8, arg, "--help")) { |
| 589 | | asked_for_help = true; |
| 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]; |
| 436 | while (i < args.len) : (i += 1) { |
| 437 | const arg_name = args[i]; |
| 438 | if (mem.eql(u8, "--pkg-begin", arg_name)) { |
| 439 | // following two arguments guaranteed to exist due to arg parsing |
| 599 | 440 | i += 1; |
| 600 | | } else if (i + 1 < argv.len and mem.eql(u8, arg, "--zig-install-prefix")) { |
| 601 | | try args.append(arg); |
| 441 | const new_pkg_name = args[i]; |
| 602 | 442 | i += 1; |
| 603 | | zig_install_prefix = argv[i]; |
| 604 | | try args.append(argv[i]); |
| 605 | | } else { |
| 606 | | try args.append(arg); |
| 443 | const new_pkg_path = args[i]; |
| 444 | |
| 445 | var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg); |
| 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); |
| 611 | | defer allocator.free(zig_lib_dir); |
| 457 | if (cur_pkg.parent != null) { |
| 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"); |
| 614 | | defer allocator.free(zig_std_dir); |
| 462 | var in_file: ?[]const u8 = undefined; |
| 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"); |
| 617 | | defer allocator.free(special_dir); |
| 477 | const basename = os.path.basename(??in_file); |
| 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"); |
| 620 | | defer allocator.free(build_runner_path); |
| 484 | const asm_a= flags.many("assembly"); |
| 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, ...) |
| 623 | | // codegen_set_out_name(g, "build") |
| 491 | if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) { |
| 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); |
| 626 | | defer allocator.free(build_file_abs); |
| 496 | const zig_root_source_file = in_file; |
| 627 | 497 | |
| 628 | | const build_file_basename = os.path.basename(build_file_abs); |
| 629 | | const build_file_dirname = os.path.dirname(build_file_abs); |
| 498 | const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch { |
| 499 | os.exit(1); |
| 500 | }; |
| 501 | defer allocator.free(full_cache_dir); |
| 630 | 502 | |
| 631 | | var full_cache_dir: []u8 = undefined; |
| 632 | | if (cache_dir == null) { |
| 633 | | full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache"); |
| 634 | | } else { |
| 635 | | full_cache_dir = try os.path.resolve(allocator, ".", ??cache_dir, full_cache_dir); |
| 503 | const zig_lib_dir = introspect.resolveZigLibDir(allocator, flags.single("zig-install-prefix") ?? null) catch { |
| 504 | os.exit(1); |
| 505 | }; |
| 506 | defer allocator.free(zig_lib_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"); |
| 640 | | defer allocator.free(path_to_build_exe); |
| 641 | | // codegen_set_cache_dir(g, full_cache_dir) |
| 531 | module.each_lib_rpath = flags.present("each-lib-rpath"); |
| 642 | 532 | |
| 643 | | args.items[0] = path_to_build_exe; |
| 644 | | args.items[1] = zig_exe_path; |
| 645 | | args.items[2] = build_file_dirname; |
| 646 | | args.items[3] = full_cache_dir; |
| 533 | var clang_argv_buf = ArrayList([]const u8).init(allocator); |
| 534 | defer clang_argv_buf.deinit(); |
| 535 | if (flags.many("mllvm")) |mllvm_flags| { |
| 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; |
| 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; |
| 541 | module.llvm_argv = mllvm_flags; |
| 542 | module.clang_argv = clang_argv_buf.toSliceConst(); |
| 654 | 543 | } |
| 655 | 544 | |
| 656 | | if (!build_file_exists and asked_for_help) { |
| 657 | | // TODO(bnoordhuis) Print help message from std/special/build_runner.zig |
| 658 | | return; |
| 545 | module.strip = flags.present("strip"); |
| 546 | module.is_static = flags.present("static"); |
| 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) { |
| 662 | | const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig"); |
| 663 | | defer allocator.free(build_template_path); |
| 567 | module.verbose_tokenize = flags.present("verbose-tokenize"); |
| 568 | module.verbose_ast_tree = flags.present("verbose-ast-tree"); |
| 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); |
| 666 | | defer srcfile.close(); |
| 575 | module.err_color = color; |
| 667 | 576 | |
| 668 | | var dstfile = try os.File.openWrite(allocator, build_file_abs); |
| 669 | | defer dstfile.close(); |
| 577 | if (flags.many("library-path")) |lib_dirs| { |
| 578 | module.lib_dirs = lib_dirs; |
| 579 | } |
| 670 | 580 | |
| 671 | | while (true) { |
| 672 | | var buffer: [4096]u8 = undefined; |
| 673 | | const n = try srcfile.read(buffer[0..]); |
| 674 | | if (n == 0) break; |
| 675 | | try dstfile.write(buffer[0..n]); |
| 676 | | } |
| 581 | if (flags.many("framework")) |frameworks| { |
| 582 | module.darwin_frameworks = frameworks; |
| 583 | } |
| 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) { |
| 682 | | warn( |
| 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 | | ); |
| 589 | if (flags.single("output-h")) |output_h| { |
| 590 | module.out_h_path = output_h; |
| 591 | } |
| 592 | |
| 593 | module.windows_subsystem_windows = flags.present("mwindows"); |
| 594 | module.windows_subsystem_console = flags.present("mconsole"); |
| 595 | module.linker_rdynamic = flags.present("rdynamic"); |
| 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 | 599 | os.exit(1); |
| 690 | 600 | } |
| 691 | 601 | |
| 692 | | // codegen_build(g) |
| 693 | | // codegen_link(g, path_to_build_exe) |
| 694 | | // codegen_destroy(g) |
| 602 | if (flags.single("mmacosx-version-min")) |ver| { |
| 603 | module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver }; |
| 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 | 654 | defer proc.deinit(); |
| 698 | 655 | |
| 699 | 656 | var term = try proc.spawnAndWait(); |
| 700 | 657 | switch (term) { |
| 701 | 658 | os.ChildProcess.Term.Exited => |status| { |
| 702 | 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 | 661 | os.exit(1); |
| 705 | 662 | } |
| 706 | 663 | }, |
| 707 | 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 | 666 | os.exit(1); |
| 710 | 667 | }, |
| 711 | 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 | 670 | os.exit(1); |
| 714 | 671 | }, |
| 715 | 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 | 674 | os.exit(1); |
| 718 | 675 | }, |
| 719 | 676 | } |
| 720 | 677 | } |
| 721 | 678 | |
| 722 | | fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { |
| 723 | | for (file_paths) |file_path| { |
| 679 | // cmd:fmt ///////////////////////////////////////////////////////////////////////////////////////// |
| 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 | 713 | var file = try os.File.openRead(allocator, file_path); |
| 725 | 714 | defer file.close(); |
| 726 | 715 | |
| 727 | 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 | 718 | continue; |
| 730 | 719 | }; |
| 731 | 720 | defer allocator.free(source_code); |
| ... | ... | @@ -734,72 +723,423 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { |
| 734 | 723 | var parser = std.zig.Parser.init(&tokenizer, allocator, file_path); |
| 735 | 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 | 730 | defer tree.deinit(); |
| 739 | 731 | |
| 740 | | const baf = try io.BufferedAtomicFile.create(allocator, file_path); |
| 741 | | defer baf.destroy(); |
| 732 | var original_file_backup = try Buffer.init(allocator, file_path); |
| 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); |
| 744 | | try baf.finish(); |
| 740 | // TODO: BufferedAtomicFile has some access problems. |
| 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 |
| 749 | | fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 { |
| 750 | | if (zig_install_prefix_arg) |zig_install_prefix| { |
| 751 | | return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| { |
| 752 | | warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); |
| 753 | | return error.ZigInstallationNotFound; |
| 754 | | }; |
| 755 | | } else { |
| 756 | | return findZigLibDir(allocator) catch |err| { |
| 757 | | warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n", |
| 758 | | @errorName(err)); |
| 759 | | return error.ZigLibDirNotFound; |
| 760 | | }; |
| 753 | // cmd:targets ///////////////////////////////////////////////////////////////////////////////////// |
| 754 | |
| 755 | // TODO: comptime '@fields' for iteration here instead so we are always in sync. |
| 756 | const Os = builtin.Os; |
| 757 | pub const os_list = []const Os { |
| 758 | Os.freestanding, |
| 759 | Os.ananas, |
| 760 | Os.cloudabi, |
| 761 | Os.dragonfly, |
| 762 | Os.freebsd, |
| 763 | Os.fuchsia, |
| 764 | Os.ios, |
| 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 |
| 765 | | fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 { |
| 766 | | const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig"); |
| 767 | | errdefer allocator.free(test_zig_dir); |
| 914 | // cmd:test //////////////////////////////////////////////////////////////////////////////////////// |
| 915 | |
| 916 | const usage_test = |
| 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); |
| 773 | | file.close(); |
| 930 | fn cmdTest(allocator: &Allocator, args: []const []const u8) !void { |
| 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 |
| 779 | | fn findZigLibDir(allocator: &mem.Allocator) ![]u8 { |
| 780 | | const self_exe_path = try os.selfExeDirPath(allocator); |
| 781 | | defer allocator.free(self_exe_path); |
| 950 | // cmd:run ///////////////////////////////////////////////////////////////////////////////////////// |
| 951 | |
| 952 | // Run should be simple and not expose the full set of arguments provided by build-exe. If specific |
| 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 | 976 | break; |
| 789 | 977 | } |
| 978 | } |
| 790 | 979 | |
| 791 | | return testZigInstallPrefix(allocator, test_dir) catch |err| { |
| 792 | | cur_path = test_dir; |
| 793 | | continue; |
| 794 | | }; |
| 980 | var flags = try Args.parse(allocator, args_run_spec, compile_args); |
| 981 | defer flags.deinit(); |
| 982 | |
| 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 |
| 798 | | //if (ZIG_INSTALL_PREFIX != nullptr) { |
| 799 | | // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { |
| 800 | | // return 0; |
| 801 | | // } |
| 802 | | //} |
| 988 | if (flags.positionals.len != 1) { |
| 989 | try stderr.write("expected exactly one zig source file\n"); |
| 990 | os.exit(1); |
| 991 | } |
| 992 | |
| 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 | } |