| ... | @@ -22,6 +22,7 @@ const fatal = @import("main.zig").fatal; | ... | @@ -22,6 +22,7 @@ const fatal = @import("main.zig").fatal; |
| 22 | const Module = @import("Module.zig"); | 22 | const Module = @import("Module.zig"); |
| 23 | const Cache = @import("Cache.zig"); | 23 | const Cache = @import("Cache.zig"); |
| 24 | const stage1 = @import("stage1.zig"); | 24 | const stage1 = @import("stage1.zig"); |
| | 25 | const translate_c = @import("translate_c.zig"); |
| 25 | | 26 | |
| 26 | /// General-purpose allocator. Used for both temporary and long-term storage. | 27 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 27 | gpa: *Allocator, | 28 | gpa: *Allocator, |
| ... | @@ -30,7 +31,7 @@ arena_state: std.heap.ArenaAllocator.State, | ... | @@ -30,7 +31,7 @@ arena_state: std.heap.ArenaAllocator.State, |
| 30 | bin_file: *link.File, | 31 | bin_file: *link.File, |
| 31 | c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, | 32 | c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, |
| 32 | stage1_lock: ?Cache.Lock = null, | 33 | stage1_lock: ?Cache.Lock = null, |
| 33 | stage1_cache_hash: *Cache.CacheHash = undefined, | 34 | stage1_cache_manifest: *Cache.Manifest = undefined, |
| 34 | | 35 | |
| 35 | link_error_flags: link.File.ErrorFlags = .{}, | 36 | link_error_flags: link.File.ErrorFlags = .{}, |
| 36 | | 37 | |
| ... | @@ -1198,29 +1199,182 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void { | ... | @@ -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 | const tracy = trace(@src()); | 1233 | const tracy = trace(@src()); |
| 1203 | defer tracy.end(); | 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 | if (!build_options.have_llvm) { | 1360 | if (!build_options.have_llvm) { |
| 1206 | return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); | 1361 | return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); |
| 1207 | } | 1362 | } |
| 1208 | const self_exe_path = comp.self_exe_path orelse | 1363 | const self_exe_path = comp.self_exe_path orelse |
| 1209 | return comp.failCObj(c_object, "clang compilation disabled", .{}); | 1364 | return comp.failCObj(c_object, "clang compilation disabled", .{}); |
| 1210 | | 1365 | |
| | 1366 | const tracy = trace(@src()); |
| | 1367 | defer tracy.end(); |
| | 1368 | |
| 1211 | if (c_object.clearStatus(comp.gpa)) { | 1369 | if (c_object.clearStatus(comp.gpa)) { |
| 1212 | // There was previous failure. | 1370 | // There was previous failure. |
| 1213 | comp.failed_c_objects.removeAssertDiscard(c_object); | 1371 | comp.failed_c_objects.removeAssertDiscard(c_object); |
| 1214 | } | 1372 | } |
| 1215 | | 1373 | |
| 1216 | var ch = comp.cache_parent.obtain(); | 1374 | var man = comp.obtainCObjectCacheManifest(); |
| 1217 | defer ch.deinit(); | 1375 | defer man.deinit(); |
| 1218 | | 1376 | |
| 1219 | ch.hash.add(comp.sanitize_c); | 1377 | _ = try man.addFile(c_object.src.src_path, null); |
| 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); | | |
| 1224 | { | 1378 | { |
| 1225 | // Hash the extra flags, with special care to call addFile for file parameters. | 1379 | // Hash the extra flags, with special care to call addFile for file parameters. |
| 1226 | // TODO this logic can likely be improved by utilizing clang_options_data.zig. | 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,11 +1382,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1228 | var arg_i: usize = 0; | 1382 | var arg_i: usize = 0; |
| 1229 | while (arg_i < c_object.src.extra_flags.len) : (arg_i += 1) { | 1383 | while (arg_i < c_object.src.extra_flags.len) : (arg_i += 1) { |
| 1230 | const arg = c_object.src.extra_flags[arg_i]; | 1384 | const arg = c_object.src.extra_flags[arg_i]; |
| 1231 | ch.hash.addBytes(arg); | 1385 | man.hash.addBytes(arg); |
| 1232 | for (file_args) |file_arg| { | 1386 | for (file_args) |file_arg| { |
| 1233 | if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_object.src.extra_flags.len) { | 1387 | if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_object.src.extra_flags.len) { |
| 1234 | arg_i += 1; | 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,7 +1408,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1254 | mem.split(c_source_basename, ".").next().?; | 1408 | mem.split(c_source_basename, ".").next().?; |
| 1255 | const o_basename = try std.fmt.allocPrint(arena, "{}{}", .{ o_basename_noext, comp.getTarget().oFileExt() }); | 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 | var argv = std.ArrayList([]const u8).init(comp.gpa); | 1412 | var argv = std.ArrayList([]const u8).init(comp.gpa); |
| 1259 | defer argv.deinit(); | 1413 | defer argv.deinit(); |
| 1260 | | 1414 | |
| ... | @@ -1270,7 +1424,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1270,7 +1424,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1270 | null | 1424 | null |
| 1271 | else | 1425 | else |
| 1272 | try std.fmt.allocPrint(arena, "{}.d", .{out_obj_path}); | 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 | try argv.append("-o"); | 1429 | try argv.append("-o"); |
| 1276 | try argv.append(out_obj_path); | 1430 | try argv.append(out_obj_path); |
| ... | @@ -1325,12 +1479,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1325,12 +1479,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1325 | if (code != 0) { | 1479 | if (code != 0) { |
| 1326 | // TODO parse clang stderr and turn it into an error message | 1480 | // TODO parse clang stderr and turn it into an error message |
| 1327 | // and then call failCObjWithOwnedErrorMsg | 1481 | // and then call failCObjWithOwnedErrorMsg |
| 1328 | std.log.err("clang failed with stderr: {}", .{stderr}); | 1482 | log.err("clang failed with stderr: {}", .{stderr}); |
| 1329 | return comp.failCObj(c_object, "clang exited with code {}", .{code}); | 1483 | return comp.failCObj(c_object, "clang exited with code {}", .{code}); |
| 1330 | } | 1484 | } |
| 1331 | }, | 1485 | }, |
| 1332 | else => { | 1486 | else => { |
| 1333 | std.log.err("clang terminated with stderr: {}", .{stderr}); | 1487 | log.err("clang terminated with stderr: {}", .{stderr}); |
| 1334 | return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); | 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,15 +1493,15 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1339 | if (out_dep_path) |dep_file_path| { | 1493 | if (out_dep_path) |dep_file_path| { |
| 1340 | const dep_basename = std.fs.path.basename(dep_file_path); | 1494 | const dep_basename = std.fs.path.basename(dep_file_path); |
| 1341 | // Add the files depended on to the cache system. | 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 | // Just to save disk space, we delete the file because it is never needed again. | 1497 | // Just to save disk space, we delete the file because it is never needed again. |
| 1344 | zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| { | 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 | // Rename into place. | 1503 | // Rename into place. |
| 1350 | const digest = ch.final(); | 1504 | const digest = man.final(); |
| 1351 | const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); | 1505 | const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); |
| 1352 | var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); | 1506 | var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); |
| 1353 | defer o_dir.close(); | 1507 | defer o_dir.close(); |
| ... | @@ -1355,8 +1509,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1355,8 +1509,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1355 | const tmp_basename = std.fs.path.basename(out_obj_path); | 1509 | const tmp_basename = std.fs.path.basename(out_obj_path); |
| 1356 | try std.os.renameat(zig_cache_tmp_dir.fd, tmp_basename, o_dir.fd, o_basename); | 1510 | try std.os.renameat(zig_cache_tmp_dir.fd, tmp_basename, o_dir.fd, o_basename); |
| 1357 | | 1511 | |
| 1358 | ch.writeManifest() catch |err| { | 1512 | man.writeManifest() catch |err| { |
| 1359 | std.log.warn("failed to write cache manifest when compiling '{}': {}", .{ c_object.src.src_path, @errorName(err) }); | 1513 | log.warn("failed to write cache manifest when compiling '{}': {}", .{ c_object.src.src_path, @errorName(err) }); |
| 1360 | }; | 1514 | }; |
| 1361 | break :blk digest; | 1515 | break :blk digest; |
| 1362 | }; | 1516 | }; |
| ... | @@ -1369,7 +1523,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1369,7 +1523,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1369 | c_object.status = .{ | 1523 | c_object.status = .{ |
| 1370 | .success = .{ | 1524 | .success = .{ |
| 1371 | .object_path = try std.fs.path.join(comp.gpa, components), | 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,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 | /// Add common C compiler args between translate-c and C object compilation. | 1553 | /// Add common C compiler args between translate-c and C object compilation. |
| 1388 | pub fn addCCArgs( | 1554 | pub fn addCCArgs( |
| 1389 | comp: *Compilation, | 1555 | comp: *Compilation, |
| 1390 | arena: *Allocator, | 1556 | arena: *Allocator, |
| 1391 | argv: *std.ArrayList([]const u8), | 1557 | argv: *std.ArrayList([]const u8), |
| 1392 | ext: FileExt, | 1558 | ext: FileExt, |
| 1393 | translate_c: bool, | | |
| 1394 | out_dep_path: ?[]const u8, | 1559 | out_dep_path: ?[]const u8, |
| 1395 | ) !void { | 1560 | ) !void { |
| 1396 | const target = comp.getTarget(); | 1561 | const target = comp.getTarget(); |
| 1397 | | 1562 | |
| 1398 | if (translate_c) { | | |
| 1399 | try argv.appendSlice(&[_][]const u8{ "-x", "c" }); | | |
| 1400 | } | | |
| 1401 | | | |
| 1402 | if (ext == .cpp) { | 1563 | if (ext == .cpp) { |
| 1403 | try argv.append("-nostdinc++"); | 1564 | try argv.append("-nostdinc++"); |
| 1404 | } | 1565 | } |
| ... | @@ -1488,11 +1649,6 @@ pub fn addCCArgs( | ... | @@ -1488,11 +1649,6 @@ pub fn addCCArgs( |
| 1488 | if (mcmodel != .default) { | 1649 | if (mcmodel != .default) { |
| 1489 | try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={}", .{@tagName(mcmodel)})); | 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 | // windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning. | 1653 | // windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning. |
| 1498 | // So for this target, we disable this warning. | 1654 | // So for this target, we disable this warning. |
| ... | @@ -2118,7 +2274,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void { | ... | @@ -2118,7 +2274,7 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void { |
| 2118 | | 2274 | |
| 2119 | if (errors.list.len != 0) { | 2275 | if (errors.list.len != 0) { |
| 2120 | for (errors.list) |full_err_msg| { | 2276 | for (errors.list) |full_err_msg| { |
| 2121 | std.log.err("{}:{}:{}: {}\n", .{ | 2277 | log.err("{}:{}:{}: {}\n", .{ |
| 2122 | full_err_msg.src_path, | 2278 | full_err_msg.src_path, |
| 2123 | full_err_msg.line + 1, | 2279 | full_err_msg.line + 1, |
| 2124 | full_err_msg.column + 1, | 2280 | full_err_msg.column + 1, |
| ... | @@ -2231,23 +2387,23 @@ fn updateStage1Module(comp: *Compilation) !void { | ... | @@ -2231,23 +2387,23 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2231 | // the artifact directory the same, however, so we take the same strategy as linking | 2387 | // the artifact directory the same, however, so we take the same strategy as linking |
| 2232 | // does where we have a file which specifies the hash of the output directory so that we can | 2388 | // does where we have a file which specifies the hash of the output directory so that we can |
| 2233 | // skip the expensive compilation step if the hash matches. | 2389 | // skip the expensive compilation step if the hash matches. |
| 2234 | var ch = comp.cache_parent.obtain(); | 2390 | var man = comp.cache_parent.obtain(); |
| 2235 | defer ch.deinit(); | 2391 | defer man.deinit(); |
| 2236 | | 2392 | |
| 2237 | _ = try ch.addFile(main_zig_file, null); | 2393 | _ = try man.addFile(main_zig_file, null); |
| 2238 | ch.hash.add(comp.bin_file.options.valgrind); | 2394 | man.hash.add(comp.bin_file.options.valgrind); |
| 2239 | ch.hash.add(comp.bin_file.options.single_threaded); | 2395 | man.hash.add(comp.bin_file.options.single_threaded); |
| 2240 | ch.hash.add(target.os.getVersionRange()); | 2396 | man.hash.add(target.os.getVersionRange()); |
| 2241 | ch.hash.add(comp.bin_file.options.dll_export_fns); | 2397 | man.hash.add(comp.bin_file.options.dll_export_fns); |
| 2242 | ch.hash.add(comp.bin_file.options.function_sections); | 2398 | man.hash.add(comp.bin_file.options.function_sections); |
| 2243 | ch.hash.add(comp.is_test); | 2399 | man.hash.add(comp.is_test); |
| 2244 | | 2400 | |
| 2245 | // Capture the state in case we come back from this branch where the hash doesn't match. | 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(); | 2402 | const prev_hash_state = man.hash.peekBin(); |
| 2247 | const input_file_count = ch.files.items.len; | 2403 | const input_file_count = man.files.items.len; |
| 2248 | | 2404 | |
| 2249 | if (try ch.hit()) { | 2405 | if (try man.hit()) { |
| 2250 | const digest = ch.final(); | 2406 | const digest = man.final(); |
| 2251 | | 2407 | |
| 2252 | var prev_digest_buf: [digest.len]u8 = undefined; | 2408 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 2253 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | 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,11 +2413,11 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2257 | }; | 2413 | }; |
| 2258 | if (mem.eql(u8, prev_digest, &digest)) { | 2414 | if (mem.eql(u8, prev_digest, &digest)) { |
| 2259 | log.debug("stage1 {} digest={} match - skipping invocation", .{ mod.root_pkg.root_src_path, digest }); | 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 | return; | 2417 | return; |
| 2262 | } | 2418 | } |
| 2263 | log.debug("stage1 {} prev_digest={} new_digest={}", .{ mod.root_pkg.root_src_path, prev_digest, digest }); | 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 | // We are about to change the output file to be different, so we invalidate the build hash now. | 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,7 +2441,7 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2285 | defer main_progress_node.end(); | 2441 | defer main_progress_node.end(); |
| 2286 | if (comp.color == .Off) progress.terminal = null; | 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 | const main_pkg_path = mod.root_pkg.root_src_directory.path orelse ""; | 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,22 +2506,22 @@ fn updateStage1Module(comp: *Compilation) !void { |
| 2350 | stage1_module.build_object(); | 2506 | stage1_module.build_object(); |
| 2351 | stage1_module.destroy(); | 2507 | stage1_module.destroy(); |
| 2352 | | 2508 | |
| 2353 | const digest = ch.final(); | 2509 | const digest = man.final(); |
| 2354 | | 2510 | |
| 2355 | log.debug("stage1 {} final digest={}", .{ mod.root_pkg.root_src_path, digest }); | 2511 | log.debug("stage1 {} final digest={}", .{ mod.root_pkg.root_src_path, digest }); |
| 2356 | | 2512 | |
| 2357 | // Update the dangling symlink with the digest. If it fails we can continue; it only | 2513 | // Update the dangling symlink with the digest. If it fails we can continue; it only |
| 2358 | // means that the next invocation will have an unnecessary cache miss. | 2514 | // means that the next invocation will have an unnecessary cache miss. |
| 2359 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { | 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 | // Again failure here only means an unnecessary cache miss. | 2518 | // Again failure here only means an unnecessary cache miss. |
| 2363 | ch.writeManifest() catch |err| { | 2519 | man.writeManifest() catch |err| { |
| 2364 | std.log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)}); | 2520 | log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)}); |
| 2365 | }; | 2521 | }; |
| 2366 | // We hang on to this lock so that the output file path can be used without | 2522 | // We hang on to this lock so that the output file path can be used without |
| 2367 | // other processes clobbering it. | 2523 | // other processes clobbering it. |
| 2368 | comp.stage1_lock = ch.toOwnedLock(); | 2524 | comp.stage1_lock = man.toOwnedLock(); |
| 2369 | } | 2525 | } |
| 2370 | | 2526 | |
| 2371 | fn createStage1Pkg( | 2527 | fn createStage1Pkg( |