Commit bf9a16a037

Andrew Kelley <andrew@ziglang.org>
2020-09-22 08:28:34
stage2: implement `zig init-lib` and `zig init-exe`
1 parent 877e424
Changed files (2)
src/main.zig
@@ -140,6 +140,10 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
         return cmdFmt(gpa, cmd_args);
     } else if (mem.eql(u8, cmd, "libc")) {
         return cmdLibC(gpa, cmd_args);
+    } else if (mem.eql(u8, cmd, "init-exe")) {
+        return cmdInit(gpa, arena, cmd_args, .Exe);
+    } else if (mem.eql(u8, cmd, "init-lib")) {
+        return cmdInit(gpa, arena, cmd_args, .Lib);
     } else if (mem.eql(u8, cmd, "targets")) {
         const info = try detectNativeTargetInfo(arena, .{});
         const stdout = io.getStdOut().outStream();
@@ -1520,6 +1524,97 @@ pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void {
     }
 }
 
+pub const usage_init =
+    \\Usage: zig init-exe
+    \\       zig init-lib
+    \\
+    \\   Initializes a `zig build` project in the current working
+    \\   directory.
+    \\
+    \\Options:
+    \\   --help                 Print this help and exit
+    \\
+    \\
+;
+
+pub fn cmdInit(
+    gpa: *Allocator,
+    arena: *Allocator,
+    args: []const []const u8,
+    output_mode: std.builtin.OutputMode,
+) !void {
+    {
+        var i: usize = 0;
+        while (i < args.len) : (i += 1) {
+            const arg = args[i];
+            if (mem.startsWith(u8, arg, "-")) {
+                if (mem.eql(u8, arg, "--help")) {
+                    try io.getStdOut().writeAll(usage_init);
+                    process.exit(0);
+                } else {
+                    fatal("unrecognized parameter: '{}'", .{arg});
+                }
+            } else {
+                fatal("unexpected extra parameter: '{}'", .{arg});
+            }
+        }
+    }
+    const self_exe_path = try fs.selfExePathAlloc(arena);
+    var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
+        fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
+    };
+    defer zig_lib_directory.handle.close();
+
+    const s = fs.path.sep_str;
+    const template_sub_path = switch (output_mode) {
+        .Obj => unreachable,
+        .Lib => "std" ++ s ++ "special" ++ s ++ "init-lib",
+        .Exe => "std" ++ s ++ "special" ++ s ++ "init-exe",
+    };
+    var template_dir = try zig_lib_directory.handle.openDir(template_sub_path, .{});
+    defer template_dir.close();
+
+    const cwd_path = try process.getCwdAlloc(arena);
+    const cwd_basename = fs.path.basename(cwd_path);
+
+    const max_bytes = 10 * 1024 * 1024;
+    const build_zig_contents = template_dir.readFileAlloc(arena, "build.zig", max_bytes) catch |err| {
+        fatal("unable to read template file 'build.zig': {}", .{@errorName(err)});
+    };
+    var modified_build_zig_contents = std.ArrayList(u8).init(arena);
+    try modified_build_zig_contents.ensureCapacity(build_zig_contents.len);
+    for (build_zig_contents) |c| {
+        if (c == '$') {
+            try modified_build_zig_contents.appendSlice(cwd_basename);
+        } else {
+            try modified_build_zig_contents.append(c);
+        }
+    }
+    const main_zig_contents = template_dir.readFileAlloc(arena, "src" ++ s ++ "main.zig", max_bytes) catch |err| {
+        fatal("unable to read template file 'main.zig': {}", .{@errorName(err)});
+    };
+    if (fs.cwd().access("build.zig", .{})) |_| {
+        fatal("existing build.zig file would be overwritten", .{});
+    } else |err| switch (err) {
+        error.FileNotFound => {},
+        else => fatal("unable to test existence of build.zig: {}\n", .{@errorName(err)}),
+    }
+    var src_dir = try fs.cwd().makeOpenPath("src", .{});
+    defer src_dir.close();
+
+    try src_dir.writeFile("main.zig", main_zig_contents);
+    try fs.cwd().writeFile("build.zig", modified_build_zig_contents.items);
+
+    std.log.info("Created build.zig", .{});
+    std.log.info("Created src" ++ s ++ "main.zig", .{});
+
+    switch (output_mode) {
+        .Lib => std.log.info("Next, try `zig build --help` or `zig build test`", .{}),
+        .Exe => std.log.info("Next, try `zig build --help` or `zig build run`", .{}),
+        .Obj => unreachable,
+    }
+}
+
 pub const usage_fmt =
     \\Usage: zig fmt [file]...
     \\
BRANCH_TODO
@@ -1,3 +1,5 @@
+ * skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)
+   (maybe make it an explicit option and have main.zig disable it)
  * `zig build`
  * repair @cImport
  * make sure zig cc works
@@ -12,7 +14,8 @@
  *  -fno-emit-asm                (default) do not output .s (assembly code)\n"
  *  -femit-llvm-ir               produce a .ll file with LLVM IR\n"
  *  -fno-emit-llvm-ir            (default) do not produce a .ll file with LLVM IR\n"
- *  --cache-dir [path]           override the local cache directory\n"
+ *  --cache-dir [path]           override the local cache directory
+ *  --global-cache-dir [path]    override the global cache directory
  * implement proper parsing of LLD stderr/stdout and exposing compile errors
  * implement proper parsing of clang stderr/stdout and exposing compile errors
  * support rpaths in ELF linker code
@@ -27,8 +30,6 @@
  * support cross compiling stage2 with `zig build`
  * --main-pkg-path
  * audit the CLI options for stage2
- * `zig init-lib`
- * `zig init-exe`
  * restore error messages for stage2_add_link_lib
  * audit the base cache hash
  * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
@@ -56,10 +57,6 @@
  * libc_installation.zig: make it look for msvc only if msvc abi is chosen
  * switch the default C ABI for windows to be mingw-w64
  * change glibc log errors to normal exposed compile errors
- * update Package to use Compilation.Directory in create()
-   - skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)
-     (maybe make it an explicit option and have main.zig disable it)
-   - make it possible for Package to not openDir and reference already existing resources.
  * improve Directory.join to only use 1 allocation in a clean way.
  * tracy builds with lc++
  * some kind of "zig identifier escape" function rather than unconditionally using @"" syntax