Skip to content

Commit 91955de

Browse files
committed
breaking changes to zig build API and improved caching
* in Zig build scripts, getOutputPath() is no longer a valid function to call, unless setOutputDir() was used, or within a custom make() function. Instead there is more convenient API to use which takes advantage of the caching system. Search this commit diff for `exe.run()` for an example. * Zig build by default enables caching. All build artifacts will go into zig-cache. If you want to access build artifacts in a convenient location, it is recommended to add an `install` step. Otherwise you can use the `run()` API mentioned above to execute programs directly from their location in the cache. Closes #330. `addSystemCommand` is available for programs not built with Zig build. * Please note that Zig does no cache evicting yet. You may have to manually delete zig-cache directories periodically to keep disk usage down. It's planned for this to be a simple Least Recently Used eviction system eventually. * `--output`, `--output-lib`, and `--output-h` are removed. Instead, use `--output-dir` which defaults to the current working directory. Or take advantage of `--cache on`, which will print the main output path to stdout, and the other artifacts will be in the same directory with predictable file names. `--disable-gen-h` is available when one wants to prevent .h file generation. * `@cImport` is always independently cached now. Closes #2015. It always writes the generated Zig code to disk which makes debug info and compile errors better. No more "TODO: remember C source location to display here" * Fix .d file parsing. (Fixes the MacOS CI failure) * Zig no longer creates "temporary files" other than inside a zig-cache directory. This breaks the CLI API that Godbolt uses. The suggested new invocation can be found in this commit diff, in the changes to `test/cli.zig`.
1 parent 1e634a3 commit 91955de

26 files changed

+691
-661
lines changed

