Skip to content

Commit 2fb9ce7

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 edca173 commit 2fb9ce7

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
@@ -6289,7 +6289,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
62896289
zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
62906290
}
62916291
Buf *import_code = buf_alloc();
6292-
if ((err = os_fetch_file_path(abs_full_path, import_code))) {
6292+
if ((err = os_fetch_file_path(abs_full_path, import_code, false))) {
62936293
zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
62946294
}
62956295

@@ -6377,7 +6377,7 @@ static void gen_root_source(CodeGen *g) {
63776377
}
63786378

63796379
Buf *source_code = buf_alloc();
6380-
if ((err = os_fetch_file_path(rel_full_path, source_code))) {
6380+
if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
63816381
zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
63826382
}
63836383

@@ -6442,7 +6442,7 @@ static void gen_global_asm(CodeGen *g) {
64426442
int err;
64436443
for (size_t i = 0; i < g->assembly_files.length; i += 1) {
64446444
Buf *asm_file = g->assembly_files.at(i);
6445-
if ((err = os_fetch_file_path(asm_file, &contents))) {
6445+
if ((err = os_fetch_file_path(asm_file, &contents, false))) {
64466446
zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
64476447
}
64486448
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"
@@ -227,6 +228,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
227228
enum Cmd {
228229
CmdInvalid,
229230
CmdBuild,
231+
CmdRun,
230232
CmdTest,
231233
CmdVersion,
232234
CmdZen,
@@ -336,6 +338,8 @@ int main(int argc, char **argv) {
336338
CliPkg *cur_pkg = allocate<CliPkg>(1);
337339
BuildMode build_mode = BuildModeDebug;
338340
ZigList<const char *> test_exec_args = {0};
341+
int comptime_args_end = 0;
342+
int runtime_args_start = argc;
339343

340344
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
341345
const char *zig_exe_path = arg0;
@@ -488,11 +492,15 @@ int main(int argc, char **argv) {
488492
return (term.how == TerminationIdClean) ? term.code : -1;
489493
}
490494

491-
for (int i = 1; i < argc; i += 1) {
495+
for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
492496
char *arg = argv[i];
493497

494498
if (arg[0] == '-') {
495-
if (strcmp(arg, "--release-fast") == 0) {
499+
if (strcmp(arg, "--") == 0) {
500+
// ignore -- from both compile and runtime arg sets
501+
runtime_args_start = i + 1;
502+
break;
503+
} else if (strcmp(arg, "--release-fast") == 0) {
496504
build_mode = BuildModeFastRelease;
497505
} else if (strcmp(arg, "--release-safe") == 0) {
498506
build_mode = BuildModeSafeRelease;
@@ -659,6 +667,9 @@ int main(int argc, char **argv) {
659667
} else if (strcmp(arg, "build-lib") == 0) {
660668
cmd = CmdBuild;
661669
out_type = OutTypeLib;
670+
} else if (strcmp(arg, "run") == 0) {
671+
cmd = CmdRun;
672+
out_type = OutTypeExe;
662673
} else if (strcmp(arg, "version") == 0) {
663674
cmd = CmdVersion;
664675
} else if (strcmp(arg, "zen") == 0) {
@@ -677,6 +688,7 @@ int main(int argc, char **argv) {
677688
} else {
678689
switch (cmd) {
679690
case CmdBuild:
691+
case CmdRun:
680692
case CmdTranslateC:
681693
case CmdTest:
682694
if (!in_file) {
@@ -731,16 +743,16 @@ int main(int argc, char **argv) {
731743
}
732744
}
733745

734-
735746
switch (cmd) {
747+
case CmdRun:
736748
case CmdBuild:
737749
case CmdTranslateC:
738750
case CmdTest:
739751
{
740752
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
741753
fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
742754
return usage(arg0);
743-
} else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {
755+
} else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
744756
fprintf(stderr, "Expected source file argument.\n");
745757
return usage(arg0);
746758
} else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
@@ -752,6 +764,10 @@ int main(int argc, char **argv) {
752764

753765
bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
754766

767+
if (cmd == CmdRun) {
768+
out_name = "run";
769+
}
770+
755771
Buf *in_file_buf = nullptr;
756772

757773
Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
@@ -776,9 +792,23 @@ int main(int argc, char **argv) {
776792
Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
777793

778794
Buf *full_cache_dir = buf_alloc();
779-
os_path_resolve(buf_create_from_str("."),
780-
buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
781-
full_cache_dir);
795+
Buf *run_exec_path = buf_alloc();
796+
if (cmd == CmdRun) {
797+
if (buf_out_name == nullptr) {
798+
buf_out_name = buf_create_from_str("run");
799+
}
800+
801+
Buf *global_cache_dir = buf_alloc();
802+
os_get_global_cache_directory(global_cache_dir);
803+
os_path_join(global_cache_dir, buf_out_name, run_exec_path);
804+
os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir);
805+
806+
out_file = buf_ptr(run_exec_path);
807+
} else {
808+
os_path_resolve(buf_create_from_str("."),
809+
buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
810+
full_cache_dir);
811+
}
782812

783813
Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
784814

@@ -862,7 +892,7 @@ int main(int argc, char **argv) {
862892

863893
add_package(g, cur_pkg, g->root_package);
864894

865-
if (cmd == CmdBuild) {
895+
if (cmd == CmdBuild || cmd == CmdRun) {
866896
codegen_set_emit_file_type(g, emit_file_type);
867897

868898
for (size_t i = 0; i < objects.length; i += 1) {
@@ -875,6 +905,18 @@ int main(int argc, char **argv) {
875905
codegen_link(g, out_file);
876906
if (timing_info)
877907
codegen_print_timing_report(g, stdout);
908+
909+
if (cmd == CmdRun) {
910+
ZigList<const char*> args = {0};
911+
for (int i = runtime_args_start; i < argc; ++i) {
912+
args.append(argv[i]);
913+
}
914+
915+
Termination term;
916+
os_spawn_process(buf_ptr(run_exec_path), args, &term);
917+
return term.code;
918+
}
919+
878920
return EXIT_SUCCESS;
879921
} else if (cmd == CmdTranslateC) {
880922
codegen_translate_c(g, in_file_buf);

src/os.cpp

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

294-
int os_fetch_file(FILE *f, Buf *out_buf) {
294+
int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
295295
static const ssize_t buf_size = 0x2000;
296296
buf_resize(out_buf, buf_size);
297297
ssize_t actual_buf_len = 0;
298+
299+
bool first_read = true;
300+
298301
for (;;) {
299302
size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
300303
actual_buf_len += amt_read;
304+
305+
if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) {
306+
size_t i = 0;
307+
while (true) {
308+
if (i > buf_len(out_buf)) {
309+
zig_panic("shebang line exceeded %zd characters", buf_size);
310+
}
311+
312+
size_t current_pos = i;
313+
i += 1;
314+
315+
if (out_buf->list.at(current_pos) == '\n') {
316+
break;
317+
}
318+
}
319+
320+
ZigList<char> *list = &out_buf->list;
321+
memmove(list->items, list->items + i, list->length - i);
322+
list->length -= i;
323+
324+
actual_buf_len -= i;
325+
}
326+
301327
if (amt_read != buf_size) {
302328
if (feof(f)) {
303329
buf_resize(out_buf, actual_buf_len);
@@ -308,6 +334,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
308334
}
309335

310336
buf_resize(out_buf, actual_buf_len + buf_size);
337+
first_read = false;
311338
}
312339
zig_unreachable();
313340
}
@@ -377,8 +404,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
377404

378405
FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
379406
FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
380-
os_fetch_file(stdout_f, out_stdout);
381-
os_fetch_file(stderr_f, out_stderr);
407+
os_fetch_file(stdout_f, out_stdout, false);
408+
os_fetch_file(stderr_f, out_stderr, false);
382409

383410
fclose(stdout_f);
384411
fclose(stderr_f);
@@ -591,7 +618,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
591618
}
592619
}
593620

594-
int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
621+
int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
595622
FILE *f = fopen(buf_ptr(full_path), "rb");
596623
if (!f) {
597624
switch (errno) {
@@ -610,7 +637,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
610637
return ErrorFileSystem;
611638
}
612639
}
613-
int result = os_fetch_file(f, out_contents);
640+
int result = os_fetch_file(f, out_contents, skip_shebang);
614641
fclose(f);
615642
return result;
616643
}
@@ -783,6 +810,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
783810
#endif
784811
}
785812

813+
#if defined(ZIG_OS_POSIX)
814+
int os_get_global_cache_directory(Buf *out_tmp_path) {
815+
const char *tmp_dir = getenv("TMPDIR");
816+
if (!tmp_dir) {
817+
tmp_dir = P_tmpdir;
818+
}
819+
820+
Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
821+
Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
822+
823+
buf_resize(out_tmp_path, 0);
824+
os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
825+
826+
buf_deinit(tmp_dir_buf);
827+
buf_deinit(cache_dirname_buf);
828+
return 0;
829+
}
830+
#endif
831+
832+
#if defined(ZIG_OS_WINDOWS)
833+
int os_get_global_cache_directory(Buf *out_tmp_path) {
834+
char tmp_dir[MAX_PATH + 1];
835+
if (GetTempPath(MAX_PATH, tmp_dir) == 0) {
836+
zig_panic("GetTempPath failed");
837+
}
838+
839+
Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
840+
Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
841+
842+
buf_resize(out_tmp_path, 0);
843+
os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
844+
845+
buf_deinit(tmp_dir_buf);
846+
buf_deinit(cache_dirname_buf);
847+
return 0;
848+
}
849+
#endif
850+
786851
int os_delete_file(Buf *path) {
787852
if (remove(buf_ptr(path))) {
788853
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)