Commit 2864359950

Andrew Kelley <superjoe30@gmail.com>
2017-04-11 12:14:46
zig build system writes template build.zig file when none exists
see #204
1 parent 7f47b0c
src/main.cpp
@@ -154,6 +154,8 @@ int main(int argc, char **argv) {
 
     if (argc >= 2 && strcmp(argv[1], "build") == 0) {
         const char *zig_exe_path = arg0;
+        const char *build_file = "build.zig";
+        bool asked_for_help = false;
 
         init_all_targets();
 
@@ -169,6 +171,12 @@ int main(int argc, char **argv) {
         for (int i = 2; i < argc; i += 1) {
             if (strcmp(argv[i], "--debug-build-verbose") == 0) {
                 verbose = true;
+            } else if (strcmp(argv[i], "--help") == 0) {
+                asked_for_help = true;
+                args.append(argv[i]);
+            } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) {
+                build_file = argv[i + 1];
+                i += 1;
             } else {
                 args.append(argv[i]);
             }
@@ -188,7 +196,43 @@ int main(int argc, char **argv) {
         codegen_set_out_type(g, OutTypeExe);
         codegen_set_verbose(g, verbose);
 
-        PackageTableEntry *build_pkg = new_package(".", "build.zig");
+        Buf build_file_abs = BUF_INIT;
+        os_path_resolve(buf_create_from_str("."), buf_create_from_str(build_file), &build_file_abs);
+        Buf build_file_basename = BUF_INIT;
+        Buf build_file_dirname = BUF_INIT;
+        os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
+
+        bool build_file_exists;
+        if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
+            fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err));
+            return 1;
+        }
+        if (!build_file_exists) {
+            if (asked_for_help) {
+                // This usage text has to be synchronized with std/special/build_runner.zig
+                fprintf(stdout,
+                        "Usage: %s build [options]\n"
+                        "\n"
+                        "General Options:\n"
+                        "  --help                 Print this help and exit.\n"
+                        "  --build-file [file]    Override path to build.zig.\n"
+                        "  --verbose              Print commands before executing them.\n"
+                        "  --debug-build-verbose  Print verbose debugging information for the build system itself.\n"
+                , zig_exe_path);
+                return 0;
+            }
+            Buf *build_template_path = buf_alloc();
+            os_path_join(special_dir, buf_create_from_str("build_file_template.zig"), build_template_path);
+
+            if ((err = os_copy_file(build_template_path, &build_file_abs))) {
+                fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));
+            } else {
+                fprintf(stderr, "Wrote build.zig template\n");
+            }
+            return 1;
+        }
+
+        PackageTableEntry *build_pkg = new_package(buf_ptr(&build_file_dirname), buf_ptr(&build_file_basename));
         build_pkg->package_table.put(buf_create_from_str("std"), g->std_package);
         g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
         codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
src/os.cpp
@@ -490,6 +490,58 @@ void os_write_file(Buf *full_path, Buf *contents) {
         zig_panic("close failed");
 }
 
+int os_copy_file(Buf *src_path, Buf *dest_path) {
+    FILE *src_f = fopen(buf_ptr(src_path), "rb");
+    if (!src_f) {
+        int err = errno;
+        if (err == ENOENT) {
+            return ErrorFileNotFound;
+        } else if (err == EACCES || err == EPERM) {
+            return ErrorAccess;
+        } else {
+            return ErrorFileSystem;
+        }
+    }
+    FILE *dest_f = fopen(buf_ptr(dest_path), "wb");
+    if (!dest_f) {
+        int err = errno;
+        if (err == ENOENT) {
+            fclose(src_f);
+            return ErrorFileNotFound;
+        } else if (err == EACCES || err == EPERM) {
+            fclose(src_f);
+            return ErrorAccess;
+        } else {
+            fclose(src_f);
+            return ErrorFileSystem;
+        }
+    }
+
+    static const size_t buf_size = 2048;
+    char buf[buf_size];
+    for (;;) {
+        size_t amt_read = fread(buf, 1, buf_size, src_f);
+        if (amt_read != buf_size) {
+            if (ferror(src_f)) {
+                fclose(src_f);
+                fclose(dest_f);
+                return ErrorFileSystem;
+            }
+        }
+        size_t amt_written = fwrite(buf, 1, amt_read, dest_f);
+        if (amt_written != amt_read) {
+            fclose(src_f);
+            fclose(dest_f);
+            return ErrorFileSystem;
+        }
+        if (feof(src_f)) {
+            fclose(src_f);
+            fclose(dest_f);
+            return 0;
+        }
+    }
+}
+
 int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
     FILE *f = fopen(buf_ptr(full_path), "rb");
     if (!f) {
src/os.hpp
@@ -41,6 +41,7 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
 bool os_path_is_absolute(Buf *path);
 
 void os_write_file(Buf *full_path, Buf *contents);
+int os_copy_file(Buf *src_path, Buf *dest_path);
 
 int os_fetch_file(FILE *file, Buf *out_contents);
 int os_fetch_file_path(Buf *full_path, Buf *out_contents);
std/special/build_file_template.zig
@@ -0,0 +1,8 @@
+const Builder = @import("std").build.Builder;
+
+pub fn build(b: &Builder) {
+    const release = b.option(bool, "release", "optimizations on and safety off") ?? false;
+
+    var exe = b.addExe("src/main.zig", "YOUR_NAME_HERE");
+    exe.setRelease(release);
+}
std/special/build_runner.zig
@@ -77,11 +77,13 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
         root.build(builder);
     }
 
+    // This usage text has to be synchronized with src/main.cpp
     %%out_stream.printf(
         \\Usage: {} build [options]
         \\
         \\General Options:
         \\  --help                 Print this help and exit.
+        \\  --build-file [file]    Override path to build.zig.
         \\  --verbose              Print commands before executing them.
         \\  --debug-build-verbose  Print verbose debugging information for the build system itself.
         \\
CMakeLists.txt
@@ -238,6 +238,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
 install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
 install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
 install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")
+install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_file_template.zig" DESTINATION "${ZIG_STD_DEST}/special")
 install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
 install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_STD_DEST}/special")
 install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special")