build.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pub fn build(b: *Builder) !void {
2020
b.allocator,
2121
[][]const u8{ b.cache_root, "langref.html" },
2222
) catch unreachable;
23-
var docgen_cmd = b.addCommand(null, b.env_map, [][]const u8{
24-
docgen_exe.getOutputPath(),
23+
var docgen_cmd = docgen_exe.run();
24+
docgen_cmd.addArgs([][]const u8{
2525
rel_zig_exe,
2626
"doc" ++ os.path.sep_str ++ "langref.html.in",
2727
langref_out_path,

doc/langref.html.in

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7914,8 +7914,7 @@ pub fn build(b: *Builder) void {
79147914

79157915
b.default_step.dependOn(&exe.step);
79167916

7917-
const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
7918-
run_cmd.step.dependOn(&exe.step);
7917+
const run_cmd = exe.run();
79197918

79207919
const test_step = b.step("test", "Test the program");
79217920
test_step.dependOn(&run_cmd.step);

example/mix_o_files/build.zig

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ pub fn build(b: *Builder) void {
44
const obj = b.addObject("base64", "base64.zig");
55

66
const exe = b.addExecutable("test", null);
7-
exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
7+
exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
88
exe.addObject(obj);
99
exe.linkSystemLibrary("c");
1010

1111
b.default_step.dependOn(&exe.step);
1212

13-
const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
14-
run_cmd.step.dependOn(&exe.step);
13+
const run_cmd = exe.run();
1514

1615
const test_step = b.step("test", "Test the program");
1716
test_step.dependOn(&run_cmd.step);

example/shared_library/build.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ pub fn build(b: *Builder) void {
1010

1111
b.default_step.dependOn(&exe.step);
1212

13-
const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
14-
run_cmd.step.dependOn(&exe.step);
13+
const run_cmd = exe.run();
1514

1615
const test_step = b.step("test", "Test the program");
1716
test_step.dependOn(&run_cmd.step);

src/all_types.hpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,6 @@ struct RootStruct {
10871087
Buf *path; // relative to root_package->root_src_dir
10881088
ZigList<size_t> *line_offsets;
10891089
Buf *source_code;
1090-
AstNode *c_import_node;
10911090
ZigLLVMDIFile *di_file;
10921091
};
10931092

@@ -1746,13 +1745,12 @@ struct CodeGen {
17461745

17471746
Buf triple_str;
17481747
Buf global_asm;
1749-
Buf *out_h_path;
1750-
Buf *out_lib_path;
1751-
Buf artifact_dir;
17521748
Buf output_file_path;
17531749
Buf o_file_output_path;
1754-
Buf *wanted_output_file_path;
17551750
Buf *cache_dir;
1751+
// As an input parameter, mutually exclusive with enable_cache. But it gets
1752+
// populated in codegen_build_and_link.
1753+
Buf *output_dir;
17561754
Buf **libc_include_dir_list;
17571755
size_t libc_include_dir_len;
17581756

@@ -1804,7 +1802,7 @@ struct CodeGen {
18041802
bool verbose_cc;
18051803
bool error_during_imports;
18061804
bool generate_error_name_table;
1807-
bool enable_cache;
1805+
bool enable_cache; // mutually exclusive with output_dir
18081806
bool enable_time_report;
18091807
bool system_linker_hack;
18101808
bool reported_bad_link_libc_error;
@@ -1844,6 +1842,7 @@ struct CodeGen {
18441842
bool each_lib_rpath;
18451843
bool disable_pic;
18461844
bool is_dummy_so;
1845+
bool disable_gen_h;
18471846

18481847
Buf *mmacosx_version_min;
18491848
Buf *mios_version_min;

src/analyze.cpp

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,6 @@ static bool is_top_level_struct(ZigType *import) {
3535
static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, Token *token, Buf *msg) {
3636
assert(is_top_level_struct(owner));
3737
RootStruct *root_struct = owner->data.structure.root_struct;
38-
if (root_struct->c_import_node != nullptr) {
39-
// if this happens, then translate_c generated code that
40-
// failed semantic analysis, which isn't supposed to happen
41-
42-
Buf *note_path = buf_create_from_str("?.c");
43-
Buf *note_source = buf_create_from_str("TODO: remember C source location to display here ");
44-
ZigList<size_t> note_line_offsets = {0};
45-
note_line_offsets.append(0);
46-
ErrorMsg *note = err_msg_create_with_line(note_path, 0, 0,
47-
note_source, &note_line_offsets, msg);
48-
49-
err_msg_add_note(parent_msg, note);
50-
return note;
51-
}
5238

5339
ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
5440
root_struct->source_code, root_struct->line_offsets, msg);
@@ -60,17 +46,6 @@ static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType
6046
ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
6147
assert(is_top_level_struct(owner));
6248
RootStruct *root_struct = owner->data.structure.root_struct;
63-
if (root_struct->c_import_node != nullptr) {
64-
// if this happens, then translate_c generated code that
65-
// failed semantic analysis, which isn't supposed to happen
66-
ErrorMsg *err = add_node_error(g, root_struct->c_import_node,
67-
buf_sprintf("compiler bug: @cImport generated invalid zig code"));
68-
69-
add_error_note_token(g, err, owner, token, msg);
70-
71-
g->errors.append(err);
72-
return err;
73-
}
7449
ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column,
7550
root_struct->source_code, root_struct->line_offsets, msg);
7651

@@ -1300,7 +1275,7 @@ static ZigTypeId container_to_type(ContainerKind kind) {
13001275
}
13011276

13021277
// This is like get_partial_container_type except it's for the implicit root struct of files.
1303-
ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
1278+
static ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
13041279
RootStruct *root_struct)
13051280
{
13061281
ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
@@ -4503,11 +4478,11 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu
45034478
Buf *pkg_root_src_dir = &package->root_src_dir;
45044479
Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1);
45054480

4506-
assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir));
4507-
45084481
Buf namespace_name = BUF_INIT;
45094482
buf_init_from_buf(&namespace_name, &package->pkg_path);
45104483
if (source_kind == SourceKindNonRoot) {
4484+
assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir));
4485+
45114486
if (buf_len(&namespace_name) != 0) buf_append_char(&namespace_name, NAMESPACE_SEP_CHAR);
45124487
buf_append_mem(&namespace_name, buf_ptr(&noextname) + buf_len(&resolved_root_src_dir) + 1,
45134488
buf_len(&noextname) - (buf_len(&resolved_root_src_dir) + 1));

src/analyze.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size);
3131
ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type);
3232
ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
3333
AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout);
34-
ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *bare_name,
35-
RootStruct *root_struct);
3634
ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
3735
ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
3836
ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
@@ -53,6 +51,7 @@ enum SourceKind {
5351
SourceKindRoot,
5452
SourceKindPkgMain,
5553
SourceKindNonRoot,
54+
SourceKindCImport,
5655
};
5756
ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Buf *source_code,
5857
SourceKind source_kind);
@@ -242,4 +241,6 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no
242241
void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
243242
Buf *type_bare_name(ZigType *t);
244243
Buf *type_h_name(ZigType *t);
244+
Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose);
245+
245246
#endif

