From 4c6f1e614a204293732004ef844e8bb057bdc212 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Sep 2018 17:08:56 -0400 Subject: [PATCH] remove `zig build --init`. add `zig init-lib` and `zig init-exe` init-lib creates a working static library with tests, and init-exe creates a working hello world with a `run` target. both now have test coverage with the new "cli tests" file. closes #1035 --- CMakeLists.txt | 13 +- build.zig | 1 + doc/langref.html.in | 2 +- src/compiler.cpp | 101 ++++++++++++ src/compiler.hpp | 4 + src/main.cpp | 230 ++++++++++++++-------------- src/os.cpp | 6 +- src/os.hpp | 2 +- std/special/build_file_template.zig | 10 -- std/special/init-exe/build.zig | 15 ++ std/special/init-exe/src/main.zig | 5 + std/special/init-lib/build.zig | 16 ++ std/special/init-lib/src/main.zig | 10 ++ test/cli.zig | 92 +++++++++++ test/tests.zig | 15 ++ 15 files changed, 384 insertions(+), 138 deletions(-) delete mode 100644 std/special/build_file_template.zig create mode 100644 std/special/init-exe/build.zig create mode 100644 std/special/init-exe/src/main.zig create mode 100644 std/special/init-lib/build.zig create mode 100644 std/special/init-lib/src/main.zig create mode 100644 test/cli.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index ee9f9c281..2e26c4ff4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -597,7 +597,6 @@ set(ZIG_STD_FILES "sort.zig" "special/bootstrap.zig" "special/bootstrap_lib.zig" - "special/build_file_template.zig" "special/build_runner.zig" "special/builtin.zig" "special/compiler_rt/aulldiv.zig" @@ -615,22 +614,26 @@ set(ZIG_STD_FILES "special/compiler_rt/fixunstfdi.zig" "special/compiler_rt/fixunstfsi.zig" "special/compiler_rt/fixunstfti.zig" + "special/compiler_rt/floattidf.zig" + "special/compiler_rt/floattisf.zig" + "special/compiler_rt/floattitf.zig" "special/compiler_rt/floatunditf.zig" "special/compiler_rt/floatunsitf.zig" "special/compiler_rt/floatuntidf.zig" "special/compiler_rt/floatuntisf.zig" "special/compiler_rt/floatuntitf.zig" - "special/compiler_rt/floattidf.zig" - "special/compiler_rt/floattisf.zig" - "special/compiler_rt/floattitf.zig" - "special/compiler_rt/muloti4.zig" "special/compiler_rt/index.zig" + "special/compiler_rt/muloti4.zig" "special/compiler_rt/truncXfYf2.zig" "special/compiler_rt/udivmod.zig" "special/compiler_rt/udivmoddi4.zig" "special/compiler_rt/udivmodti4.zig" "special/compiler_rt/udivti3.zig" "special/compiler_rt/umodti3.zig" + "special/init-exe/build.zig" + "special/init-exe/src/main.zig" + "special/init-lib/build.zig" + "special/init-lib/src/main.zig" "special/panic.zig" "special/test_runner.zig" "unicode.zig" diff --git a/build.zig b/build.zig index 0bb4808dc..bc9cd4c1c 100644 --- a/build.zig +++ b/build.zig @@ -112,6 +112,7 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addBuildExampleTests(b, test_filter, modes)); + test_step.dependOn(tests.addCliTests(b, test_filter, modes)); test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); diff --git a/doc/langref.html.in b/doc/langref.html.in index f5b92873e..9bd11b823 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5877,7 +5877,7 @@ fn add(a: i32, b: i32) i32 { {#header_open|@OpaqueType#}
{#syntax#}@OpaqueType() type{#endsyntax#}

- Creates a new type with an unknown size and alignment. + Creates a new type with an unknown (but non-zero) size and alignment.

This is typically used for type safety when interacting with C code that does not expose struct details. diff --git a/src/compiler.cpp b/src/compiler.cpp index dd02b541d..0d4dff5d5 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -5,6 +5,9 @@ static Buf saved_compiler_id = BUF_INIT; static Buf saved_app_data_dir = BUF_INIT; static Buf saved_stage1_path = BUF_INIT; +static Buf saved_lib_dir = BUF_INIT; +static Buf saved_special_dir = BUF_INIT; +static Buf saved_std_dir = BUF_INIT; Buf *get_stage1_cache_path() { if (saved_stage1_path.list.length != 0) { @@ -64,3 +67,101 @@ Error get_compiler_id(Buf **result) { return ErrorNone; } + +static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) { + Buf lib_buf = BUF_INIT; + buf_init_from_str(&lib_buf, "lib"); + + Buf zig_buf = BUF_INIT; + buf_init_from_str(&zig_buf, "zig"); + + Buf std_buf = BUF_INIT; + buf_init_from_str(&std_buf, "std"); + + Buf index_zig_buf = BUF_INIT; + buf_init_from_str(&index_zig_buf, "index.zig"); + + Buf test_lib_dir = BUF_INIT; + Buf test_zig_dir = BUF_INIT; + Buf test_std_dir = BUF_INIT; + Buf test_index_file = BUF_INIT; + + os_path_join(test_path, &lib_buf, &test_lib_dir); + os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir); + os_path_join(&test_zig_dir, &std_buf, &test_std_dir); + os_path_join(&test_std_dir, &index_zig_buf, &test_index_file); + + int err; + bool exists; + if ((err = os_file_exists(&test_index_file, &exists))) { + exists = false; + } + if (exists) { + buf_init_from_buf(out_zig_lib_dir, &test_zig_dir); + return true; + } + return false; +} + +static int find_zig_lib_dir(Buf *out_path) { + int err; + + Buf self_exe_path = BUF_INIT; + buf_resize(&self_exe_path, 0); + if (!(err = os_self_exe_path(&self_exe_path))) { + Buf *cur_path = &self_exe_path; + + for (;;) { + Buf *test_dir = buf_alloc(); + os_path_dirname(cur_path, test_dir); + + if (buf_eql_buf(test_dir, cur_path)) { + break; + } + + if (test_zig_install_prefix(test_dir, out_path)) { + return 0; + } + + cur_path = test_dir; + } + } + + return ErrorFileNotFound; +} + +Buf *get_zig_lib_dir(void) { + if (saved_lib_dir.list.length != 0) { + return &saved_lib_dir; + } + buf_resize(&saved_lib_dir, 0); + + int err; + if ((err = find_zig_lib_dir(&saved_lib_dir))) { + fprintf(stderr, "Unable to find zig lib directory\n"); + exit(EXIT_FAILURE); + } + return &saved_lib_dir; +} + +Buf *get_zig_std_dir() { + if (saved_std_dir.list.length != 0) { + return &saved_std_dir; + } + buf_resize(&saved_std_dir, 0); + + os_path_join(get_zig_lib_dir(), buf_create_from_str("std"), &saved_std_dir); + + return &saved_std_dir; +} + +Buf *get_zig_special_dir() { + if (saved_special_dir.list.length != 0) { + return &saved_special_dir; + } + buf_resize(&saved_special_dir, 0); + + os_path_join(get_zig_std_dir(), buf_sprintf("special"), &saved_special_dir); + + return &saved_special_dir; +} diff --git a/src/compiler.hpp b/src/compiler.hpp index b95e4ceda..ffdd1cefb 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -14,4 +14,8 @@ Buf *get_stage1_cache_path(); Error get_compiler_id(Buf **result); +Buf *get_zig_lib_dir(); +Buf *get_zig_special_dir(); +Buf *get_zig_std_dir(); + #endif diff --git a/src/main.cpp b/src/main.cpp index bf6c14297..95fba8d59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,8 @@ static int usage(const char *arg0) { " build-obj [source] create object from source or assembly\n" " builtin show the source code of that @import(\"builtin\")\n" " id print the base64-encoded compiler id\n" + " init-exe initialize a `zig build` application in the cwd\n" + " init-lib initialize a `zig build` library in the cwd\n" " run [source] create executable and run immediately\n" " translate-c [source] convert c code to zig code\n" " targets list available compilation targets\n" @@ -34,7 +36,7 @@ static int usage(const char *arg0) { "Compile Options:\n" " --assembly [source] add assembly file to build\n" " --cache-dir [path] override the cache directory\n" - " --cache [auto|off|on] build to the global cache and print output path to stdout\n" + " --cache [auto|off|on] build in global cache, print out paths to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" " -ftime-report print timing diagnostics\n" @@ -42,7 +44,7 @@ static int usage(const char *arg0) { " --name [name] override output name\n" " --output [file] override destination path\n" " --output-h [file] override generated header file path\n" - " --pkg-begin [name] [path] make package available to import and push current pkg\n" + " --pkg-begin [name] [path] make pkg available to import and push current pkg\n" " --pkg-end pop current pkg\n" " --release-fast build with optimizations on and safety off\n" " --release-safe build with optimizations on and safety on\n" @@ -52,17 +54,16 @@ static int usage(const char *arg0) { " --target-arch [name] specify target architecture\n" " --target-environ [name] specify target environment\n" " --target-os [name] specify target operating system\n" - " --verbose-tokenize turn on compiler debug output for tokenization\n" - " --verbose-ast turn on compiler debug output for parsing into an AST\n" - " --verbose-link turn on compiler debug output for linking\n" - " --verbose-ir turn on compiler debug output for Zig IR\n" - " --verbose-llvm-ir turn on compiler debug output for LLVM IR\n" - " --verbose-cimport turn on compiler debug output for C imports\n" + " --verbose-tokenize enable compiler debug output for tokenization\n" + " --verbose-ast enable compiler debug output for AST parsing\n" + " --verbose-link enable compiler debug output for linking\n" + " --verbose-ir enable compiler debug output for Zig IR\n" + " --verbose-llvm-ir enable compiler debug output for LLVM IR\n" + " --verbose-cimport enable compiler debug output for C imports\n" " -dirafter [dir] same as -isystem but do it last\n" " -isystem [dir] add additional search path for other .h files\n" - " -mllvm [arg] additional arguments to forward to LLVM's option processing\n" + " -mllvm [arg] forward an arg to LLVM's option processing\n" "Link Options:\n" - " --ar-path [path] set the path to ar\n" " --dynamic-linker [path] set the path to ld.so\n" " --each-lib-rpath add rpath for each used dynamic library\n" " --libc-lib-dir [path] directory where libc crt1.o resides\n" @@ -142,78 +143,6 @@ static int print_target_list(FILE *f) { return EXIT_SUCCESS; } -static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) { - Buf lib_buf = BUF_INIT; - buf_init_from_str(&lib_buf, "lib"); - - Buf zig_buf = BUF_INIT; - buf_init_from_str(&zig_buf, "zig"); - - Buf std_buf = BUF_INIT; - buf_init_from_str(&std_buf, "std"); - - Buf index_zig_buf = BUF_INIT; - buf_init_from_str(&index_zig_buf, "index.zig"); - - Buf test_lib_dir = BUF_INIT; - Buf test_zig_dir = BUF_INIT; - Buf test_std_dir = BUF_INIT; - Buf test_index_file = BUF_INIT; - - os_path_join(test_path, &lib_buf, &test_lib_dir); - os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir); - os_path_join(&test_zig_dir, &std_buf, &test_std_dir); - os_path_join(&test_std_dir, &index_zig_buf, &test_index_file); - - int err; - bool exists; - if ((err = os_file_exists(&test_index_file, &exists))) { - exists = false; - } - if (exists) { - buf_init_from_buf(out_zig_lib_dir, &test_zig_dir); - return true; - } - return false; -} - -static int find_zig_lib_dir(Buf *out_path) { - int err; - - Buf self_exe_path = BUF_INIT; - buf_resize(&self_exe_path, 0); - if (!(err = os_self_exe_path(&self_exe_path))) { - Buf *cur_path = &self_exe_path; - - for (;;) { - Buf *test_dir = buf_alloc(); - os_path_dirname(cur_path, test_dir); - - if (buf_eql_buf(test_dir, cur_path)) { - break; - } - - if (test_zig_install_prefix(test_dir, out_path)) { - return 0; - } - - cur_path = test_dir; - } - } - - return ErrorFileNotFound; -} - -static Buf *resolve_zig_lib_dir(void) { - int err; - Buf *result = buf_alloc(); - if ((err = find_zig_lib_dir(result))) { - fprintf(stderr, "Unable to find zig lib directory\n"); - exit(EXIT_FAILURE); - } - return result; -} - enum Cmd { CmdInvalid, CmdBuild, @@ -277,6 +206,9 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) { } int main(int argc, char **argv) { + char *arg0 = argv[0]; + Error err; + if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) { printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", ZIG_CMAKE_BINARY_DIR, @@ -290,8 +222,10 @@ int main(int argc, char **argv) { return 0; } + // Must be before all os.hpp function calls. + os_init(); + if (argc == 2 && strcmp(argv[1], "id") == 0) { - Error err; Buf *compiler_id; if ((err = get_compiler_id(&compiler_id))) { fprintf(stderr, "Unable to determine compiler id: %s\n", err_str(err)); @@ -301,9 +235,97 @@ int main(int argc, char **argv) { return EXIT_SUCCESS; } - os_init(); + enum InitKind { + InitKindNone, + InitKindExe, + InitKindLib, + }; + InitKind init_kind = InitKindNone; + if (argc >= 2) { + const char *init_cmd = argv[1]; + if (strcmp(init_cmd, "init-exe") == 0) { + init_kind = InitKindExe; + } else if (strcmp(init_cmd, "init-lib") == 0) { + init_kind = InitKindLib; + } + if (init_kind != InitKindNone) { + if (argc >= 3) { + fprintf(stderr, "Unexpected extra argument: %s\n", argv[2]); + return usage(arg0); + } + Buf *cmd_template_path = buf_alloc(); + os_path_join(get_zig_special_dir(), buf_create_from_str(init_cmd), cmd_template_path); + Buf *build_zig_path = buf_alloc(); + os_path_join(cmd_template_path, buf_create_from_str("build.zig"), build_zig_path); + Buf *src_dir_path = buf_alloc(); + os_path_join(cmd_template_path, buf_create_from_str("src"), src_dir_path); + Buf *main_zig_path = buf_alloc(); + os_path_join(src_dir_path, buf_create_from_str("main.zig"), main_zig_path); + + Buf *cwd = buf_alloc(); + if ((err = os_get_cwd(cwd))) { + fprintf(stderr, "Unable to get cwd: %s\n", err_str(err)); + return EXIT_FAILURE; + } + Buf *cwd_basename = buf_alloc(); + os_path_split(cwd, nullptr, cwd_basename); + + Buf *build_zig_contents = buf_alloc(); + if ((err = os_fetch_file_path(build_zig_path, build_zig_contents, false))) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(build_zig_path), err_str(err)); + return EXIT_FAILURE; + } + Buf *modified_build_zig_contents = buf_alloc(); + for (size_t i = 0; i < buf_len(build_zig_contents); i += 1) { + char c = buf_ptr(build_zig_contents)[i]; + if (c == '$') { + buf_append_buf(modified_build_zig_contents, cwd_basename); + } else { + buf_append_char(modified_build_zig_contents, c); + } + } + + Buf *main_zig_contents = buf_alloc(); + if ((err = os_fetch_file_path(main_zig_path, main_zig_contents, false))) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(main_zig_path), err_str(err)); + return EXIT_FAILURE; + } + + Buf *out_build_zig_path = buf_create_from_str("build.zig"); + Buf *out_src_dir_path = buf_create_from_str("src"); + Buf *out_main_zig_path = buf_alloc(); + os_path_join(out_src_dir_path, buf_create_from_str("main.zig"), out_main_zig_path); + + bool already_exists; + if ((err = os_file_exists(out_build_zig_path, &already_exists))) { + fprintf(stderr, "Unable test existence of %s: %s\n", buf_ptr(out_build_zig_path), err_str(err)); + return EXIT_FAILURE; + } + if (already_exists) { + fprintf(stderr, "This file would be overwritten: %s\n", buf_ptr(out_build_zig_path)); + return EXIT_FAILURE; + } + + if ((err = os_make_dir(out_src_dir_path))) { + fprintf(stderr, "Unable to make directory: %s: %s\n", buf_ptr(out_src_dir_path), err_str(err)); + return EXIT_FAILURE; + } + os_write_file(out_build_zig_path, modified_build_zig_contents); + os_write_file(out_main_zig_path, main_zig_contents); + fprintf(stderr, "Created %s\n", buf_ptr(out_build_zig_path)); + fprintf(stderr, "Created %s\n", buf_ptr(out_main_zig_path)); + if (init_kind == InitKindExe) { + fprintf(stderr, "\nNext, try `zig build --help` or `zig build run`\n"); + } else if (init_kind == InitKindLib) { + fprintf(stderr, "\nNext, try `zig build --help` or `zig build test`\n"); + } else { + zig_unreachable(); + } + + return EXIT_SUCCESS; + } + } - char *arg0 = argv[0]; Cmd cmd = CmdInvalid; EmitFileType emit_file_type = EmitFileTypeBinary; const char *in_file = nullptr; @@ -333,7 +355,6 @@ int main(int argc, char **argv) { ZigList link_libs = {0}; ZigList forbidden_link_libs = {0}; ZigList frameworks = {0}; - int err; const char *target_arch = nullptr; const char *target_os = nullptr; const char *target_environ = nullptr; @@ -364,7 +385,6 @@ int main(int argc, char **argv) { const char *zig_exe_path = arg0; const char *build_file = "build.zig"; bool asked_for_help = false; - bool asked_to_init = false; init_all_targets(); @@ -376,9 +396,6 @@ int main(int argc, char **argv) { if (strcmp(argv[i], "--help") == 0) { asked_for_help = true; args.append(argv[i]); - } else if (strcmp(argv[i], "--init") == 0) { - asked_to_init = true; - args.append(argv[i]); } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) { build_file = argv[i + 1]; i += 1; @@ -390,18 +407,10 @@ int main(int argc, char **argv) { } } - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - - Buf *zig_std_dir = buf_alloc(); - os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir); - - Buf *special_dir = buf_alloc(); - os_path_join(zig_std_dir, buf_sprintf("special"), special_dir); - Buf *build_runner_path = buf_alloc(); - os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path); + os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path); - CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); + CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir()); g->enable_time_report = timing_info; buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); codegen_set_out_name(g, buf_create_from_str("build")); @@ -437,7 +446,6 @@ int main(int argc, char **argv) { "\n" "General Options:\n" " --help Print this help and exit\n" - " --init Generate a build.zig template\n" " --build-file [file] Override path to build.zig\n" " --cache-dir [path] Override path to cache directory\n" " --verbose Print commands before executing them\n" @@ -463,22 +471,11 @@ int main(int argc, char **argv) { "\n" , zig_exe_path); return EXIT_SUCCESS; - } else if (asked_to_init) { - 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)); - return EXIT_FAILURE; - } else { - fprintf(stderr, "Wrote build.zig template\n"); - return EXIT_SUCCESS; - } } fprintf(stderr, "No 'build.zig' file found.\n" - "Initialize a 'build.zig' template file with `zig build --init`,\n" + "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n" "or build an executable directly with `zig build-exe $FILENAME.zig`.\n" "See: `zig build --help` or `zig help` for more options.\n" ); @@ -773,8 +770,7 @@ int main(int argc, char **argv) { switch (cmd) { case CmdBuiltin: { - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf); + CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir()); Buf *builtin_source = codegen_generate_builtin_source(g); if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); @@ -832,9 +828,7 @@ int main(int argc, char **argv) { if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); } - Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); - - CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf); + CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir()); g->enable_time_report = timing_info; buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); codegen_set_out_name(g, buf_out_name); diff --git a/src/os.cpp b/src/os.cpp index 6e46b96e4..431f7d16b 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1091,14 +1091,14 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { return result; } -int os_get_cwd(Buf *out_cwd) { +Error os_get_cwd(Buf *out_cwd) { #if defined(ZIG_OS_WINDOWS) char buf[4096]; if (GetCurrentDirectory(4096, buf) == 0) { zig_panic("GetCurrentDirectory failed"); } buf_init_from_str(out_cwd, buf); - return 0; + return ErrorNone; #elif defined(ZIG_OS_POSIX) char buf[PATH_MAX]; char *res = getcwd(buf, PATH_MAX); @@ -1106,7 +1106,7 @@ int os_get_cwd(Buf *out_cwd) { zig_panic("unable to get cwd: %s", strerror(errno)); } buf_init_from_str(out_cwd, res); - return 0; + return ErrorNone; #else #error "missing os_get_cwd implementation" #endif diff --git a/src/os.hpp b/src/os.hpp index 1054bf24a..30083971e 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -114,7 +114,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path); Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang); Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang); -int os_get_cwd(Buf *out_cwd); +Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd); bool os_stderr_tty(void); void os_stderr_set_color(TermColor color); diff --git a/std/special/build_file_template.zig b/std/special/build_file_template.zig deleted file mode 100644 index 11e964769..000000000 --- a/std/special/build_file_template.zig +++ /dev/null @@ -1,10 +0,0 @@ -const Builder = @import("std").build.Builder; - -pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); - exe.setBuildMode(mode); - - b.default_step.dependOn(&exe.step); - b.installArtifact(exe); -} diff --git a/std/special/init-exe/build.zig b/std/special/init-exe/build.zig new file mode 100644 index 000000000..21a260056 --- /dev/null +++ b/std/special/init-exe/build.zig @@ -0,0 +1,15 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + const exe = b.addExecutable("$", "src/main.zig"); + exe.setBuildMode(mode); + + const run_step = b.step("run", "Run the app"); + const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()}); + run_step.dependOn(&run_cmd.step); + run_cmd.step.dependOn(&exe.step); + + b.default_step.dependOn(&exe.step); + b.installArtifact(exe); +} diff --git a/std/special/init-exe/src/main.zig b/std/special/init-exe/src/main.zig new file mode 100644 index 000000000..71034d1bf --- /dev/null +++ b/std/special/init-exe/src/main.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn main() error!void { + std.debug.warn("All your base are belong to us.\n"); +} diff --git a/std/special/init-lib/build.zig b/std/special/init-lib/build.zig new file mode 100644 index 000000000..9557ccf10 --- /dev/null +++ b/std/special/init-lib/build.zig @@ -0,0 +1,16 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const mode = b.standardReleaseOptions(); + const lib = b.addStaticLibrary("$", "src/main.zig"); + lib.setBuildMode(mode); + + var main_tests = b.addTest("src/main.zig"); + main_tests.setBuildMode(mode); + + const test_step = b.step("test", "Run library tests"); + test_step.dependOn(&main_tests.step); + + b.default_step.dependOn(&lib.step); + b.installArtifact(lib); +} diff --git a/std/special/init-lib/src/main.zig b/std/special/init-lib/src/main.zig new file mode 100644 index 000000000..27fdeb203 --- /dev/null +++ b/std/special/init-lib/src/main.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +export fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "basic add functionality" { + assertOrPanic(add(3, 7) == 10); +} diff --git a/test/cli.zig b/test/cli.zig new file mode 100644 index 000000000..f65dabc9f --- /dev/null +++ b/test/cli.zig @@ -0,0 +1,92 @@ +const std = @import("std"); +const os = std.os; +const assertOrPanic = std.debug.assertOrPanic; + +var a: *std.mem.Allocator = undefined; + +pub fn main() !void { + var direct_allocator = std.heap.DirectAllocator.init(); + defer direct_allocator.deinit(); + + var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator); + defer arena.deinit(); + + var arg_it = os.args(); + + // skip my own exe name + _ = arg_it.skip(); + + a = &arena.allocator; + + const zig_exe_rel = try (arg_it.next(a) orelse { + std.debug.warn("Expected first argument to be path to zig compiler\n"); + return error.InvalidArgs; + }); + const cache_root = try (arg_it.next(a) orelse { + std.debug.warn("Expected second argument to be cache root directory path\n"); + return error.InvalidArgs; + }); + const zig_exe = try os.path.resolve(a, zig_exe_rel); + + try testZigInitLib(zig_exe, cache_root); + try testZigInitExe(zig_exe, cache_root); +} + +fn unwrapArg(arg: UnwrapArgError![]u8) UnwrapArgError![]u8 { + return arg catch |err| { + warn("Unable to parse command line: {}\n", err); + return err; + }; +} + +fn printCmd(cwd: []const u8, argv: []const []const u8) void { + std.debug.warn("cd {} && ", cwd); + for (argv) |arg| { + std.debug.warn("{} ", arg); + } + std.debug.warn("\n"); +} + +fn exec(cwd: []const u8, argv: []const []const u8) !os.ChildProcess.ExecResult { + const max_output_size = 100 * 1024; + const result = os.ChildProcess.exec(a, argv, cwd, null, max_output_size) catch |err| { + std.debug.warn("The following command failed:\n"); + printCmd(cwd, argv); + return err; + }; + switch (result.term) { + os.ChildProcess.Term.Exited => |code| { + if (code != 0) { + std.debug.warn("The following command exited with error code {}:\n", code); + printCmd(cwd, argv); + std.debug.warn("stderr:\n{}\n", result.stderr); + return error.CommandFailed; + } + }, + else => { + std.debug.warn("The following command terminated unexpectedly:\n"); + printCmd(cwd, argv); + std.debug.warn("stderr:\n{}\n", result.stderr); + return error.CommandFailed; + }, + } + return result; +} + +fn testZigInitLib(zig_exe: []const u8, cache_root: []const u8) !void { + const dir_path = try os.path.join(a, cache_root, "clitest"); + try os.deleteTree(a, dir_path); + try os.makeDir(dir_path); + _ = try exec(dir_path, [][]const u8{ zig_exe, "init-lib" }); + const test_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "test" }); + assertOrPanic(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); +} + +fn testZigInitExe(zig_exe: []const u8, cache_root: []const u8) !void { + const dir_path = try os.path.join(a, cache_root, "clitest"); + try os.deleteTree(a, dir_path); + try os.makeDir(dir_path); + _ = try exec(dir_path, [][]const u8{ zig_exe, "init-exe" }); + const run_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "run" }); + assertOrPanic(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n")); +} diff --git a/test/tests.zig b/test/tests.zig index a0e179207..88908e877 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -103,6 +103,21 @@ pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8, modes: return cases.step; } +pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { + const step = b.step("test-cli", "Test the command line interface"); + + const exe = b.addExecutable("test-cli", "test/cli.zig"); + const run_cmd = b.addCommand(null, b.env_map, [][]const u8{ + b.pathFromRoot(exe.getOutputPath()), + os.path.realAlloc(b.allocator, b.zig_exe) catch unreachable, + b.pathFromRoot(b.cache_root), + }); + run_cmd.step.dependOn(&exe.step); + + step.dependOn(&run_cmd.step); + return step; +} + pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step { const cases = b.allocator.create(CompareOutputContext{ .b = b,