authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-24 16:22:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-24 16:22:45-07:00
log054fafd7d9a5226f21e7be1737c6d352fe39f795
treec0e10eb14eca2b7e8cccabe4e2cdfd36fe1d6119
parent1123c909872569e9a956f9110685c417036118bd

stage2: implement @cImport

Also rename Cache.CacheHash to Cache.Manifest

8 files changed, 311 insertions(+), 86 deletions(-)

BRANCH_TODO+1-2
...@@ -1,6 +1,4 @@...@@ -1,6 +1,4 @@
1 * repair @cImport
2 * tests passing with -Dskip-non-native1 * tests passing with -Dskip-non-native
3 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
4 * make sure zig cc works2 * make sure zig cc works
5 - using it as a preprocessor (-E)3 - using it as a preprocessor (-E)
6 - try building some software4 - try building some software
...@@ -24,6 +22,7 @@...@@ -24,6 +22,7 @@
24 * audit the base cache hash22 * audit the base cache hash
25 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.23 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
26 * restore error messages for stage2_add_link_lib24 * restore error messages for stage2_add_link_lib
25 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
2726
28 * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API27 * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API
29 * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API28 * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API
src/Cache.zig+24-24
...@@ -12,9 +12,9 @@ const mem = std.mem;...@@ -12,9 +12,9 @@ const mem = std.mem;
12const fmt = std.fmt;12const fmt = std.fmt;
13const Allocator = std.mem.Allocator;13const Allocator = std.mem.Allocator;
1414
15/// Be sure to call `CacheHash.deinit` after successful initialization.15/// Be sure to call `Manifest.deinit` after successful initialization.
16pub fn obtain(cache: *const Cache) CacheHash {16pub fn obtain(cache: *const Cache) Manifest {
17 return CacheHash{17 return Manifest{
18 .cache = cache,18 .cache = cache,
19 .hash = cache.hash,19 .hash = cache.hash,
20 .manifest_file = null,20 .manifest_file = null,
...@@ -30,7 +30,7 @@ pub const hex_digest_len = bin_digest_len * 2;...@@ -30,7 +30,7 @@ pub const hex_digest_len = bin_digest_len * 2;
30const manifest_file_size_max = 50 * 1024 * 1024;30const manifest_file_size_max = 50 * 1024 * 1024;
3131
32/// The type used for hashing file contents. Currently, this is SipHash128(1, 3), because it32/// The type used for hashing file contents. Currently, this is SipHash128(1, 3), because it
33/// provides enough collision resistance for the CacheHash use cases, while being one of our33/// provides enough collision resistance for the Manifest use cases, while being one of our
34/// fastest options right now.34/// fastest options right now.
35pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);35pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);
3636
...@@ -147,10 +147,10 @@ pub const Lock = struct {...@@ -147,10 +147,10 @@ pub const Lock = struct {
147 }147 }
148};148};
149149
150/// CacheHash manages project-local `zig-cache` directories.150/// Manifest manages project-local `zig-cache` directories.
151/// This is not a general-purpose cache.151/// This is not a general-purpose cache.
152/// It is designed to be fast and simple, not to withstand attacks using specially-crafted input.152/// It is designed to be fast and simple, not to withstand attacks using specially-crafted input.
153pub const CacheHash = struct {153pub const Manifest = struct {
154 cache: *const Cache,154 cache: *const Cache,
155 /// Current state for incremental hashing.155 /// Current state for incremental hashing.
156 hash: HashHelper,156 hash: HashHelper,
...@@ -173,7 +173,7 @@ pub const CacheHash = struct {...@@ -173,7 +173,7 @@ pub const CacheHash = struct {
173 /// ```173 /// ```
174 /// var file_contents = cache_hash.files.items[file_index].contents.?;174 /// var file_contents = cache_hash.files.items[file_index].contents.?;
175 /// ```175 /// ```
176 pub fn addFile(self: *CacheHash, file_path: []const u8, max_file_size: ?usize) !usize {176 pub fn addFile(self: *Manifest, file_path: []const u8, max_file_size: ?usize) !usize {
177 assert(self.manifest_file == null);177 assert(self.manifest_file == null);
178178
179 try self.files.ensureCapacity(self.cache.gpa, self.files.items.len + 1);179 try self.files.ensureCapacity(self.cache.gpa, self.files.items.len + 1);
...@@ -193,13 +193,13 @@ pub const CacheHash = struct {...@@ -193,13 +193,13 @@ pub const CacheHash = struct {
193 return idx;193 return idx;
194 }194 }
195195
196 pub fn addOptionalFile(self: *CacheHash, optional_file_path: ?[]const u8) !void {196 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
197 self.hash.add(optional_file_path != null);197 self.hash.add(optional_file_path != null);
198 const file_path = optional_file_path orelse return;198 const file_path = optional_file_path orelse return;
199 _ = try self.addFile(file_path, null);199 _ = try self.addFile(file_path, null);
200 }200 }
201201
202 pub fn addListOfFiles(self: *CacheHash, list_of_files: []const []const u8) !void {202 pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {
203 self.hash.add(list_of_files.len);203 self.hash.add(list_of_files.len);
204 for (list_of_files) |file_path| {204 for (list_of_files) |file_path| {
205 _ = try self.addFile(file_path, null);205 _ = try self.addFile(file_path, null);
...@@ -210,13 +210,13 @@ pub const CacheHash = struct {...@@ -210,13 +210,13 @@ pub const CacheHash = struct {
210 /// A hex encoding of its hash is available by calling `final`.210 /// A hex encoding of its hash is available by calling `final`.
211 ///211 ///
212 /// This function will also acquire an exclusive lock to the manifest file. This means212 /// This function will also acquire an exclusive lock to the manifest file. This means
213 /// that a process holding a CacheHash will block any other process attempting to213 /// that a process holding a Manifest will block any other process attempting to
214 /// acquire the lock.214 /// acquire the lock.
215 ///215 ///
216 /// The lock on the manifest file is released when `deinit` is called. As another216 /// The lock on the manifest file is released when `deinit` is called. As another
217 /// option, one may call `toOwnedLock` to obtain a smaller object which can represent217 /// option, one may call `toOwnedLock` to obtain a smaller object which can represent
218 /// the lock. `deinit` is safe to call whether or not `toOwnedLock` has been called.218 /// the lock. `deinit` is safe to call whether or not `toOwnedLock` has been called.
219 pub fn hit(self: *CacheHash) !bool {219 pub fn hit(self: *Manifest) !bool {
220 assert(self.manifest_file == null);220 assert(self.manifest_file == null);
221221
222 const ext = ".txt";222 const ext = ".txt";
...@@ -361,7 +361,7 @@ pub const CacheHash = struct {...@@ -361,7 +361,7 @@ pub const CacheHash = struct {
361 return true;361 return true;
362 }362 }
363363
364 pub fn unhit(self: *CacheHash, bin_digest: [bin_digest_len]u8, input_file_count: usize) void {364 pub fn unhit(self: *Manifest, bin_digest: [bin_digest_len]u8, input_file_count: usize) void {
365 // Reset the hash.365 // Reset the hash.
366 self.hash.hasher = hasher_init;366 self.hash.hasher = hasher_init;
367 self.hash.hasher.update(&bin_digest);367 self.hash.hasher.update(&bin_digest);
...@@ -377,7 +377,7 @@ pub const CacheHash = struct {...@@ -377,7 +377,7 @@ pub const CacheHash = struct {
377 }377 }
378 }378 }
379379
380 fn populateFileHash(self: *CacheHash, ch_file: *File) !void {380 fn populateFileHash(self: *Manifest, ch_file: *File) !void {
381 const file = try fs.cwd().openFile(ch_file.path.?, .{});381 const file = try fs.cwd().openFile(ch_file.path.?, .{});
382 defer file.close();382 defer file.close();
383383
...@@ -421,7 +421,7 @@ pub const CacheHash = struct {...@@ -421,7 +421,7 @@ pub const CacheHash = struct {
421 /// calculated. This is useful for processes that don't know the all the files that421 /// calculated. This is useful for processes that don't know the all the files that
422 /// are depended on ahead of time. For example, a source file that can import other files422 /// are depended on ahead of time. For example, a source file that can import other files
423 /// will need to be recompiled if the imported file is changed.423 /// will need to be recompiled if the imported file is changed.
424 pub fn addFilePostFetch(self: *CacheHash, file_path: []const u8, max_file_size: usize) ![]const u8 {424 pub fn addFilePostFetch(self: *Manifest, file_path: []const u8, max_file_size: usize) ![]const u8 {
425 assert(self.manifest_file != null);425 assert(self.manifest_file != null);
426426
427 const resolved_path = try fs.path.resolve(self.cache.gpa, &[_][]const u8{file_path});427 const resolved_path = try fs.path.resolve(self.cache.gpa, &[_][]const u8{file_path});
...@@ -446,7 +446,7 @@ pub const CacheHash = struct {...@@ -446,7 +446,7 @@ pub const CacheHash = struct {
446 /// calculated. This is useful for processes that don't know the all the files that446 /// calculated. This is useful for processes that don't know the all the files that
447 /// are depended on ahead of time. For example, a source file that can import other files447 /// are depended on ahead of time. For example, a source file that can import other files
448 /// will need to be recompiled if the imported file is changed.448 /// will need to be recompiled if the imported file is changed.
449 pub fn addFilePost(self: *CacheHash, file_path: []const u8) !void {449 pub fn addFilePost(self: *Manifest, file_path: []const u8) !void {
450 assert(self.manifest_file != null);450 assert(self.manifest_file != null);
451451
452 const resolved_path = try fs.path.resolve(self.cache.gpa, &[_][]const u8{file_path});452 const resolved_path = try fs.path.resolve(self.cache.gpa, &[_][]const u8{file_path});
...@@ -465,7 +465,7 @@ pub const CacheHash = struct {...@@ -465,7 +465,7 @@ pub const CacheHash = struct {
465 try self.populateFileHash(new_ch_file);465 try self.populateFileHash(new_ch_file);
466 }466 }
467467
468 pub fn addDepFilePost(self: *CacheHash, dir: fs.Dir, dep_file_basename: []const u8) !void {468 pub fn addDepFilePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void {
469 assert(self.manifest_file != null);469 assert(self.manifest_file != null);
470470
471 const dep_file_contents = try dir.readFileAlloc(self.cache.gpa, dep_file_basename, manifest_file_size_max);471 const dep_file_contents = try dir.readFileAlloc(self.cache.gpa, dep_file_basename, manifest_file_size_max);
...@@ -501,7 +501,7 @@ pub const CacheHash = struct {...@@ -501,7 +501,7 @@ pub const CacheHash = struct {
501 }501 }
502502
503 /// Returns a hex encoded hash of the inputs.503 /// Returns a hex encoded hash of the inputs.
504 pub fn final(self: *CacheHash) [hex_digest_len]u8 {504 pub fn final(self: *Manifest) [hex_digest_len]u8 {
505 assert(self.manifest_file != null);505 assert(self.manifest_file != null);
506506
507 // We don't close the manifest file yet, because we want to507 // We don't close the manifest file yet, because we want to
...@@ -519,7 +519,7 @@ pub const CacheHash = struct {...@@ -519,7 +519,7 @@ pub const CacheHash = struct {
519 return out_digest;519 return out_digest;
520 }520 }
521521
522 pub fn writeManifest(self: *CacheHash) !void {522 pub fn writeManifest(self: *Manifest) !void {
523 assert(self.manifest_file != null);523 assert(self.manifest_file != null);
524 if (!self.manifest_dirty) return;524 if (!self.manifest_dirty) return;
525525
...@@ -544,18 +544,18 @@ pub const CacheHash = struct {...@@ -544,18 +544,18 @@ pub const CacheHash = struct {
544 }544 }
545545
546 /// Obtain only the data needed to maintain a lock on the manifest file.546 /// Obtain only the data needed to maintain a lock on the manifest file.
547 /// The `CacheHash` remains safe to deinit.547 /// The `Manifest` remains safe to deinit.
548 /// Don't forget to call `writeManifest` before this!548 /// Don't forget to call `writeManifest` before this!
549 pub fn toOwnedLock(self: *CacheHash) Lock {549 pub fn toOwnedLock(self: *Manifest) Lock {
550 const manifest_file = self.manifest_file.?;550 const manifest_file = self.manifest_file.?;
551 self.manifest_file = null;551 self.manifest_file = null;
552 return Lock{ .manifest_file = manifest_file };552 return Lock{ .manifest_file = manifest_file };
553 }553 }
554554
555 /// Releases the manifest file and frees any memory the CacheHash was using.555 /// Releases the manifest file and frees any memory the Manifest was using.
556 /// `CacheHash.hit` must be called first.556 /// `Manifest.hit` must be called first.
557 /// Don't forget to call `writeManifest` before this!557 /// Don't forget to call `writeManifest` before this!
558 pub fn deinit(self: *CacheHash) void {558 pub fn deinit(self: *Manifest) void {
559 if (self.manifest_file) |file| {559 if (self.manifest_file) |file| {
560 file.close();560 file.close();
561 }561 }
...@@ -808,7 +808,7 @@ test "no file inputs" {...@@ -808,7 +808,7 @@ test "no file inputs" {
808 testing.expectEqual(digest1, digest2);808 testing.expectEqual(digest1, digest2);
809}809}
810810
811test "CacheHashes with files added after initial hash work" {811test "Manifest with files added after initial hash work" {
812 if (std.Target.current.os.tag == .wasi) {812 if (std.Target.current.os.tag == .wasi) {
813 // https://github.com/ziglang/zig/issues/5437813 // https://github.com/ziglang/zig/issues/5437
814 return error.SkipZigTest;814 return error.SkipZigTest;
src/Compilation.zig+209-53
...@@ -22,6 +22,7 @@ const fatal = @import("main.zig").fatal;...@@ -22,6 +22,7 @@ const fatal = @import("main.zig").fatal;
22const Module = @import("Module.zig");22const Module = @import("Module.zig");
23const Cache = @import("Cache.zig");23const Cache = @import("Cache.zig");
24const stage1 = @import("stage1.zig");24const stage1 = @import("stage1.zig");
25const translate_c = @import("translate_c.zig");
2526
26/// General-purpose allocator. Used for both temporary and long-term storage.27/// General-purpose allocator. Used for both temporary and long-term storage.
27gpa: *Allocator,28gpa: *Allocator,
...@@ -30,7 +31,7 @@ arena_state: std.heap.ArenaAllocator.State,...@@ -30,7 +31,7 @@ arena_state: std.heap.ArenaAllocator.State,
30bin_file: *link.File,31bin_file: *link.File,
31c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},32c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
32stage1_lock: ?Cache.Lock = null,33stage1_lock: ?Cache.Lock = null,
33stage1_cache_hash: *Cache.CacheHash = undefined,34stage1_cache_manifest: *Cache.Manifest = undefined,
3435
35link_error_flags: link.File.ErrorFlags = .{},36link_error_flags: link.File.ErrorFlags = .{},
3637
...@@ -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}
12001201
1201fn updateCObject(comp: *Compilation, c_object: *CObject) !void {1202fn 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
1217test "cImport" {
1218 _ = cImport;
1219}
1220
1221const 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.
1229pub 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();
12041235
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
1359fn 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 orelse1363 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", .{});
12101365
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 }
12151373
1216 var ch = comp.cache_parent.obtain();1374 var man = comp.obtainCObjectCacheManifest();
1217 defer ch.deinit();1375 defer man.deinit();
12181376
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() });
12561410
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();
12601414
...@@ -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 null1424 null
1271 else1425 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);
12741428
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 message1480 // TODO parse clang stderr and turn it into an error message
1327 // and then call failCObjWithOwnedErrorMsg1481 // 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 }
13481502
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);
13571511
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}
13861540
1541pub 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.
1388pub fn addCCArgs(1554pub 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();
13971562
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 }
14961652
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 {
21182274
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 linking2387 // 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 can2388 // 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();
22362392
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);
22442400
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;
22482404
2249 if (try ch.hit()) {2405 if (try man.hit()) {
2250 const digest = ch.final();2406 const digest = man.final();
22512407
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 }
22662422
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;
22872443
2288 comp.stage1_cache_hash = &ch;2444 comp.stage1_cache_manifest = &man;
22892445
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 "";
22912447
...@@ -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();
23522508
2353 const digest = ch.final();2509 const digest = man.final();
23542510
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 });
23562512
2357 // Update the dangling symlink with the digest. If it fails we can continue; it only2513 // 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 without2522 // 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}
23702526
2371fn createStage1Pkg(2527fn createStage1Pkg(
src/main.zig+1-1
...@@ -1617,7 +1617,7 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator) !void {...@@ -1617,7 +1617,7 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator) !void {
16171617
1618 const c_source_file = comp.c_source_files[0];1618 const c_source_file = comp.c_source_files[0];
1619 const file_ext = Compilation.classifyFileExt(c_source_file.src_path);1619 const file_ext = Compilation.classifyFileExt(c_source_file.src_path);
1620 try comp.addCCArgs(arena, &argv, file_ext, true, null);1620 try comp.addTranslateCCArgs(arena, &argv, file_ext, null);
1621 try argv.append(c_source_file.src_path);1621 try argv.append(c_source_file.src_path);
16221622
1623 if (comp.verbose_cc) {1623 if (comp.verbose_cc) {
src/stage1.zig+34-3
...@@ -11,10 +11,12 @@ const fatal = stage2.fatal;...@@ -11,10 +11,12 @@ const fatal = stage2.fatal;
11const CrossTarget = std.zig.CrossTarget;11const CrossTarget = std.zig.CrossTarget;
12const Target = std.Target;12const Target = std.Target;
13const Compilation = @import("Compilation.zig");13const Compilation = @import("Compilation.zig");
14const translate_c = @import("translate_c.zig");
1415
15comptime {16comptime {
16 assert(std.builtin.link_libc);17 assert(std.builtin.link_libc);
17 assert(build_options.is_stage1);18 assert(build_options.is_stage1);
19 assert(build_options.have_llvm);
18 _ = @import("compiler_rt");20 _ = @import("compiler_rt");
19}21}
2022
...@@ -322,8 +324,37 @@ const Stage2SemVer = extern struct {...@@ -322,8 +324,37 @@ const Stage2SemVer = extern struct {
322};324};
323325
324// ABI warning326// ABI warning
325export fn stage2_cimport(stage1: *Module) [*:0]const u8 {327export fn stage2_cimport(
326 @panic("TODO implement stage2_cimport");328 stage1: *Module,
329 c_src_ptr: [*]const u8,
330 c_src_len: usize,
331 out_zig_path_ptr: *[*]const u8,
332 out_zig_path_len: *usize,
333 out_errors_ptr: *[*]translate_c.ClangErrMsg,
334 out_errors_len: *usize,
335) Error {
336 const comp = @intToPtr(*Compilation, stage1.userdata);
337 const c_src = c_src_ptr[0..c_src_len];
338 const result = comp.cImport(c_src) catch |err| switch (err) {
339 error.SystemResources => return .SystemResources,
340 error.OperationAborted => return .OperationAborted,
341 error.BrokenPipe => return .BrokenPipe,
342 error.DiskQuota => return .DiskQuota,
343 error.FileTooBig => return .FileTooBig,
344 error.NoSpaceLeft => return .NoSpaceLeft,
345 error.AccessDenied => return .AccessDenied,
346 error.OutOfMemory => return .OutOfMemory,
347 error.Unexpected => return .Unexpected,
348 error.InputOutput => return .FileSystem,
349 error.ASTUnitFailure => return .ASTUnitFailure,
350 else => return .Unexpected,
351 };
352 out_zig_path_ptr.* = result.out_zig_path.ptr;
353 out_zig_path_len.* = result.out_zig_path.len;
354 out_errors_ptr.* = result.errors.ptr;
355 out_errors_len.* = result.errors.len;
356 if (result.errors.len != 0) return .CCompileErrors;
357 return Error.None;
327}358}
328359
329export fn stage2_add_link_lib(360export fn stage2_add_link_lib(
...@@ -345,7 +376,7 @@ export fn stage2_fetch_file(...@@ -345,7 +376,7 @@ export fn stage2_fetch_file(
345 const comp = @intToPtr(*Compilation, stage1.userdata);376 const comp = @intToPtr(*Compilation, stage1.userdata);
346 const file_path = path_ptr[0..path_len];377 const file_path = path_ptr[0..path_len];
347 const max_file_size = std.math.maxInt(u32);378 const max_file_size = std.math.maxInt(u32);
348 const contents = comp.stage1_cache_hash.addFilePostFetch(file_path, max_file_size) catch return null;379 const contents = comp.stage1_cache_manifest.addFilePostFetch(file_path, max_file_size) catch return null;
349 result_len.* = contents.len;380 result_len.* = contents.len;
350 return contents.ptr;381 return contents.ptr;
351}382}
src/stage1/ir.cpp+35-1
...@@ -26382,7 +26382,41 @@ static IrInstGen *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstSrcCImpo...@@ -26382,7 +26382,41 @@ static IrInstGen *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstSrcCImpo
26382 cimport_pkg->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);26382 cimport_pkg->package_table.put(buf_create_from_str("std"), ira->codegen->std_package);
26383 buf_init_from_buf(&cimport_pkg->pkg_path, namespace_name);26383 buf_init_from_buf(&cimport_pkg->pkg_path, namespace_name);
2638426384
26385 Buf *out_zig_path = buf_create_from_str(stage2_cimport(&ira->codegen->stage1));26385 const char *out_zig_path_ptr;
26386 size_t out_zig_path_len;
26387 Stage2ErrorMsg *errors_ptr;
26388 size_t errors_len;
26389 if ((err = stage2_cimport(&ira->codegen->stage1,
26390 buf_ptr(&cimport_scope->buf), buf_len(&cimport_scope->buf),
26391 &out_zig_path_ptr, &out_zig_path_len,
26392 &errors_ptr, &errors_len)))
26393 {
26394 if (err != ErrorCCompileErrors) {
26395 ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err)));
26396 return ira->codegen->invalid_inst_gen;
26397 }
26398
26399 ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed"));
26400 if (!ira->codegen->stage1.link_libc) {
26401 add_error_note(ira->codegen, parent_err_msg, node,
26402 buf_sprintf("libc headers not available; compilation does not link against libc"));
26403 }
26404 for (size_t i = 0; i < errors_len; i += 1) {
26405 Stage2ErrorMsg *clang_err = &errors_ptr[i];
26406 // Clang can emit "too many errors, stopping now", in which case `source` and `filename_ptr` are null
26407 if (clang_err->source && clang_err->filename_ptr) {
26408 ErrorMsg *err_msg = err_msg_create_with_offset(
26409 clang_err->filename_ptr ?
26410 buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
26411 clang_err->line, clang_err->column, clang_err->offset, clang_err->source,
26412 buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));
26413 err_msg_add_note(parent_err_msg, err_msg);
26414 }
26415 }
26416
26417 return ira->codegen->invalid_inst_gen;
26418 }
26419 Buf *out_zig_path = buf_create_from_mem(out_zig_path_ptr, out_zig_path_len);
2638626420
26387 Buf *import_code = buf_alloc();26421 Buf *import_code = buf_alloc();
26388 if ((err = file_fetch(ira->codegen, out_zig_path, import_code))) {26422 if ((err = file_fetch(ira->codegen, out_zig_path, import_code))) {
src/stage1/stage2.h+3-1
...@@ -165,7 +165,9 @@ ZIG_EXTERN_C const char *stage2_fetch_file(struct ZigStage1 *stage1, const char...@@ -165,7 +165,9 @@ ZIG_EXTERN_C const char *stage2_fetch_file(struct ZigStage1 *stage1, const char
165 size_t *result_len);165 size_t *result_len);
166166
167// ABI warning167// ABI warning
168ZIG_EXTERN_C const char *stage2_cimport(struct ZigStage1 *stage1);168ZIG_EXTERN_C Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len,
169 const char **out_zig_path_ptr, size_t *out_zig_path_len,
170 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len);
169171
170// ABI warning172// ABI warning
171ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1,173ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1,
src/stage1/zig0.cpp+4-1
...@@ -511,7 +511,10 @@ const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, si...@@ -511,7 +511,10 @@ const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, si
511 return buf_ptr(&contents_buf);511 return buf_ptr(&contents_buf);
512}512}
513513
514const char *stage2_cimport(struct ZigStage1 *stage1) {514Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len,
515 const char **out_zig_path_ptr, size_t *out_zig_path_len,
516 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len)
517{
515 const char *msg = "stage0 called stage2_cimport";518 const char *msg = "stage0 called stage2_cimport";
516 stage2_panic(msg, strlen(msg));519 stage2_panic(msg, strlen(msg));
517}520}