src/ast_render.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
470470
fprintf(ar->f, ", ");
471471
}
472472
}
473+
if (node->data.fn_proto.is_var_args) {
474+
fprintf(ar->f, ", ...");
475+
}
473476
fprintf(ar->f, ")");
474477
if (node->data.fn_proto.align_expr) {
475478
fprintf(ar->f, " align(");

src/cache_hash.cpp

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ void cache_init(CacheHash *ch, Buf *manifest_dir) {
1919
ch->manifest_dir = manifest_dir;
2020
ch->manifest_file_path = nullptr;
2121
ch->manifest_dirty = false;
22+
ch->force_check_manifest = false;
23+
ch->b64_digest = BUF_INIT;
2224
}
2325

2426
void cache_str(CacheHash *ch, const char *ptr) {
@@ -243,22 +245,21 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
243245
int rc = blake2b_final(&ch->blake, bin_digest, 48);
244246
assert(rc == 0);
245247

246-
if (ch->files.length == 0) {
248+
buf_resize(&ch->b64_digest, 64);
249+
base64_encode(buf_to_slice(&ch->b64_digest), {bin_digest, 48});
250+
251+
if (ch->files.length == 0 && !ch->force_check_manifest) {
247252
buf_resize(out_digest, 64);
248253
base64_encode(buf_to_slice(out_digest), {bin_digest, 48});
249254
return ErrorNone;
250255
}
251256

252-
Buf b64_digest = BUF_INIT;
253-
buf_resize(&b64_digest, 64);
254-
base64_encode(buf_to_slice(&b64_digest), {bin_digest, 48});
255-
256257
rc = blake2b_init(&ch->blake, 48);
257258
assert(rc == 0);
258259
blake2b_update(&ch->blake, bin_digest, 48);
259260

260261
ch->manifest_file_path = buf_alloc();
261-
os_path_join(ch->manifest_dir, &b64_digest, ch->manifest_file_path);
262+
os_path_join(ch->manifest_dir, &ch->b64_digest, ch->manifest_file_path);
262263

263264
buf_append_str(ch->manifest_file_path, ".txt");
264265

@@ -380,7 +381,7 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
380381
blake2b_update(&ch->blake, chf->bin_digest, 48);
381382
}
382383
}
383-
if (file_i < input_file_count) {
384+
if (file_i < input_file_count || file_i == 0) {
384385
// manifest file is empty or missing entries, so this is a cache miss
385386
ch->manifest_dirty = true;
386387
for (; file_i < input_file_count; file_i += 1) {
@@ -442,6 +443,7 @@ Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
442443
}
443444
if (opt_line.value.len == 0)
444445
continue;
446+
445447
if (opt_line.value.ptr[0] == '"') {
446448
if (opt_line.value.len < 2) {
447449
if (verbose) {
@@ -460,21 +462,28 @@ Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
460462
}
461463
return ErrorInvalidDepFile;
462464
}
463-
} else {
464-
if (opt_line.value.ptr[opt_line.value.len - 1] == '\\') {
465-
opt_line.value.len -= 2; // cut off ` \`
465+
Buf *filename_buf = buf_create_from_slice(opt_line.value);
466+
if ((err = cache_add_file(ch, filename_buf))) {
467+
if (verbose) {
468+
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
469+
fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
470+
}
471+
return err;
466472
}
467-
if (opt_line.value.len == 0)
468-
continue;
469-
}
470-
471-
Buf *filename_buf = buf_create_from_slice(opt_line.value);
472-
if ((err = cache_add_file(ch, filename_buf))) {
473-
if (verbose) {
474-
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
475-
fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
473+
} else {
474+
// sometimes there are multiple files on the same line; we actually need space tokenization.
475+
SplitIterator line_it = memSplit(opt_line.value, str(" \t\\"));
476+
Slice<uint8_t> filename;
477+
while (SplitIterator_next(&line_it).unwrap(&filename)) {
478+
Buf *filename_buf = buf_create_from_slice(filename);
479+
if ((err = cache_add_file(ch, filename_buf))) {
480+
if (verbose) {
481+
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
482+
fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
483+
}
484+
return err;
485+
}
476486
}
477-
return err;
478487
}
479488
}
480489
return ErrorNone;

src/cache_hash.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ struct CacheHash {
2525
ZigList<CacheHashFile> files;
2626
Buf *manifest_dir;
2727
Buf *manifest_file_path;
28+
Buf b64_digest;
2829
OsFile manifest_file;
2930
bool manifest_dirty;
31+
bool force_check_manifest;
3032
};
3133

3234
// Always call this first to set up.
@@ -51,6 +53,10 @@ void cache_file_opt(CacheHash *ch, Buf *path);
5153
// If you got a cache hit, the next step is cache_release.
5254
// From this point on, there is a lock on the input params. Release
5355
// the lock with cache_release.
56+
// Set force_check_manifest if you plan to add files later, but have not
57+
// added any files before calling cache_hit. CacheHash::b64_digest becomes
58+
// available for use after this call, even in the case of a miss, and it
59+
// is a hash of the input parameters only.
5460
Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
5561

5662
// If you did not get a cache hit, call this function for every file

0 commit comments

Comments
 (0)