| ... | ... | @@ -22,6 +22,7 @@ const fatal = @import("main.zig").fatal; |
| 22 | 22 | const Module = @import("Module.zig"); |
| 23 | 23 | const Cache = @import("Cache.zig"); |
| 24 | 24 | const stage1 = @import("stage1.zig"); |
| 25 | const translate_c = @import("translate_c.zig"); |
| 25 | 26 | |
| 26 | 27 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 27 | 28 | gpa: *Allocator, |
| ... | ... | @@ -30,7 +31,7 @@ arena_state: std.heap.ArenaAllocator.State, |
| 30 | 31 | bin_file: *link.File, |
| 31 | 32 | c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, |
| 32 | 33 | stage1_lock: ?Cache.Lock = null, |
| 33 | | stage1_cache_hash: *Cache.CacheHash = undefined, |
| 34 | stage1_cache_manifest: *Cache.Manifest = undefined, |
| 34 | 35 | |
| 35 | 36 | link_error_flags: link.File.ErrorFlags = .{}, |
| 36 | 37 | |
| ... | ... | @@ -1198,29 +1199,182 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void { |
| 1198 | 1199 | }; |
| 1199 | 1200 | } |
| 1200 | 1201 | |
| 1201 | | fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1202 | fn obtainCObjectCacheManifest(comp: *Compilation) Cache.Manifest { |
| 1203 | var man = comp.cache_parent.obtain(); |
| 1204 | |
| 1205 | // Only things that need to be added on top of the base hash, and only things |
| 1206 | // that apply both to @cImport and compiling C objects. No linking stuff here! |
| 1207 | // Also nothing that applies only to compiling .zig code. |
| 1208 | |
| 1209 | man.hash.add(comp.sanitize_c); |
| 1210 | man.hash.addListOfBytes(comp.clang_argv); |
| 1211 | man.hash.add(comp.bin_file.options.link_libcpp); |
| 1212 | man.hash.addListOfBytes(comp.libc_include_dir_list); |
| 1213 | |
| 1214 | return man; |
| 1215 | } |
| 1216 | |
| 1217 | test "cImport" { |
| 1218 | _ = cImport; |
| 1219 | } |
| 1220 | |
| 1221 | const CImportResult = struct { |
| 1222 | out_zig_path: []u8, |
| 1223 | errors: []translate_c.ClangErrMsg, |
| 1224 | }; |
| 1225 | |
| 1226 | /// Caller owns returned memory. |
| 1227 | /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked |
| 1228 | /// a bit when we want to start using it from self-hosted. |
| 1229 | pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { |
| 1230 | if (!build_options.have_llvm) |
| 1231 | return error.ZigCompilerNotBuiltWithLLVMExtensions; |
| 1232 | |
| 1202 | 1233 | const tracy = trace(@src()); |
| 1203 | 1234 | defer tracy.end(); |
| 1204 | 1235 | |
| 1236 | const cimport_zig_basename = "cimport.zig"; |
| 1237 | |
| 1238 | var man = comp.obtainCObjectCacheManifest(); |
| 1239 | defer man.deinit(); |
| 1240 | |
| 1241 | man.hash.addBytes(c_src); |
| 1242 | |
| 1243 | // If the previous invocation resulted in clang errors, we will see a hit |
| 1244 | // here with 0 files in the manifest, in which case it is actually a miss. |
| 1245 | const actual_hit = (try man.hit()) and man.files.items.len != 0; |
| 1246 | const digest = if (!actual_hit) digest: { |
| 1247 | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); |
| 1248 | defer arena_allocator.deinit(); |
| 1249 | const arena = &arena_allocator.allocator; |
| 1250 | |
| 1251 | // We need a place to leave the .h file so we can can log it in case of verbose_cimport. |
| 1252 | // This block is so that the defers for closing the tmp directory handle can run before |
| 1253 | // we try to delete the directory after the block. |
| 1254 | const result: struct { tmp_dir_sub_path: []const u8, digest: [Cache.hex_digest_len]u8 } = blk: { |
| 1255 | const tmp_digest = man.hash.peek(); |
| 1256 | const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest }); |
| 1257 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{}); |
| 1258 | defer zig_cache_tmp_dir.close(); |
| 1259 | const cimport_c_basename = "cimport.c"; |
| 1260 | const out_h_path = try comp.local_cache_directory.join(arena, &[_][]const u8{ |
| 1261 | tmp_dir_sub_path, cimport_c_basename, |
| 1262 | }); |
| 1263 | const out_dep_path = try std.fmt.allocPrint(arena, "{}.d", .{out_h_path}); |
| 1264 | |
| 1265 | try zig_cache_tmp_dir.writeFile(cimport_c_basename, c_src); |
| 1266 | if (comp.verbose_cimport) { |
| 1267 | log.info("C import source: {}", .{out_h_path}); |
| 1268 | } |
| 1269 | |
| 1270 | var argv = std.ArrayList([]const u8).init(comp.gpa); |
| 1271 | defer argv.deinit(); |
| 1272 | |
| 1273 | try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path); |
| 1274 | |
| 1275 | try argv.append(out_h_path); |
| 1276 | |
| 1277 | if (comp.verbose_cc) { |
| 1278 | dump_argv(argv.items); |
| 1279 | } |
| 1280 | |
| 1281 | // Convert to null terminated args. |
| 1282 | const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1); |
| 1283 | new_argv_with_sentinel[argv.items.len] = null; |
| 1284 | const new_argv = new_argv_with_sentinel[0..argv.items.len :null]; |
| 1285 | for (argv.items) |arg, i| { |
| 1286 | new_argv[i] = try arena.dupeZ(u8, arg); |
| 1287 | } |
| 1288 | |
| 1289 | const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); |
| 1290 | const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); |
| 1291 | var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; |
| 1292 | const tree = translate_c.translate( |
| 1293 | comp.gpa, |
| 1294 | new_argv.ptr, |
| 1295 | new_argv.ptr + new_argv.len, |
| 1296 | &clang_errors, |
| 1297 | c_headers_dir_path_z, |
| 1298 | ) catch |err| switch (err) { |
| 1299 | error.OutOfMemory => return error.OutOfMemory, |
| 1300 | error.ASTUnitFailure => { |
| 1301 | log.warn("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}); |
| 1302 | return error.ASTUnitFailure; |
| 1303 | }, |
| 1304 | error.SemanticAnalyzeFail => { |
| 1305 | return CImportResult{ |
| 1306 | .out_zig_path = "", |
| 1307 | .errors = clang_errors, |
| 1308 | }; |
| 1309 | }, |
| 1310 | }; |
| 1311 | defer tree.deinit(); |
| 1312 | |
| 1313 | if (comp.verbose_cimport) { |
| 1314 | log.info("C import .d file: {}", .{out_dep_path}); |
| 1315 | } |
| 1316 | |
| 1317 | const dep_basename = std.fs.path.basename(out_dep_path); |
| 1318 | try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 1319 | |
| 1320 | const digest = man.final(); |
| 1321 | const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); |
| 1322 | var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); |
| 1323 | defer o_dir.close(); |
| 1324 | |
| 1325 | var out_zig_file = try o_dir.createFile(cimport_zig_basename, .{}); |
| 1326 | defer out_zig_file.close(); |
| 1327 | |
| 1328 | var bos = std.io.bufferedOutStream(out_zig_file.writer()); |
| 1329 | _ = try std.zig.render(comp.gpa, bos.writer(), tree); |
| 1330 | try bos.flush(); |
| 1331 | |
| 1332 | man.writeManifest() catch |err| { |
| 1333 | log.warn("failed to write cache manifest for C import: {}", .{@errorName(err)}); |
| 1334 | }; |
| 1335 | |
| 1336 | break :blk .{ .tmp_dir_sub_path = tmp_dir_sub_path, .digest = digest }; |
| 1337 | }; |
| 1338 | if (!comp.verbose_cimport) { |
| 1339 | // Remove the tmp dir and files to save space because we don't need them again. |
| 1340 | comp.local_cache_directory.handle.deleteTree(result.tmp_dir_sub_path) catch |err| { |
| 1341 | log.warn("failed to delete tmp files for C import: {}", .{@errorName(err)}); |
| 1342 | }; |
| 1343 | } |
| 1344 | break :digest result.digest; |
| 1345 | } else man.final(); |
| 1346 | |
| 1347 | const out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ |
| 1348 | "o", &digest, cimport_zig_basename, |
| 1349 | }); |
| 1350 | if (comp.verbose_cimport) { |
| 1351 | log.info("C import output: {}\n", .{out_zig_path}); |
| 1352 | } |
| 1353 | return CImportResult{ |
| 1354 | .out_zig_path = out_zig_path, |
| 1355 | .errors = &[0]translate_c.ClangErrMsg{}, |
| 1356 | }; |
| 1357 | } |
| 1358 | |
| 1359 | fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1205 | 1360 | if (!build_options.have_llvm) { |
| 1206 | 1361 | return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); |
| 1207 | 1362 | } |
| 1208 | 1363 | const self_exe_path = comp.self_exe_path orelse |
| 1209 | 1364 | return comp.failCObj(c_object, "clang compilation disabled", .{}); |
| 1210 | 1365 | |
| 1366 | const tracy = trace(@src()); |
| 1367 | defer tracy.end(); |
| 1368 | |
| 1211 | 1369 | if (c_object.clearStatus(comp.gpa)) { |
| 1212 | 1370 | // There was previous failure. |
| 1213 | 1371 | comp.failed_c_objects.removeAssertDiscard(c_object); |
| 1214 | 1372 | } |
| 1215 | 1373 | |
| 1216 | | var ch = comp.cache_parent.obtain(); |
| 1217 | | defer ch.deinit(); |
| 1374 | var man = comp.obtainCObjectCacheManifest(); |
| 1375 | defer man.deinit(); |
| 1218 | 1376 | |
| 1219 | | ch.hash.add(comp.sanitize_c); |
| 1220 | | ch.hash.addListOfBytes(comp.clang_argv); |
| 1221 | | ch.hash.add(comp.bin_file.options.link_libcpp); |
| 1222 | | ch.hash.addListOfBytes(comp.libc_include_dir_list); |
| 1223 | | _ = try ch.addFile(c_object.src.src_path, null); |
| 1377 | _ = try man.addFile(c_object.src.src_path, null); |
| 1224 | 1378 | { |
| 1225 | 1379 | // Hash the extra flags, with special care to call addFile for file parameters. |
| 1226 | 1380 | // TODO this logic can likely be improved by utilizing clang_options_data.zig. |
| ... | ... | @@ -1228,11 +1382,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1228 | 1382 | var arg_i: usize = 0; |
| 1229 | 1383 | while (arg_i < c_object.src.extra_flags.len) : (arg_i += 1) { |
| 1230 | 1384 | const arg = c_object.src.extra_flags[arg_i]; |
| 1231 | | ch.hash.addBytes(arg); |
| 1385 | man.hash.addBytes(arg); |
| 1232 | 1386 | for (file_args) |file_arg| { |
| 1233 | 1387 | if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_object.src.extra_flags.len) { |
| 1234 | 1388 | arg_i += 1; |
| 1235 | | _ = try ch.addFile(c_object.src.extra_flags[arg_i], null); |
| 1389 | _ = try man.addFile(c_object.src.extra_flags[arg_i], null); |
| 1236 | 1390 | } |
| 1237 | 1391 | } |
| 1238 | 1392 | } |
| ... | ... | @@ -1254,7 +1408,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1254 | 1408 | mem.split(c_source_basename, ".").next().?; |
| 1255 | 1409 | const o_basename = try std.fmt.allocPrint(arena, "{}{}", .{ o_basename_noext, comp.getTarget().oFileExt() }); |
| 1256 | 1410 | |
| 1257 | | const digest = if ((try ch.hit()) and !comp.disable_c_depfile) ch.final() else blk: { |
| 1411 | const digest = if ((try man.hit()) and !comp.disable_c_depfile) man.final() else blk: { |
| 1258 | 1412 | var argv = std.ArrayList([]const u8).init(comp.gpa); |
| 1259 | 1413 | defer argv.deinit(); |
| 1260 | 1414 | |
| ... | ... | @@ -1270,7 +1424,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1270 | 1424 | null |
| 1271 | 1425 | else |
| 1272 | 1426 | try std.fmt.allocPrint(arena, "{}.d", .{out_obj_path}); |
| 1273 | | try comp.addCCArgs(arena, &argv, ext, false, out_dep_path); |
| 1427 | try comp.addCCArgs(arena, &argv, ext, out_dep_path); |
| 1274 | 1428 | |
| 1275 | 1429 | try argv.append("-o"); |
| 1276 | 1430 | try argv.append(out_obj_path); |
| ... | ... | @@ -1325,12 +1479,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1325 | 1479 | if (code != 0) { |
| 1326 | 1480 | // TODO parse clang stderr and turn it into an error message |
| 1327 | 1481 | // and then call failCObjWithOwnedErrorMsg |
| 1328 | | std.log.err("clang failed with stderr: {}", .{stderr}); |
| 1482 | log.err("clang failed with stderr: {}", .{stderr}); |
| 1329 | 1483 | return comp.failCObj(c_object, "clang exited with code {}", .{code}); |
| 1330 | 1484 | } |
| 1331 | 1485 | }, |
| 1332 | 1486 | else => { |
| 1333 | | std.log.err("clang terminated with stderr: {}", .{stderr}); |
| 1487 | log.err("clang terminated with stderr: {}", .{stderr}); |
| 1334 | 1488 | return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); |
| 1335 | 1489 | }, |
| 1336 | 1490 | } |
| ... | ... | @@ -1339,15 +1493,15 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1339 | 1493 | if (out_dep_path) |dep_file_path| { |
| 1340 | 1494 | const dep_basename = std.fs.path.basename(dep_file_path); |
| 1341 | 1495 | // Add the files depended on to the cache system. |
| 1342 | | try ch.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 1496 | try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); |
| 1343 | 1497 | // Just to save disk space, we delete the file because it is never needed again. |
| 1344 | 1498 | zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| { |
| 1345 | | std.log.warn("failed to delete '{}': {}", .{ dep_file_path, @errorName(err) }); |
| 1499 | log.warn("failed to delete '{}': {}", .{ dep_file_path, @errorName(err) }); |
| 1346 | 1500 | }; |
| 1347 | 1501 | } |
| 1348 | 1502 | |
| 1349 | 1503 | // Rename into place. |
| 1350 | | const digest = ch.final(); |
| 1504 | const digest = man.final(); |
| 1351 | 1505 | const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); |
| 1352 | 1506 | var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); |
| 1353 | 1507 | defer o_dir.close(); |
| ... | ... | @@ -1355,8 +1509,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1355 | 1509 | const tmp_basename = std.fs.path.basename(out_obj_path); |
| 1356 | 1510 | try std.os.renameat(zig_cache_tmp_dir.fd, tmp_basename, o_dir.fd, o_basename); |
| 1357 | 1511 | |
| 1358 | | ch.writeManifest() catch |err| { |
| 1359 | | std.log.warn("failed to write cache manifest when compiling '{}': {}", .{ c_object.src.src_path, @errorName(err) }); |
| 1512 | man.writeManifest() catch |err| { |
| 1513 | log.warn("failed to write cache manifest when compiling '{}': {}", .{ c_object.src.src_path, @errorName(err) }); |
| 1360 | 1514 | }; |
| 1361 | 1515 | break :blk digest; |
| 1362 | 1516 | }; |
| ... | ... | @@ -1369,7 +1523,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1369 | 1523 | c_object.status = .{ |
| 1370 | 1524 | .success = .{ |
| 1371 | 1525 | .object_path = try std.fs.path.join(comp.gpa, components), |
| 1372 | | .lock = ch.toOwnedLock(), |
| 1526 | .lock = man.toOwnedLock(), |
| 1373 | 1527 | }, |
| 1374 | 1528 | }; |
| 1375 | 1529 | } |
| ... | ... | @@ -1384,21 +1538,28 @@ fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{ |
| 1384 | 1538 | } |
| 1385 | 1539 | } |
| 1386 | 1540 | |
| 1541 | pub fn addTranslateCCArgs( |
| 1542 | comp: *Compilation, |
| 1543 | arena: *Allocator, |
| 1544 | argv: *std.ArrayList([]const u8), |
| 1545 | ext: FileExt, |
| 1546 | out_dep_path: ?[]const u8, |
| 1547 | ) !void { |
| 1548 | try comp.addCCArgs(arena, argv, ext, out_dep_path); |
| 1549 | // This gives us access to preprocessing entities, presumably at the cost of performance. |
| 1550 | try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" }); |
| 1551 | } |
| 1552 | |
| 1387 | 1553 | /// Add common C compiler args between translate-c and C object compilation. |
| 1388 | 1554 | pub fn addCCArgs( |
| 1389 | 1555 | comp: *Compilation, |
| 1390 | 1556 | arena: *Allocator, |
| 1391 | 1557 | argv: *std.ArrayList([]const u8), |
| 1392 | 1558 | ext: FileExt, |
| 1393 | | translate_c: bool, |
| 1394 | 1559 | out_dep_path: ?[]const u8, |
| 1395 | 1560 | ) !void { |
| 1396 | 1561 | const target = comp.getTarget(); |
| 1397 | 1562 | |
| 1398 | | if (translate_c) { |
| 1399 | | try argv.appendSlice(&[_][]const u8{ "-x", "c" }); |
| 1400 | | } |
| 1401 | | |
| 1402 | 1563 | if (ext == .cpp) { |
| 1403 | 1564 | try argv.append("-nostdinc++"); |
| 1404 | 1565 | } |
| ... | ... | @@ -1488,11 +1649,6 @@ pub fn addCCArgs( |
| 1488 | 1649 | if (mcmodel != .default) { |
| 1489 | 1650 | try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={}", .{@tagName(mcmodel)})); |
| 1490 | 1651 | } |
| 1491 | | if (translate_c) { |
| 1492 | | // This gives us access to preprocessing entities, presumably at the cost of performance. |
| 1493 | | try argv.append("-Xclang"); |
| 1494 | | try argv.append("-detailed-preprocessing-record"); |
| 1495 | | } |
| 1496 | 1652 | |
| 1497 | 1653 | // windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning. |
| 1498 | 1654 | // So for this target, we disable this warning. |
| ... | ... | @@ -2118,7 +2274,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void { |
| 2118 | 2274 | |
| 2119 | 2275 | if (errors.list.len != 0) { |
| 2120 | 2276 | for (errors.list) |full_err_msg| { |
| 2121 | | std.log.err("{}:{}:{}: {}\n", .{ |
| 2277 | log.err("{}:{}:{}: {}\n", .{ |
| 2122 | 2278 | full_err_msg.src_path, |
| 2123 | 2279 | full_err_msg.line + 1, |
| 2124 | 2280 | full_err_msg.column + 1, |
| ... | ... | @@ -2231,23 +2387,23 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2231 | 2387 | // the artifact directory the same, however, so we take the same strategy as linking |
| 2232 | 2388 | // does where we have a file which specifies the hash of the output directory so that we can |
| 2233 | 2389 | // skip the expensive compilation step if the hash matches. |
| 2234 | | var ch = comp.cache_parent.obtain(); |
| 2235 | | defer ch.deinit(); |
| 2390 | var man = comp.cache_parent.obtain(); |
| 2391 | defer man.deinit(); |
| 2236 | 2392 | |
| 2237 | | _ = try ch.addFile(main_zig_file, null); |
| 2238 | | ch.hash.add(comp.bin_file.options.valgrind); |
| 2239 | | ch.hash.add(comp.bin_file.options.single_threaded); |
| 2240 | | ch.hash.add(target.os.getVersionRange()); |
| 2241 | | ch.hash.add(comp.bin_file.options.dll_export_fns); |
| 2242 | | ch.hash.add(comp.bin_file.options.function_sections); |
| 2243 | | ch.hash.add(comp.is_test); |
| 2393 | _ = try man.addFile(main_zig_file, null); |
| 2394 | man.hash.add(comp.bin_file.options.valgrind); |
| 2395 | man.hash.add(comp.bin_file.options.single_threaded); |
| 2396 | man.hash.add(target.os.getVersionRange()); |
| 2397 | man.hash.add(comp.bin_file.options.dll_export_fns); |
| 2398 | man.hash.add(comp.bin_file.options.function_sections); |
| 2399 | man.hash.add(comp.is_test); |
| 2244 | 2400 | |
| 2245 | 2401 | // Capture the state in case we come back from this branch where the hash doesn't match. |
| 2246 | | const prev_hash_state = ch.hash.peekBin(); |
| 2247 | | const input_file_count = ch.files.items.len; |
| 2402 | const prev_hash_state = man.hash.peekBin(); |
| 2403 | const input_file_count = man.files.items.len; |
| 2248 | 2404 | |
| 2249 | | if (try ch.hit()) { |
| 2250 | | const digest = ch.final(); |
| 2405 | if (try man.hit()) { |
| 2406 | const digest = man.final(); |
| 2251 | 2407 | |
| 2252 | 2408 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 2253 | 2409 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { |
| ... | ... | @@ -2257,11 +2413,11 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2257 | 2413 | }; |
| 2258 | 2414 | if (mem.eql(u8, prev_digest, &digest)) { |
| 2259 | 2415 | log.debug("stage1 {} digest={} match - skipping invocation", .{ mod.root_pkg.root_src_path, digest }); |
| 2260 | | comp.stage1_lock = ch.toOwnedLock(); |
| 2416 | comp.stage1_lock = man.toOwnedLock(); |
| 2261 | 2417 | return; |
| 2262 | 2418 | } |
| 2263 | 2419 | log.debug("stage1 {} prev_digest={} new_digest={}", .{ mod.root_pkg.root_src_path, prev_digest, digest }); |
| 2264 | | ch.unhit(prev_hash_state, input_file_count); |
| 2420 | man.unhit(prev_hash_state, input_file_count); |
| 2265 | 2421 | } |
| 2266 | 2422 | |
| 2267 | 2423 | // We are about to change the output file to be different, so we invalidate the build hash now. |
| ... | ... | @@ -2285,7 +2441,7 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2285 | 2441 | defer main_progress_node.end(); |
| 2286 | 2442 | if (comp.color == .Off) progress.terminal = null; |
| 2287 | 2443 | |
| 2288 | | comp.stage1_cache_hash = &ch; |
| 2444 | comp.stage1_cache_manifest = &man; |
| 2289 | 2445 | |
| 2290 | 2446 | const main_pkg_path = mod.root_pkg.root_src_directory.path orelse ""; |
| 2291 | 2447 | |
| ... | ... | @@ -2350,22 +2506,22 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2350 | 2506 | stage1_module.build_object(); |
| 2351 | 2507 | stage1_module.destroy(); |
| 2352 | 2508 | |
| 2353 | | const digest = ch.final(); |
| 2509 | const digest = man.final(); |
| 2354 | 2510 | |
| 2355 | 2511 | log.debug("stage1 {} final digest={}", .{ mod.root_pkg.root_src_path, digest }); |
| 2356 | 2512 | |
| 2357 | 2513 | // Update the dangling symlink with the digest. If it fails we can continue; it only |
| 2358 | 2514 | // means that the next invocation will have an unnecessary cache miss. |
| 2359 | 2515 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { |
| 2360 | | std.log.warn("failed to save stage1 hash digest symlink: {}", .{@errorName(err)}); |
| 2516 | log.warn("failed to save stage1 hash digest symlink: {}", .{@errorName(err)}); |
| 2361 | 2517 | }; |
| 2362 | 2518 | // Again failure here only means an unnecessary cache miss. |
| 2363 | | ch.writeManifest() catch |err| { |
| 2364 | | std.log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)}); |
| 2519 | man.writeManifest() catch |err| { |
| 2520 | log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)}); |
| 2365 | 2521 | }; |
| 2366 | 2522 | // We hang on to this lock so that the output file path can be used without |
| 2367 | 2523 | // other processes clobbering it. |
| 2368 | | comp.stage1_lock = ch.toOwnedLock(); |
| 2524 | comp.stage1_lock = man.toOwnedLock(); |
| 2369 | 2525 | } |
| 2370 | 2526 | |
| 2371 | 2527 | fn createStage1Pkg( |