Skip to content

Commit 2e5115b

Browse files
committed
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.
1 parent 67f1119 commit 2e5115b

File tree

5 files changed

+129
-20
lines changed

5 files changed

+129
-20
lines changed

src/codegen.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6286,7 +6286,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
62866286
zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
62876287
}
62886288
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))) {
62906290
zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
62916291
}
62926292

@@ -6374,7 +6374,7 @@ static void gen_root_source(CodeGen *g) {
63746374
}
63756375

63766376
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))) {
63786378
zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
63796379
}
63806380

@@ -6439,7 +6439,7 @@ static void gen_global_asm(CodeGen *g) {
64396439
int err;
64406440
for (size_t i = 0; i < g->assembly_files.length; i += 1) {
64416441
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))) {
64436443
zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
64446444
}
64456445
buf_append_buf(&g->global_asm, &contents);

src/ir.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14709,7 +14709,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
1470914709
return ira->codegen->builtin_types.entry_namespace;
1471014710
}
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))) {
1471314713
if (err == ErrorFileNotFound) {
1471414714
ir_add_error_node(ira, source_node,
1471514715
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
1557015570
// load from file system into const expr
1557115571
Buf *file_contents = buf_alloc();
1557215572
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))) {
1557415574
if (err == ErrorFileNotFound) {
1557515575
ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
1557615576
return ira->codegen->builtin_types.entry_invalid;

src/main.cpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
2323
" build-exe [source] create executable from source or object files\n"
2424
" build-lib [source] create library from source or object files\n"
2525
" build-obj [source] create object from source or assembly\n"
26+
" run [source] create executable and run immediately\n"
2627
" translate-c [source] convert c code to zig code\n"
2728
" targets list available compilation targets\n"
2829
" 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) {
220221
enum Cmd {
221222
CmdInvalid,
222223
CmdBuild,
224+
CmdRun,
223225
CmdTest,
224226
CmdVersion,
225227
CmdZen,
@@ -329,6 +331,8 @@ int main(int argc, char **argv) {
329331
CliPkg *cur_pkg = allocate<CliPkg>(1);
330332
BuildMode build_mode = BuildModeDebug;
331333
ZigList<const char *> test_exec_args = {0};
334+
int comptime_args_end = 0;
335+
int runtime_args_start = argc;
332336

333337
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
334338
const char *zig_exe_path = arg0;
@@ -481,11 +485,15 @@ int main(int argc, char **argv) {
481485
return (term.how == TerminationIdClean) ? term.code : -1;
482486
}
483487

484-
for (int i = 1; i < argc; i += 1) {
488+
for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
485489
char *arg = argv[i];
486490

487491
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) {
489497
build_mode = BuildModeFastRelease;
490498
} else if (strcmp(arg, "--release-safe") == 0) {
491499
build_mode = BuildModeSafeRelease;
@@ -652,6 +660,9 @@ int main(int argc, char **argv) {
652660
} else if (strcmp(arg, "build-lib") == 0) {
653661
cmd = CmdBuild;
654662
out_type = OutTypeLib;
663+
} else if (strcmp(arg, "run") == 0) {
664+
cmd = CmdRun;
665+
out_type = OutTypeExe;
655666
} else if (strcmp(arg, "version") == 0) {
656667
cmd = CmdVersion;
657668
} else if (strcmp(arg, "zen") == 0) {
@@ -670,6 +681,7 @@ int main(int argc, char **argv) {
670681
} else {
671682
switch (cmd) {
672683
case CmdBuild:
684+
case CmdRun:
673685
case CmdTranslateC:
674686
case CmdTest:
675687
if (!in_file) {
@@ -724,16 +736,16 @@ int main(int argc, char **argv) {
724736
}
725737
}
726738

727-
728739
switch (cmd) {
740+
case CmdRun:
729741
case CmdBuild:
730742
case CmdTranslateC:
731743
case CmdTest:
732744
{
733745
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
734746
fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
735747
return usage(arg0);
736-
} else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {
748+
} else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
737749
fprintf(stderr, "Expected source file argument.\n");
738750
return usage(arg0);
739751
} else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
@@ -745,6 +757,10 @@ int main(int argc, char **argv) {
745757

746758
bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
747759

760+
if (cmd == CmdRun) {
761+
out_name = "run";
762+
}
763+
748764
Buf *in_file_buf = nullptr;
749765

750766
Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
@@ -769,9 +785,23 @@ int main(int argc, char **argv) {
769785
Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
770786

771787
Buf *full_cache_dir = buf_alloc();
772-
os_path_resolve(buf_create_from_str("."),
773-
buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
774-
full_cache_dir);
788+
Buf *run_exec_path = buf_alloc();
789+
if (cmd == CmdRun) {
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

776806
Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
777807

@@ -855,7 +885,7 @@ int main(int argc, char **argv) {
855885

856886
add_package(g, cur_pkg, g->root_package);
857887

858-
if (cmd == CmdBuild) {
888+
if (cmd == CmdBuild || cmd == CmdRun) {
859889
codegen_set_emit_file_type(g, emit_file_type);
860890

861891
for (size_t i = 0; i < objects.length; i += 1) {
@@ -868,6 +898,18 @@ int main(int argc, char **argv) {
868898
codegen_link(g, out_file);
869899
if (timing_info)
870900
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+
871913
return EXIT_SUCCESS;
872914
} else if (cmd == CmdTranslateC) {
873915
codegen_translate_c(g, in_file_buf);

src/os.cpp

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
288288
return;
289289
}
290290

291-
int os_fetch_file(FILE *f, Buf *out_buf) {
291+
int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
292292
static const ssize_t buf_size = 0x2000;
293293
buf_resize(out_buf, buf_size);
294294
ssize_t actual_buf_len = 0;
295+
296+
bool first_read = true;
297+
295298
for (;;) {
296299
size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
297300
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+
298324
if (amt_read != buf_size) {
299325
if (feof(f)) {
300326
buf_resize(out_buf, actual_buf_len);
@@ -305,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
305331
}
306332

307333
buf_resize(out_buf, actual_buf_len + buf_size);
334+
first_read = false;
308335
}
309336
zig_unreachable();
310337
}
@@ -374,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
374401

375402
FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
376403
FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
377-
os_fetch_file(stdout_f, out_stdout);
378-
os_fetch_file(stderr_f, out_stderr);
404+
os_fetch_file(stdout_f, out_stdout, false);
405+
os_fetch_file(stderr_f, out_stderr, false);
379406

380407
fclose(stdout_f);
381408
fclose(stderr_f);
@@ -588,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
588615
}
589616
}
590617

591-
int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
618+
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
592619
FILE *f = fopen(buf_ptr(full_path), "rb");
593620
if (!f) {
594621
switch (errno) {
@@ -607,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
607634
return ErrorFileSystem;
608635
}
609636
}
610-
int result = os_fetch_file(f, out_contents);
637+
int result = os_fetch_file(f, out_contents, skip_shebang);
611638
fclose(f);
612639
return result;
613640
}
@@ -780,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
780807
#endif
781808
}
782809

810+
#if defined(ZIG_OS_POSIX)
811+
int 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)
830+
int 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+
783848
int os_delete_file(Buf *path) {
784849
if (remove(buf_ptr(path))) {
785850
return ErrorFileSystem;

src/os.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);
5151
void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
5252
bool os_path_is_absolute(Buf *path);
5353

54+
int os_get_global_cache_directory(Buf *out_tmp_path);
55+
5456
int os_make_path(Buf *path);
5557
int os_make_dir(Buf *path);
5658

5759
void os_write_file(Buf *full_path, Buf *contents);
5860
int os_copy_file(Buf *src_path, Buf *dest_path);
5961

60-
int os_fetch_file(FILE *file, Buf *out_contents);
61-
int os_fetch_file_path(Buf *full_path, Buf *out_contents);
62+
int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
63+
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
6264

6365
int os_get_cwd(Buf *out_cwd);
6466

0 commit comments

Comments
 (0)