| ... | @@ -26,15 +26,11 @@ const usage = | ... | @@ -26,15 +26,11 @@ const usage = |
| 26 | \\ | 26 | \\ |
| 27 | \\Commands: | 27 | \\Commands: |
| 28 | \\ | 28 | \\ |
| 29 | \\ build Build project from build.zig | | |
| 30 | \\ build-exe [source] Create executable from source or object files | 29 | \\ build-exe [source] Create executable from source or object files |
| 31 | \\ build-lib [source] Create library from source or object files | 30 | \\ build-lib [source] Create library from source or object files |
| 32 | \\ build-obj [source] Create object from source or assembly | 31 | \\ build-obj [source] Create object from source or assembly |
| 33 | \\ fmt [source] Parse file and render in canonical zig format | 32 | \\ fmt [source] Parse file and render in canonical zig format |
| 34 | \\ run [source] Create executable and run immediately | | |
| 35 | \\ targets List available compilation targets | 33 | \\ targets List available compilation targets |
| 36 | \\ test [source] Create and run a test build | | |
| 37 | \\ translate-c [source] Convert c code to zig code | | |
| 38 | \\ version Print version number and exit | 34 | \\ version Print version number and exit |
| 39 | \\ zen Print zen of zig and exit | 35 | \\ zen Print zen of zig and exit |
| 40 | \\ | 36 | \\ |
| ... | @@ -47,7 +43,7 @@ const Command = struct { | ... | @@ -47,7 +43,7 @@ const Command = struct { |
| 47 | }; | 43 | }; |
| 48 | | 44 | |
| 49 | pub fn main() !void { | 45 | pub fn main() !void { |
| 50 | var allocator = std.heap.c_allocator; | 46 | const allocator = std.heap.c_allocator; |
| 51 | | 47 | |
| 52 | var stdout_file = try std.io.getStdOut(); | 48 | var stdout_file = try std.io.getStdOut(); |
| 53 | var stdout_out_stream = std.io.FileOutStream.init(&stdout_file); | 49 | var stdout_out_stream = std.io.FileOutStream.init(&stdout_file); |
| ... | @@ -58,18 +54,16 @@ pub fn main() !void { | ... | @@ -58,18 +54,16 @@ pub fn main() !void { |
| 58 | stderr = &stderr_out_stream.stream; | 54 | stderr = &stderr_out_stream.stream; |
| 59 | | 55 | |
| 60 | const args = try os.argsAlloc(allocator); | 56 | const args = try os.argsAlloc(allocator); |
| 61 | defer os.argsFree(allocator, args); | 57 | // TODO I'm getting unreachable code here, which shouldn't happen |
| | 58 | //defer os.argsFree(allocator, args); |
| 62 | | 59 | |
| 63 | if (args.len <= 1) { | 60 | if (args.len <= 1) { |
| | 61 | try stderr.write("expected command argument\n\n"); |
| 64 | try stderr.write(usage); | 62 | try stderr.write(usage); |
| 65 | os.exit(1); | 63 | os.exit(1); |
| 66 | } | 64 | } |
| 67 | | 65 | |
| 68 | const commands = []Command{ | 66 | const commands = []Command{ |
| 69 | Command{ | | |
| 70 | .name = "build", | | |
| 71 | .exec = cmdBuild, | | |
| 72 | }, | | |
| 73 | Command{ | 67 | Command{ |
| 74 | .name = "build-exe", | 68 | .name = "build-exe", |
| 75 | .exec = cmdBuildExe, | 69 | .exec = cmdBuildExe, |
| ... | @@ -86,22 +80,10 @@ pub fn main() !void { | ... | @@ -86,22 +80,10 @@ pub fn main() !void { |
| 86 | .name = "fmt", | 80 | .name = "fmt", |
| 87 | .exec = cmdFmt, | 81 | .exec = cmdFmt, |
| 88 | }, | 82 | }, |
| 89 | Command{ | | |
| 90 | .name = "run", | | |
| 91 | .exec = cmdRun, | | |
| 92 | }, | | |
| 93 | Command{ | 83 | Command{ |
| 94 | .name = "targets", | 84 | .name = "targets", |
| 95 | .exec = cmdTargets, | 85 | .exec = cmdTargets, |
| 96 | }, | 86 | }, |
| 97 | Command{ | | |
| 98 | .name = "test", | | |
| 99 | .exec = cmdTest, | | |
| 100 | }, | | |
| 101 | Command{ | | |
| 102 | .name = "translate-c", | | |
| 103 | .exec = cmdTranslateC, | | |
| 104 | }, | | |
| 105 | Command{ | 87 | Command{ |
| 106 | .name = "version", | 88 | .name = "version", |
| 107 | .exec = cmdVersion, | 89 | .exec = cmdVersion, |
| ... | @@ -124,177 +106,15 @@ pub fn main() !void { | ... | @@ -124,177 +106,15 @@ pub fn main() !void { |
| 124 | | 106 | |
| 125 | for (commands) |command| { | 107 | for (commands) |command| { |
| 126 | if (mem.eql(u8, command.name, args[1])) { | 108 | if (mem.eql(u8, command.name, args[1])) { |
| 127 | try command.exec(allocator, args[2..]); | 109 | return command.exec(allocator, args[2..]); |
| 128 | return; | | |
| 129 | } | 110 | } |
| 130 | } | 111 | } |
| 131 | | 112 | |
| 132 | try stderr.print("unknown command: {}\n\n", args[1]); | 113 | try stderr.print("unknown command: {}\n\n", args[1]); |
| 133 | try stderr.write(usage); | 114 | try stderr.write(usage); |
| | 115 | os.exit(1); |
| 134 | } | 116 | } |
| 135 | | 117 | |
| 136 | // cmd:build /////////////////////////////////////////////////////////////////////////////////////// | | |
| 137 | | | |
| 138 | const usage_build = | | |
| 139 | \\usage: zig build <options> | | |
| 140 | \\ | | |
| 141 | \\General Options: | | |
| 142 | \\ --help Print this help and exit | | |
| 143 | \\ --init Generate a build.zig template | | |
| 144 | \\ --build-file [file] Override path to build.zig | | |
| 145 | \\ --cache-dir [path] Override path to cache directory | | |
| 146 | \\ --verbose Print commands before executing them | | |
| 147 | \\ --prefix [path] Override default install prefix | | |
| 148 | \\ | | |
| 149 | \\Project-Specific Options: | | |
| 150 | \\ | | |
| 151 | \\ Project-specific options become available when the build file is found. | | |
| 152 | \\ | | |
| 153 | \\Advanced Options: | | |
| 154 | \\ --build-file [file] Override path to build.zig | | |
| 155 | \\ --cache-dir [path] Override path to cache directory | | |
| 156 | \\ --verbose-tokenize Enable compiler debug output for tokenization | | |
| 157 | \\ --verbose-ast Enable compiler debug output for parsing into an AST | | |
| 158 | \\ --verbose-link Enable compiler debug output for linking | | |
| 159 | \\ --verbose-ir Enable compiler debug output for Zig IR | | |
| 160 | \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR | | |
| 161 | \\ --verbose-cimport Enable compiler debug output for C imports | | |
| 162 | \\ | | |
| 163 | \\ | | |
| 164 | ; | | |
| 165 | | | |
| 166 | const args_build_spec = []Flag{ | | |
| 167 | Flag.Bool("--help"), | | |
| 168 | Flag.Bool("--init"), | | |
| 169 | Flag.Arg1("--build-file"), | | |
| 170 | Flag.Arg1("--cache-dir"), | | |
| 171 | Flag.Bool("--verbose"), | | |
| 172 | Flag.Arg1("--prefix"), | | |
| 173 | | | |
| 174 | Flag.Arg1("--build-file"), | | |
| 175 | Flag.Arg1("--cache-dir"), | | |
| 176 | Flag.Bool("--verbose-tokenize"), | | |
| 177 | Flag.Bool("--verbose-ast"), | | |
| 178 | Flag.Bool("--verbose-link"), | | |
| 179 | Flag.Bool("--verbose-ir"), | | |
| 180 | Flag.Bool("--verbose-llvm-ir"), | | |
| 181 | Flag.Bool("--verbose-cimport"), | | |
| 182 | }; | | |
| 183 | | | |
| 184 | const missing_build_file = | | |
| 185 | \\No 'build.zig' file found. | | |
| 186 | \\ | | |
| 187 | \\Initialize a 'build.zig' template file with `zig build --init`, | | |
| 188 | \\or build an executable directly with `zig build-exe $FILENAME.zig`. | | |
| 189 | \\ | | |
| 190 | \\See: `zig build --help` or `zig help` for more options. | | |
| 191 | \\ | | |
| 192 | ; | | |
| 193 | | | |
| 194 | fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void { | | |
| 195 | var flags = try Args.parse(allocator, args_build_spec, args); | | |
| 196 | defer flags.deinit(); | | |
| 197 | | | |
| 198 | if (flags.present("help")) { | | |
| 199 | try stderr.write(usage_build); | | |
| 200 | os.exit(0); | | |
| 201 | } | | |
| 202 | | | |
| 203 | const zig_lib_dir = try introspect.resolveZigLibDir(allocator); | | |
| 204 | defer allocator.free(zig_lib_dir); | | |
| 205 | | | |
| 206 | const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std"); | | |
| 207 | defer allocator.free(zig_std_dir); | | |
| 208 | | | |
| 209 | const special_dir = try os.path.join(allocator, zig_std_dir, "special"); | | |
| 210 | defer allocator.free(special_dir); | | |
| 211 | | | |
| 212 | const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig"); | | |
| 213 | defer allocator.free(build_runner_path); | | |
| 214 | | | |
| 215 | const build_file = flags.single("build-file") orelse "build.zig"; | | |
| 216 | const build_file_abs = try os.path.resolve(allocator, ".", build_file); | | |
| 217 | defer allocator.free(build_file_abs); | | |
| 218 | | | |
| 219 | const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false; | | |
| 220 | | | |
| 221 | if (flags.present("init")) { | | |
| 222 | if (build_file_exists) { | | |
| 223 | try stderr.print("build.zig already exists\n"); | | |
| 224 | os.exit(1); | | |
| 225 | } | | |
| 226 | | | |
| 227 | // need a new scope for proper defer scope finalization on exit | | |
| 228 | { | | |
| 229 | const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig"); | | |
| 230 | defer allocator.free(build_template_path); | | |
| 231 | | | |
| 232 | try os.copyFile(allocator, build_template_path, build_file_abs); | | |
| 233 | try stderr.print("wrote build.zig template\n"); | | |
| 234 | } | | |
| 235 | | | |
| 236 | os.exit(0); | | |
| 237 | } | | |
| 238 | | | |
| 239 | if (!build_file_exists) { | | |
| 240 | try stderr.write(missing_build_file); | | |
| 241 | os.exit(1); | | |
| 242 | } | | |
| 243 | | | |
| 244 | // TODO: Invoke build.zig entrypoint directly? | | |
| 245 | var zig_exe_path = try os.selfExePath(allocator); | | |
| 246 | defer allocator.free(zig_exe_path); | | |
| 247 | | | |
| 248 | var build_args = ArrayList([]const u8).init(allocator); | | |
| 249 | defer build_args.deinit(); | | |
| 250 | | | |
| 251 | const build_file_basename = os.path.basename(build_file_abs); | | |
| 252 | const build_file_dirname = os.path.dirname(build_file_abs) orelse "."; | | |
| 253 | | | |
| 254 | var full_cache_dir: []u8 = undefined; | | |
| 255 | if (flags.single("cache-dir")) |cache_dir| { | | |
| 256 | full_cache_dir = try os.path.resolve(allocator, ".", cache_dir, full_cache_dir); | | |
| 257 | } else { | | |
| 258 | full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache"); | | |
| 259 | } | | |
| 260 | defer allocator.free(full_cache_dir); | | |
| 261 | | | |
| 262 | const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build"); | | |
| 263 | defer allocator.free(path_to_build_exe); | | |
| 264 | | | |
| 265 | try build_args.append(path_to_build_exe); | | |
| 266 | try build_args.append(zig_exe_path); | | |
| 267 | try build_args.append(build_file_dirname); | | |
| 268 | try build_args.append(full_cache_dir); | | |
| 269 | | | |
| 270 | var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator); | | |
| 271 | defer proc.deinit(); | | |
| 272 | | | |
| 273 | var term = try proc.spawnAndWait(); | | |
| 274 | switch (term) { | | |
| 275 | os.ChildProcess.Term.Exited => |status| { | | |
| 276 | if (status != 0) { | | |
| 277 | try stderr.print("{} exited with status {}\n", build_args.at(0), status); | | |
| 278 | os.exit(1); | | |
| 279 | } | | |
| 280 | }, | | |
| 281 | os.ChildProcess.Term.Signal => |signal| { | | |
| 282 | try stderr.print("{} killed by signal {}\n", build_args.at(0), signal); | | |
| 283 | os.exit(1); | | |
| 284 | }, | | |
| 285 | os.ChildProcess.Term.Stopped => |signal| { | | |
| 286 | try stderr.print("{} stopped by signal {}\n", build_args.at(0), signal); | | |
| 287 | os.exit(1); | | |
| 288 | }, | | |
| 289 | os.ChildProcess.Term.Unknown => |status| { | | |
| 290 | try stderr.print("{} encountered unknown failure {}\n", build_args.at(0), status); | | |
| 291 | os.exit(1); | | |
| 292 | }, | | |
| 293 | } | | |
| 294 | } | | |
| 295 | | | |
| 296 | // cmd:build-exe /////////////////////////////////////////////////////////////////////////////////// | | |
| 297 | | | |
| 298 | const usage_build_generic = | 118 | const usage_build_generic = |
| 299 | \\usage: zig build-exe <options> [file] | 119 | \\usage: zig build-exe <options> [file] |
| 300 | \\ zig build-lib <options> [file] | 120 | \\ zig build-lib <options> [file] |
| ... | @@ -315,8 +135,11 @@ const usage_build_generic = | ... | @@ -315,8 +135,11 @@ const usage_build_generic = |
| 315 | \\ --output-h [file] Override generated header file path | 135 | \\ --output-h [file] Override generated header file path |
| 316 | \\ --pkg-begin [name] [path] Make package available to import and push current pkg | 136 | \\ --pkg-begin [name] [path] Make package available to import and push current pkg |
| 317 | \\ --pkg-end Pop current pkg | 137 | \\ --pkg-end Pop current pkg |
| 318 | \\ --release-fast Build with optimizations on and safety off | 138 | \\ --mode [mode] Set the build mode |
| 319 | \\ --release-safe Build with optimizations on and safety on | 139 | \\ debug (default) optimizations off, safety on |
| | 140 | \\ release-fast optimizations on, safety off |
| | 141 | \\ release-safe optimizations on, safety on |
| | 142 | \\ release-small optimize for small binary, safety off |
| 320 | \\ --static Output will be statically linked | 143 | \\ --static Output will be statically linked |
| 321 | \\ --strip Exclude debug symbols | 144 | \\ --strip Exclude debug symbols |
| 322 | \\ --target-arch [name] Specify target architecture | 145 | \\ --target-arch [name] Specify target architecture |
| ... | @@ -367,6 +190,12 @@ const args_build_generic = []Flag{ | ... | @@ -367,6 +190,12 @@ const args_build_generic = []Flag{ |
| 367 | "off", | 190 | "off", |
| 368 | "on", | 191 | "on", |
| 369 | }), | 192 | }), |
| | 193 | Flag.Option("--mode", []const []const u8{ |
| | 194 | "debug", |
| | 195 | "release-fast", |
| | 196 | "release-safe", |
| | 197 | "release-small", |
| | 198 | }), |
| 370 | | 199 | |
| 371 | Flag.ArgMergeN("--assembly", 1), | 200 | Flag.ArgMergeN("--assembly", 1), |
| 372 | Flag.Arg1("--cache-dir"), | 201 | Flag.Arg1("--cache-dir"), |
| ... | @@ -383,8 +212,6 @@ const args_build_generic = []Flag{ | ... | @@ -383,8 +212,6 @@ const args_build_generic = []Flag{ |
| 383 | // NOTE: Parsed manually after initial check | 212 | // NOTE: Parsed manually after initial check |
| 384 | Flag.ArgN("--pkg-begin", 2), | 213 | Flag.ArgN("--pkg-begin", 2), |
| 385 | Flag.Bool("--pkg-end"), | 214 | Flag.Bool("--pkg-end"), |
| 386 | Flag.Bool("--release-fast"), | | |
| 387 | Flag.Bool("--release-safe"), | | |
| 388 | Flag.Bool("--static"), | 215 | Flag.Bool("--static"), |
| 389 | Flag.Bool("--strip"), | 216 | Flag.Bool("--strip"), |
| 390 | Flag.Arg1("--target-arch"), | 217 | Flag.Arg1("--target-arch"), |
| ... | @@ -431,16 +258,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -431,16 +258,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 431 | defer flags.deinit(); | 258 | defer flags.deinit(); |
| 432 | | 259 | |
| 433 | if (flags.present("help")) { | 260 | if (flags.present("help")) { |
| 434 | try stderr.write(usage_build_generic); | 261 | try stdout.write(usage_build_generic); |
| 435 | os.exit(0); | 262 | os.exit(0); |
| 436 | } | 263 | } |
| 437 | | 264 | |
| 438 | var build_mode = builtin.Mode.Debug; | 265 | const build_mode = blk: { |
| 439 | if (flags.present("release-fast")) { | 266 | if (flags.single("mode")) |mode_flag| { |
| 440 | build_mode = builtin.Mode.ReleaseFast; | 267 | if (mem.eql(u8, mode_flag, "debug")) { |
| 441 | } else if (flags.present("release-safe")) { | 268 | break :blk builtin.Mode.Debug; |
| 442 | build_mode = builtin.Mode.ReleaseSafe; | 269 | } else if (mem.eql(u8, mode_flag, "release-fast")) { |
| 443 | } | 270 | break :blk builtin.Mode.ReleaseFast; |
| | 271 | } else if (mem.eql(u8, mode_flag, "release-safe")) { |
| | 272 | break :blk builtin.Mode.ReleaseSafe; |
| | 273 | } else if (mem.eql(u8, mode_flag, "release-small")) { |
| | 274 | break :blk builtin.Mode.ReleaseSmall; |
| | 275 | } else unreachable; |
| | 276 | } else { |
| | 277 | break :blk builtin.Mode.Debug; |
| | 278 | } |
| | 279 | }; |
| 444 | | 280 | |
| 445 | const color = blk: { | 281 | const color = blk: { |
| 446 | if (flags.single("color")) |color_flag| { | 282 | if (flags.single("color")) |color_flag| { |
| ... | @@ -456,20 +292,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -456,20 +292,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 456 | } | 292 | } |
| 457 | }; | 293 | }; |
| 458 | | 294 | |
| 459 | var emit_type = Module.Emit.Binary; | 295 | const emit_type = blk: { |
| 460 | if (flags.single("emit")) |emit_flag| { | 296 | if (flags.single("emit")) |emit_flag| { |
| 461 | if (mem.eql(u8, emit_flag, "asm")) { | 297 | if (mem.eql(u8, emit_flag, "asm")) { |
| 462 | emit_type = Module.Emit.Assembly; | 298 | break :blk Module.Emit.Assembly; |
| 463 | } else if (mem.eql(u8, emit_flag, "bin")) { | 299 | } else if (mem.eql(u8, emit_flag, "bin")) { |
| 464 | emit_type = Module.Emit.Binary; | 300 | break :blk Module.Emit.Binary; |
| 465 | } else if (mem.eql(u8, emit_flag, "llvm-ir")) { | 301 | } else if (mem.eql(u8, emit_flag, "llvm-ir")) { |
| 466 | emit_type = Module.Emit.LlvmIr; | 302 | break :blk Module.Emit.LlvmIr; |
| | 303 | } else unreachable; |
| 467 | } else { | 304 | } else { |
| 468 | unreachable; | 305 | break :blk Module.Emit.Binary; |
| 469 | } | 306 | } |
| 470 | } | 307 | }; |
| 471 | | 308 | |
| 472 | var cur_pkg = try Module.CliPkg.init(allocator, "", "", null); // TODO: Need a path, name? | 309 | var cur_pkg = try CliPkg.init(allocator, "", "", null); |
| 473 | defer cur_pkg.deinit(); | 310 | defer cur_pkg.deinit(); |
| 474 | | 311 | |
| 475 | var i: usize = 0; | 312 | var i: usize = 0; |
| ... | @@ -482,15 +319,16 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -482,15 +319,16 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 482 | i += 1; | 319 | i += 1; |
| 483 | const new_pkg_path = args[i]; | 320 | const new_pkg_path = args[i]; |
| 484 | | 321 | |
| 485 | var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg); | 322 | var new_cur_pkg = try CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg); |
| 486 | try cur_pkg.children.append(new_cur_pkg); | 323 | try cur_pkg.children.append(new_cur_pkg); |
| 487 | cur_pkg = new_cur_pkg; | 324 | cur_pkg = new_cur_pkg; |
| 488 | } else if (mem.eql(u8, "--pkg-end", arg_name)) { | 325 | } else if (mem.eql(u8, "--pkg-end", arg_name)) { |
| 489 | if (cur_pkg.parent == null) { | 326 | if (cur_pkg.parent) |parent| { |
| | 327 | cur_pkg = parent; |
| | 328 | } else { |
| 490 | try stderr.print("encountered --pkg-end with no matching --pkg-begin\n"); | 329 | try stderr.print("encountered --pkg-end with no matching --pkg-begin\n"); |
| 491 | os.exit(1); | 330 | os.exit(1); |
| 492 | } | 331 | } |
| 493 | cur_pkg = cur_pkg.parent.?; | | |
| 494 | } | 332 | } |
| 495 | } | 333 | } |
| 496 | | 334 | |
| ... | @@ -499,43 +337,42 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -499,43 +337,42 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 499 | os.exit(1); | 337 | os.exit(1); |
| 500 | } | 338 | } |
| 501 | | 339 | |
| 502 | var in_file: ?[]const u8 = undefined; | 340 | const provided_name = flags.single("name"); |
| 503 | switch (flags.positionals.len) { | 341 | const root_source_file = switch (flags.positionals.len) { |
| 504 | 0 => { | 342 | 0 => null, |
| 505 | try stderr.write("--name [name] not provided and unable to infer\n"); | 343 | 1 => flags.positionals.at(0), |
| 506 | os.exit(1); | | |
| 507 | }, | | |
| 508 | 1 => { | | |
| 509 | in_file = flags.positionals.at(0); | | |
| 510 | }, | | |
| 511 | else => { | 344 | else => { |
| 512 | try stderr.write("only one zig input file is accepted during build\n"); | 345 | try stderr.print("unexpected extra parameter: {}\n", flags.positionals.at(1)); |
| 513 | os.exit(1); | 346 | os.exit(1); |
| 514 | }, | 347 | }, |
| 515 | } | 348 | }; |
| 516 | | 349 | |
| 517 | const basename = os.path.basename(in_file.?); | 350 | const root_name = if (provided_name) |n| n else blk: { |
| 518 | var it = mem.split(basename, "."); | 351 | if (root_source_file) |file| { |
| 519 | const root_name = it.next() orelse { | 352 | const basename = os.path.basename(file); |
| 520 | try stderr.write("file name cannot be empty\n"); | 353 | var it = mem.split(basename, "."); |
| 521 | os.exit(1); | 354 | break :blk it.next() orelse basename; |
| | 355 | } else { |
| | 356 | try stderr.write("--name [name] not provided and unable to infer\n"); |
| | 357 | os.exit(1); |
| | 358 | } |
| 522 | }; | 359 | }; |
| 523 | | 360 | |
| 524 | const asm_a = flags.many("assembly"); | 361 | const assembly_files = flags.many("assembly"); |
| 525 | const obj_a = flags.many("object"); | 362 | const link_objects = flags.many("object"); |
| 526 | if (in_file == null and (obj_a == null or obj_a.?.len == 0) and (asm_a == null or asm_a.?.len == 0)) { | 363 | if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) { |
| 527 | try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); | 364 | try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); |
| 528 | os.exit(1); | 365 | os.exit(1); |
| 529 | } | 366 | } |
| 530 | | 367 | |
| 531 | if (out_type == Module.Kind.Obj and (obj_a != null and obj_a.?.len != 0)) { | 368 | if (out_type == Module.Kind.Obj and link_objects.len != 0) { |
| 532 | try stderr.write("When building an object file, --object arguments are invalid\n"); | 369 | try stderr.write("When building an object file, --object arguments are invalid\n"); |
| 533 | os.exit(1); | 370 | os.exit(1); |
| 534 | } | 371 | } |
| 535 | | 372 | |
| 536 | const zig_root_source_file = in_file; | 373 | const rel_cache_dir = flags.single("cache-dir") orelse "zig-cache"[0..]; |
| 537 | | 374 | const full_cache_dir = os.path.resolve(allocator, ".", rel_cache_dir) catch { |
| 538 | const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") orelse "zig-cache"[0..]) catch { | 375 | try stderr.print("invalid cache dir: {}\n", rel_cache_dir); |
| 539 | os.exit(1); | 376 | os.exit(1); |
| 540 | }; | 377 | }; |
| 541 | defer allocator.free(full_cache_dir); | 378 | defer allocator.free(full_cache_dir); |
| ... | @@ -546,7 +383,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -546,7 +383,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 546 | var module = try Module.create( | 383 | var module = try Module.create( |
| 547 | allocator, | 384 | allocator, |
| 548 | root_name, | 385 | root_name, |
| 549 | zig_root_source_file, | 386 | root_source_file, |
| 550 | Target.Native, | 387 | Target.Native, |
| 551 | out_type, | 388 | out_type, |
| 552 | build_mode, | 389 | build_mode, |
| ... | @@ -561,24 +398,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -561,24 +398,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 561 | | 398 | |
| 562 | module.is_test = false; | 399 | module.is_test = false; |
| 563 | | 400 | |
| 564 | if (flags.single("linker-script")) |linker_script| { | 401 | module.linker_script = flags.single("linker-script"); |
| 565 | module.linker_script = linker_script; | | |
| 566 | } | | |
| 567 | | | |
| 568 | module.each_lib_rpath = flags.present("each-lib-rpath"); | 402 | module.each_lib_rpath = flags.present("each-lib-rpath"); |
| 569 | | 403 | |
| 570 | var clang_argv_buf = ArrayList([]const u8).init(allocator); | 404 | var clang_argv_buf = ArrayList([]const u8).init(allocator); |
| 571 | defer clang_argv_buf.deinit(); | 405 | defer clang_argv_buf.deinit(); |
| 572 | if (flags.many("mllvm")) |mllvm_flags| { | | |
| 573 | for (mllvm_flags) |mllvm| { | | |
| 574 | try clang_argv_buf.append("-mllvm"); | | |
| 575 | try clang_argv_buf.append(mllvm); | | |
| 576 | } | | |
| 577 | | 406 | |
| 578 | module.llvm_argv = mllvm_flags; | 407 | const mllvm_flags = flags.many("mllvm"); |
| 579 | module.clang_argv = clang_argv_buf.toSliceConst(); | 408 | for (mllvm_flags) |mllvm| { |
| | 409 | try clang_argv_buf.append("-mllvm"); |
| | 410 | try clang_argv_buf.append(mllvm); |
| 580 | } | 411 | } |
| 581 | | 412 | |
| | 413 | module.llvm_argv = mllvm_flags; |
| | 414 | module.clang_argv = clang_argv_buf.toSliceConst(); |
| | 415 | |
| 582 | module.strip = flags.present("strip"); | 416 | module.strip = flags.present("strip"); |
| 583 | module.is_static = flags.present("static"); | 417 | module.is_static = flags.present("static"); |
| 584 | | 418 | |
| ... | @@ -610,18 +444,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -610,18 +444,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 610 | module.verbose_cimport = flags.present("verbose-cimport"); | 444 | module.verbose_cimport = flags.present("verbose-cimport"); |
| 611 | | 445 | |
| 612 | module.err_color = color; | 446 | module.err_color = color; |
| 613 | | 447 | module.lib_dirs = flags.many("library-path"); |
| 614 | if (flags.many("library-path")) |lib_dirs| { | 448 | module.darwin_frameworks = flags.many("framework"); |
| 615 | module.lib_dirs = lib_dirs; | 449 | module.rpath_list = flags.many("rpath"); |
| 616 | } | | |
| 617 | | | |
| 618 | if (flags.many("framework")) |frameworks| { | | |
| 619 | module.darwin_frameworks = frameworks; | | |
| 620 | } | | |
| 621 | | | |
| 622 | if (flags.many("rpath")) |rpath_list| { | | |
| 623 | module.rpath_list = rpath_list; | | |
| 624 | } | | |
| 625 | | 450 | |
| 626 | if (flags.single("output-h")) |output_h| { | 451 | if (flags.single("output-h")) |output_h| { |
| 627 | module.out_h_path = output_h; | 452 | module.out_h_path = output_h; |
| ... | @@ -644,41 +469,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo | ... | @@ -644,41 +469,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 644 | } | 469 | } |
| 645 | | 470 | |
| 646 | module.emit_file_type = emit_type; | 471 | module.emit_file_type = emit_type; |
| 647 | if (flags.many("object")) |objects| { | 472 | module.link_objects = link_objects; |
| 648 | module.link_objects = objects; | 473 | module.assembly_files = assembly_files; |
| 649 | } | | |
| 650 | if (flags.many("assembly")) |assembly_files| { | | |
| 651 | module.assembly_files = assembly_files; | | |
| 652 | } | | |
| 653 | | 474 | |
| 654 | try module.build(); | 475 | try module.build(); |
| 655 | try module.link(flags.single("out-file") orelse null); | 476 | try module.link(flags.single("out-file")); |
| 656 | | | |
| 657 | if (flags.present("print-timing-info")) { | | |
| 658 | // codegen_print_timing_info(g, stderr); | | |
| 659 | } | | |
| 660 | | | |
| 661 | try stderr.print("building {}: {}\n", @tagName(out_type), in_file); | | |
| 662 | } | 477 | } |
| 663 | | 478 | |
| 664 | fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void { | 479 | fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void { |
| 665 | try buildOutputType(allocator, args, Module.Kind.Exe); | 480 | return buildOutputType(allocator, args, Module.Kind.Exe); |
| 666 | } | 481 | } |
| 667 | | 482 | |
| 668 | // cmd:build-lib /////////////////////////////////////////////////////////////////////////////////// | | |
| 669 | | | |
| 670 | fn cmdBuildLib(allocator: *Allocator, args: []const []const u8) !void { | 483 | fn cmdBuildLib(allocator: *Allocator, args: []const []const u8) !void { |
| 671 | try buildOutputType(allocator, args, Module.Kind.Lib); | 484 | return buildOutputType(allocator, args, Module.Kind.Lib); |
| 672 | } | 485 | } |
| 673 | | 486 | |
| 674 | // cmd:build-obj /////////////////////////////////////////////////////////////////////////////////// | | |
| 675 | | | |
| 676 | fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void { | 487 | fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void { |
| 677 | try buildOutputType(allocator, args, Module.Kind.Obj); | 488 | return buildOutputType(allocator, args, Module.Kind.Obj); |
| 678 | } | 489 | } |
| 679 | | 490 | |
| 680 | // cmd:fmt ///////////////////////////////////////////////////////////////////////////////////////// | | |
| 681 | | | |
| 682 | const usage_fmt = | 491 | const usage_fmt = |
| 683 | \\usage: zig fmt [file]... | 492 | \\usage: zig fmt [file]... |
| 684 | \\ | 493 | \\ |
| ... | @@ -735,7 +544,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -735,7 +544,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 735 | defer flags.deinit(); | 544 | defer flags.deinit(); |
| 736 | | 545 | |
| 737 | if (flags.present("help")) { | 546 | if (flags.present("help")) { |
| 738 | try stderr.write(usage_fmt); | 547 | try stdout.write(usage_fmt); |
| 739 | os.exit(0); | 548 | os.exit(0); |
| 740 | } | 549 | } |
| 741 | | 550 | |
| ... | @@ -863,162 +672,16 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -863,162 +672,16 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void { |
| 863 | } | 672 | } |
| 864 | } | 673 | } |
| 865 | | 674 | |
| 866 | // cmd:version ///////////////////////////////////////////////////////////////////////////////////// | | |
| 867 | | | |
| 868 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { | 675 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { |
| 869 | try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING)); | 676 | try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING)); |
| 870 | } | 677 | } |
| 871 | | 678 | |
| 872 | // cmd:test //////////////////////////////////////////////////////////////////////////////////////// | | |
| 873 | | | |
| 874 | const usage_test = | | |
| 875 | \\usage: zig test [file]... | | |
| 876 | \\ | | |
| 877 | \\Options: | | |
| 878 | \\ --help Print this help and exit | | |
| 879 | \\ | | |
| 880 | \\ | | |
| 881 | ; | | |
| 882 | | | |
| 883 | const args_test_spec = []Flag{Flag.Bool("--help")}; | 679 | const args_test_spec = []Flag{Flag.Bool("--help")}; |
| 884 | | 680 | |
| 885 | fn cmdTest(allocator: *Allocator, args: []const []const u8) !void { | | |
| 886 | var flags = try Args.parse(allocator, args_build_spec, args); | | |
| 887 | defer flags.deinit(); | | |
| 888 | | | |
| 889 | if (flags.present("help")) { | | |
| 890 | try stderr.write(usage_test); | | |
| 891 | os.exit(0); | | |
| 892 | } | | |
| 893 | | | |
| 894 | if (flags.positionals.len != 1) { | | |
| 895 | try stderr.write("expected exactly one zig source file\n"); | | |
| 896 | os.exit(1); | | |
| 897 | } | | |
| 898 | | | |
| 899 | // compile the test program into the cache and run | | |
| 900 | | | |
| 901 | // NOTE: May be overlap with buildOutput, take the shared part out. | | |
| 902 | try stderr.print("testing file {}\n", flags.positionals.at(0)); | | |
| 903 | } | | |
| 904 | | | |
| 905 | // cmd:run ///////////////////////////////////////////////////////////////////////////////////////// | | |
| 906 | | | |
| 907 | // Run should be simple and not expose the full set of arguments provided by build-exe. If specific | | |
| 908 | // build requirements are need, the user should `build-exe` then `run` manually. | | |
| 909 | const usage_run = | | |
| 910 | \\usage: zig run [file] -- <runtime args> | | |
| 911 | \\ | | |
| 912 | \\Options: | | |
| 913 | \\ --help Print this help and exit | | |
| 914 | \\ | | |
| 915 | \\ | | |
| 916 | ; | | |
| 917 | | | |
| 918 | const args_run_spec = []Flag{Flag.Bool("--help")}; | | |
| 919 | | | |
| 920 | fn cmdRun(allocator: *Allocator, args: []const []const u8) !void { | | |
| 921 | var compile_args = args; | | |
| 922 | var runtime_args: []const []const u8 = []const []const u8{}; | | |
| 923 | | | |
| 924 | for (args) |argv, i| { | | |
| 925 | if (mem.eql(u8, argv, "--")) { | | |
| 926 | compile_args = args[0..i]; | | |
| 927 | runtime_args = args[i + 1 ..]; | | |
| 928 | break; | | |
| 929 | } | | |
| 930 | } | | |
| 931 | var flags = try Args.parse(allocator, args_run_spec, compile_args); | | |
| 932 | defer flags.deinit(); | | |
| 933 | | | |
| 934 | if (flags.present("help")) { | | |
| 935 | try stderr.write(usage_run); | | |
| 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 | try stderr.print("runtime args:\n"); | | |
| 945 | for (runtime_args) |cargs| { | | |
| 946 | try stderr.print("{}\n", cargs); | | |
| 947 | } | | |
| 948 | } | | |
| 949 | | | |
| 950 | // cmd:translate-c ///////////////////////////////////////////////////////////////////////////////// | | |
| 951 | | | |
| 952 | const usage_translate_c = | | |
| 953 | \\usage: zig translate-c [file] | | |
| 954 | \\ | | |
| 955 | \\Options: | | |
| 956 | \\ --help Print this help and exit | | |
| 957 | \\ --enable-timing-info Print timing diagnostics | | |
| 958 | \\ --output [path] Output file to write generated zig file (default: stdout) | | |
| 959 | \\ | | |
| 960 | \\ | | |
| 961 | ; | | |
| 962 | | | |
| 963 | const args_translate_c_spec = []Flag{ | | |
| 964 | Flag.Bool("--help"), | | |
| 965 | Flag.Bool("--enable-timing-info"), | | |
| 966 | Flag.Arg1("--libc-include-dir"), | | |
| 967 | Flag.Arg1("--output"), | | |
| 968 | }; | | |
| 969 | | | |
| 970 | fn cmdTranslateC(allocator: *Allocator, args: []const []const u8) !void { | | |
| 971 | var flags = try Args.parse(allocator, args_translate_c_spec, args); | | |
| 972 | defer flags.deinit(); | | |
| 973 | | | |
| 974 | if (flags.present("help")) { | | |
| 975 | try stderr.write(usage_translate_c); | | |
| 976 | os.exit(0); | | |
| 977 | } | | |
| 978 | | | |
| 979 | if (flags.positionals.len != 1) { | | |
| 980 | try stderr.write("expected exactly one c source file\n"); | | |
| 981 | os.exit(1); | | |
| 982 | } | | |
| 983 | | | |
| 984 | // set up codegen | | |
| 985 | | | |
| 986 | const zig_root_source_file = null; | | |
| 987 | | | |
| 988 | // NOTE: translate-c shouldn't require setting up the full codegen instance as it does in | | |
| 989 | // the C++ compiler. | | |
| 990 | | | |
| 991 | // codegen_create(g); | | |
| 992 | // codegen_set_out_name(g, null); | | |
| 993 | // codegen_translate_c(g, flags.positional.at(0)) | | |
| 994 | | | |
| 995 | var output_stream = stdout; | | |
| 996 | if (flags.single("output")) |output_file| { | | |
| 997 | var file = try os.File.openWrite(allocator, output_file); | | |
| 998 | defer file.close(); | | |
| 999 | | | |
| 1000 | var file_stream = io.FileOutStream.init(&file); | | |
| 1001 | // TODO: Not being set correctly, still stdout | | |
| 1002 | output_stream = &file_stream.stream; | | |
| 1003 | } | | |
| 1004 | | | |
| 1005 | // ast_render(g, output_stream, g->root_import->root, 4); | | |
| 1006 | try output_stream.write("pub const example = 10;\n"); | | |
| 1007 | | | |
| 1008 | if (flags.present("enable-timing-info")) { | | |
| 1009 | // codegen_print_timing_info(g, stdout); | | |
| 1010 | try stderr.write("printing timing info for translate-c\n"); | | |
| 1011 | } | | |
| 1012 | } | | |
| 1013 | | | |
| 1014 | // cmd:help //////////////////////////////////////////////////////////////////////////////////////// | | |
| 1015 | | | |
| 1016 | fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { | 681 | fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { |
| 1017 | try stderr.write(usage); | 682 | try stdout.write(usage); |
| 1018 | } | 683 | } |
| 1019 | | 684 | |
| 1020 | // cmd:zen ///////////////////////////////////////////////////////////////////////////////////////// | | |
| 1021 | | | |
| 1022 | const info_zen = | 685 | const info_zen = |
| 1023 | \\ | 686 | \\ |
| 1024 | \\ * Communicate intent precisely. | 687 | \\ * Communicate intent precisely. |
| ... | @@ -1040,8 +703,6 @@ fn cmdZen(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -1040,8 +703,6 @@ fn cmdZen(allocator: *Allocator, args: []const []const u8) !void { |
| 1040 | try stdout.write(info_zen); | 703 | try stdout.write(info_zen); |
| 1041 | } | 704 | } |
| 1042 | | 705 | |
| 1043 | // cmd:internal //////////////////////////////////////////////////////////////////////////////////// | | |
| 1044 | | | |
| 1045 | const usage_internal = | 706 | const usage_internal = |
| 1046 | \\usage: zig internal [subcommand] | 707 | \\usage: zig internal [subcommand] |
| 1047 | \\ | 708 | \\ |
| ... | @@ -1095,3 +756,28 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -1095,3 +756,28 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { |
| 1095 | std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), | 756 | std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), |
| 1096 | ); | 757 | ); |
| 1097 | } | 758 | } |
| | 759 | |
| | 760 | const CliPkg = struct { |
| | 761 | name: []const u8, |
| | 762 | path: []const u8, |
| | 763 | children: ArrayList(*CliPkg), |
| | 764 | parent: ?*CliPkg, |
| | 765 | |
| | 766 | pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg { |
| | 767 | var pkg = try allocator.create(CliPkg{ |
| | 768 | .name = name, |
| | 769 | .path = path, |
| | 770 | .children = ArrayList(*CliPkg).init(allocator), |
| | 771 | .parent = parent, |
| | 772 | }); |
| | 773 | return pkg; |
| | 774 | } |
| | 775 | |
| | 776 | pub fn deinit(self: *CliPkg) void { |
| | 777 | for (self.children.toSliceConst()) |child| { |
| | 778 | child.deinit(); |
| | 779 | } |
| | 780 | self.children.deinit(); |
| | 781 | } |
| | 782 | }; |
| | 783 | |