authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-03-31 19:04:01+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-04-01 17:03:06+12:00
log2e5115b0687ee9b7078dbf70da7d7070a7c80399
tree23f3acc2db17931b0bbb2ef4837de7b06dcfcc25
parent67f11190d10caac1d08b76d60ec28eb2f5173946

Add run compiler command

'zig run file.zig' builds a file and stores the artifacts in the global cache. On successful compilation the binary is executed. 'zig run file.zig -- a b c' does the same, but passes the arguments a, b and c as runtime arguments to the program. Everything after an '--' are treated as runtime arguments. On a posix system, a shebang can be used to run a zig file directly. An example shebang would be '#!/usr/bin/zig run'. You may not be able pass extra compile arguments currently as part of the shebang. Linux for example treats all arguments after the first as a single argument which will result in an 'invalid command'. Currently there is no customisability for the cache path as a compile argument. For a posix system you can use `TMPDIR=. zig run file.zig` to override, in this case using the current directory for the run cache. The input file is always recompiled, even if it has changed. This is intended to be cached but further discussion/thought needs to go into this. Closes #466.

5 files changed, 129 insertions(+), 20 deletions(-)

src/codegen.cpp+3-3
...@@ -6286,7 +6286,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package...@@ -6286,7 +6286,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
6286 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6286 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6287 }6287 }
6288 Buf *import_code = buf_alloc();6288 Buf *import_code = buf_alloc();
6289 if ((err = os_fetch_file_path(abs_full_path, import_code))) {6289 if ((err = os_fetch_file_path(abs_full_path, import_code, false))) {
6290 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6290 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6291 }6291 }
62926292
...@@ -6374,7 +6374,7 @@ static void gen_root_source(CodeGen *g) {...@@ -6374,7 +6374,7 @@ static void gen_root_source(CodeGen *g) {
6374 }6374 }
63756375
6376 Buf *source_code = buf_alloc();6376 Buf *source_code = buf_alloc();
6377 if ((err = os_fetch_file_path(rel_full_path, source_code))) {6377 if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
6378 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));6378 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6379 }6379 }
63806380
...@@ -6439,7 +6439,7 @@ static void gen_global_asm(CodeGen *g) {...@@ -6439,7 +6439,7 @@ static void gen_global_asm(CodeGen *g) {
6439 int err;6439 int err;
6440 for (size_t i = 0; i < g->assembly_files.length; i += 1) {6440 for (size_t i = 0; i < g->assembly_files.length; i += 1) {
6441 Buf *asm_file = g->assembly_files.at(i);6441 Buf *asm_file = g->assembly_files.at(i);
6442 if ((err = os_fetch_file_path(asm_file, &contents))) {6442 if ((err = os_fetch_file_path(asm_file, &contents, false))) {
6443 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));6443 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
6444 }6444 }
6445 buf_append_buf(&g->global_asm, &contents);6445 buf_append_buf(&g->global_asm, &contents);
src/ir.cpp+2-2
...@@ -14709,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi...@@ -14709,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
14709 return ira->codegen->builtin_types.entry_namespace;14709 return ira->codegen->builtin_types.entry_namespace;
14710 }14710 }
1471114711
14712 if ((err = os_fetch_file_path(abs_full_path, import_code))) {14712 if ((err = os_fetch_file_path(abs_full_path, import_code, true))) {
14713 if (err == ErrorFileNotFound) {14713 if (err == ErrorFileNotFound) {
14714 ir_add_error_node(ira, source_node,14714 ir_add_error_node(ira, source_node,
14715 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));14715 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
...@@ -15570,7 +15570,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr...@@ -15570,7 +15570,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
15570 // load from file system into const expr15570 // load from file system into const expr
15571 Buf *file_contents = buf_alloc();15571 Buf *file_contents = buf_alloc();
15572 int err;15572 int err;
15573 if ((err = os_fetch_file_path(&file_path, file_contents))) {15573 if ((err = os_fetch_file_path(&file_path, file_contents, false))) {
15574 if (err == ErrorFileNotFound) {15574 if (err == ErrorFileNotFound) {
15575 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));15575 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
15576 return ira->codegen->builtin_types.entry_invalid;15576 return ira->codegen->builtin_types.entry_invalid;
src/main.cpp+50-8
...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
23 " build-exe [source] create executable from source or object files\n"23 " build-exe [source] create executable from source or object files\n"
24 " build-lib [source] create library from source or object files\n"24 " build-lib [source] create library from source or object files\n"
25 " build-obj [source] create object from source or assembly\n"25 " build-obj [source] create object from source or assembly\n"
26 " run [source] create executable and run immediately\n"
26 " translate-c [source] convert c code to zig code\n"27 " translate-c [source] convert c code to zig code\n"
27 " targets list available compilation targets\n"28 " targets list available compilation targets\n"
28 " test [source] create and run a test build\n"29 " test [source] create and run a test build\n"
...@@ -220,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {...@@ -220,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
220enum Cmd {221enum Cmd {
221 CmdInvalid,222 CmdInvalid,
222 CmdBuild,223 CmdBuild,
224 CmdRun,
223 CmdTest,225 CmdTest,
224 CmdVersion,226 CmdVersion,
225 CmdZen,227 CmdZen,
...@@ -329,6 +331,8 @@ int main(int argc, char **argv) {...@@ -329,6 +331,8 @@ int main(int argc, char **argv) {
329 CliPkg *cur_pkg = allocate<CliPkg>(1);331 CliPkg *cur_pkg = allocate<CliPkg>(1);
330 BuildMode build_mode = BuildModeDebug;332 BuildMode build_mode = BuildModeDebug;
331 ZigList<const char *> test_exec_args = {0};333 ZigList<const char *> test_exec_args = {0};
334 int comptime_args_end = 0;
335 int runtime_args_start = argc;
332336
333 if (argc >= 2 && strcmp(argv[1], "build") == 0) {337 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
334 const char *zig_exe_path = arg0;338 const char *zig_exe_path = arg0;
...@@ -481,11 +485,15 @@ int main(int argc, char **argv) {...@@ -481,11 +485,15 @@ int main(int argc, char **argv) {
481 return (term.how == TerminationIdClean) ? term.code : -1;485 return (term.how == TerminationIdClean) ? term.code : -1;
482 }486 }
483487
484 for (int i = 1; i < argc; i += 1) {488 for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
485 char *arg = argv[i];489 char *arg = argv[i];
486490
487 if (arg[0] == '-') {491 if (arg[0] == '-') {
488 if (strcmp(arg, "--release-fast") == 0) {492 if (strcmp(arg, "--") == 0) {
493 // ignore -- from both compile and runtime arg sets
494 runtime_args_start = i + 1;
495 break;
496 } else if (strcmp(arg, "--release-fast") == 0) {
489 build_mode = BuildModeFastRelease;497 build_mode = BuildModeFastRelease;
490 } else if (strcmp(arg, "--release-safe") == 0) {498 } else if (strcmp(arg, "--release-safe") == 0) {
491 build_mode = BuildModeSafeRelease;499 build_mode = BuildModeSafeRelease;
...@@ -652,6 +660,9 @@ int main(int argc, char **argv) {...@@ -652,6 +660,9 @@ int main(int argc, char **argv) {
652 } else if (strcmp(arg, "build-lib") == 0) {660 } else if (strcmp(arg, "build-lib") == 0) {
653 cmd = CmdBuild;661 cmd = CmdBuild;
654 out_type = OutTypeLib;662 out_type = OutTypeLib;
663 } else if (strcmp(arg, "run") == 0) {
664 cmd = CmdRun;
665 out_type = OutTypeExe;
655 } else if (strcmp(arg, "version") == 0) {666 } else if (strcmp(arg, "version") == 0) {
656 cmd = CmdVersion;667 cmd = CmdVersion;
657 } else if (strcmp(arg, "zen") == 0) {668 } else if (strcmp(arg, "zen") == 0) {
...@@ -670,6 +681,7 @@ int main(int argc, char **argv) {...@@ -670,6 +681,7 @@ int main(int argc, char **argv) {
670 } else {681 } else {
671 switch (cmd) {682 switch (cmd) {
672 case CmdBuild:683 case CmdBuild:
684 case CmdRun:
673 case CmdTranslateC:685 case CmdTranslateC:
674 case CmdTest:686 case CmdTest:
675 if (!in_file) {687 if (!in_file) {
...@@ -724,8 +736,8 @@ int main(int argc, char **argv) {...@@ -724,8 +736,8 @@ int main(int argc, char **argv) {
724 }736 }
725 }737 }
726738
727
728 switch (cmd) {739 switch (cmd) {
740 case CmdRun:
729 case CmdBuild:741 case CmdBuild:
730 case CmdTranslateC:742 case CmdTranslateC:
731 case CmdTest:743 case CmdTest:
...@@ -733,7 +745,7 @@ int main(int argc, char **argv) {...@@ -733,7 +745,7 @@ int main(int argc, char **argv) {
733 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {745 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
734 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");746 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
735 return usage(arg0);747 return usage(arg0);
736 } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {748 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
737 fprintf(stderr, "Expected source file argument.\n");749 fprintf(stderr, "Expected source file argument.\n");
738 return usage(arg0);750 return usage(arg0);
739 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {751 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
...@@ -745,6 +757,10 @@ int main(int argc, char **argv) {...@@ -745,6 +757,10 @@ int main(int argc, char **argv) {
745757
746 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);758 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
747759
760 if (cmd == CmdRun) {
761 out_name = "run";
762 }
763
748 Buf *in_file_buf = nullptr;764 Buf *in_file_buf = nullptr;
749765
750 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :766 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
...@@ -769,9 +785,23 @@ int main(int argc, char **argv) {...@@ -769,9 +785,23 @@ int main(int argc, char **argv) {
769 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;785 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
770786
771 Buf *full_cache_dir = buf_alloc();787 Buf *full_cache_dir = buf_alloc();
772 os_path_resolve(buf_create_from_str("."),788 Buf *run_exec_path = buf_alloc();
773 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),789 if (cmd == CmdRun) {
774 full_cache_dir);790 if (buf_out_name == nullptr) {
791 buf_out_name = buf_create_from_str("run");
792 }
793
794 Buf *global_cache_dir = buf_alloc();
795 os_get_global_cache_directory(global_cache_dir);
796 os_path_join(global_cache_dir, buf_out_name, run_exec_path);
797 os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir);
798
799 out_file = buf_ptr(run_exec_path);
800 } else {
801 os_path_resolve(buf_create_from_str("."),
802 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
803 full_cache_dir);
804 }
775805
776 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
777807
...@@ -855,7 +885,7 @@ int main(int argc, char **argv) {...@@ -855,7 +885,7 @@ int main(int argc, char **argv) {
855885
856 add_package(g, cur_pkg, g->root_package);886 add_package(g, cur_pkg, g->root_package);
857887
858 if (cmd == CmdBuild) {888 if (cmd == CmdBuild || cmd == CmdRun) {
859 codegen_set_emit_file_type(g, emit_file_type);889 codegen_set_emit_file_type(g, emit_file_type);
860890
861 for (size_t i = 0; i < objects.length; i += 1) {891 for (size_t i = 0; i < objects.length; i += 1) {
...@@ -868,6 +898,18 @@ int main(int argc, char **argv) {...@@ -868,6 +898,18 @@ int main(int argc, char **argv) {
868 codegen_link(g, out_file);898 codegen_link(g, out_file);
869 if (timing_info)899 if (timing_info)
870 codegen_print_timing_report(g, stdout);900 codegen_print_timing_report(g, stdout);
901
902 if (cmd == CmdRun) {
903 ZigList<const char*> args = {0};
904 for (int i = runtime_args_start; i < argc; ++i) {
905 args.append(argv[i]);
906 }
907
908 Termination term;
909 os_spawn_process(buf_ptr(run_exec_path), args, &term);
910 return term.code;
911 }
912
871 return EXIT_SUCCESS;913 return EXIT_SUCCESS;
872 } else if (cmd == CmdTranslateC) {914 } else if (cmd == CmdTranslateC) {
873 codegen_translate_c(g, in_file_buf);915 codegen_translate_c(g, in_file_buf);
src/os.cpp+70-5
...@@ -288,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {...@@ -288,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
288 return;288 return;
289}289}
290290
291int os_fetch_file(FILE *f, Buf *out_buf) {291int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
292 static const ssize_t buf_size = 0x2000;292 static const ssize_t buf_size = 0x2000;
293 buf_resize(out_buf, buf_size);293 buf_resize(out_buf, buf_size);
294 ssize_t actual_buf_len = 0;294 ssize_t actual_buf_len = 0;
295
296 bool first_read = true;
297
295 for (;;) {298 for (;;) {
296 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
297 actual_buf_len += amt_read;300 actual_buf_len += amt_read;
301
302 if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) {
303 size_t i = 0;
304 while (true) {
305 if (i > buf_len(out_buf)) {
306 zig_panic("shebang line exceeded %zd characters", buf_size);
307 }
308
309 size_t current_pos = i;
310 i += 1;
311
312 if (out_buf->list.at(current_pos) == '\n') {
313 break;
314 }
315 }
316
317 ZigList<char> *list = &out_buf->list;
318 memmove(list->items, list->items + i, list->length - i);
319 list->length -= i;
320
321 actual_buf_len -= i;
322 }
323
298 if (amt_read != buf_size) {324 if (amt_read != buf_size) {
299 if (feof(f)) {325 if (feof(f)) {
300 buf_resize(out_buf, actual_buf_len);326 buf_resize(out_buf, actual_buf_len);
...@@ -305,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {...@@ -305,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
305 }331 }
306332
307 buf_resize(out_buf, actual_buf_len + buf_size);333 buf_resize(out_buf, actual_buf_len + buf_size);
334 first_read = false;
308 }335 }
309 zig_unreachable();336 zig_unreachable();
310}337}
...@@ -374,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,...@@ -374,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
374401
375 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");402 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
376 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");403 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
377 os_fetch_file(stdout_f, out_stdout);404 os_fetch_file(stdout_f, out_stdout, false);
378 os_fetch_file(stderr_f, out_stderr);405 os_fetch_file(stderr_f, out_stderr, false);
379406
380 fclose(stdout_f);407 fclose(stdout_f);
381 fclose(stderr_f);408 fclose(stderr_f);
...@@ -588,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {...@@ -588,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
588 }615 }
589}616}
590617
591int os_fetch_file_path(Buf *full_path, Buf *out_contents) {618int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
592 FILE *f = fopen(buf_ptr(full_path), "rb");619 FILE *f = fopen(buf_ptr(full_path), "rb");
593 if (!f) {620 if (!f) {
594 switch (errno) {621 switch (errno) {
...@@ -607,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {...@@ -607,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
607 return ErrorFileSystem;634 return ErrorFileSystem;
608 }635 }
609 }636 }
610 int result = os_fetch_file(f, out_contents);637 int result = os_fetch_file(f, out_contents, skip_shebang);
611 fclose(f);638 fclose(f);
612 return result;639 return result;
613}640}
...@@ -780,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {...@@ -780,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
780#endif807#endif
781}808}
782809
810#if defined(ZIG_OS_POSIX)
811int os_get_global_cache_directory(Buf *out_tmp_path) {
812 const char *tmp_dir = getenv("TMPDIR");
813 if (!tmp_dir) {
814 tmp_dir = P_tmpdir;
815 }
816
817 Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
818 Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
819
820 buf_resize(out_tmp_path, 0);
821 os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
822
823 buf_deinit(tmp_dir_buf);
824 buf_deinit(cache_dirname_buf);
825 return 0;
826}
827#endif
828
829#if defined(ZIG_OS_WINDOWS)
830int os_get_global_cache_directory(Buf *out_tmp_path) {
831 char tmp_dir[MAX_PATH + 1];
832 if (GetTempPath(MAX_PATH, tmp_dir) == 0) {
833 zig_panic("GetTempPath failed");
834 }
835
836 Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
837 Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
838
839 buf_resize(out_tmp_path, 0);
840 os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
841
842 buf_deinit(tmp_dir_buf);
843 buf_deinit(cache_dirname_buf);
844 return 0;
845}
846#endif
847
783int os_delete_file(Buf *path) {848int os_delete_file(Buf *path) {
784 if (remove(buf_ptr(path))) {849 if (remove(buf_ptr(path))) {
785 return ErrorFileSystem;850 return ErrorFileSystem;
src/os.hpp+4-2
...@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);...@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);
51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
52bool os_path_is_absolute(Buf *path);52bool os_path_is_absolute(Buf *path);
5353
54int os_get_global_cache_directory(Buf *out_tmp_path);
55
54int os_make_path(Buf *path);56int os_make_path(Buf *path);
55int os_make_dir(Buf *path);57int os_make_dir(Buf *path);
5658
57void os_write_file(Buf *full_path, Buf *contents);59void os_write_file(Buf *full_path, Buf *contents);
58int os_copy_file(Buf *src_path, Buf *dest_path);60int os_copy_file(Buf *src_path, Buf *dest_path);
5961
60int os_fetch_file(FILE *file, Buf *out_contents);62int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
61int os_fetch_file_path(Buf *full_path, Buf *out_contents);63int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
6264
63int os_get_cwd(Buf *out_cwd);65int os_get_cwd(Buf *out_cwd);
6466