diff options
| author | Veikka Tuominen <git@vexu.eu> | 2021-09-19 11:51:32 +0300 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-09-20 20:50:55 -0700 |
| commit | 9a54ff72df5cc8631c467f3478117eb85a952ced (patch) | |
| tree | c303fa7cdde3c8165d034da1ed8357175c260e3d | |
| parent | 1ad905c71e0896295d4781853cd577bbe1b4111a (diff) | |
| download | zig-9a54ff72df5cc8631c467f3478117eb85a952ced.tar.gz zig-9a54ff72df5cc8631c467f3478117eb85a952ced.zip | |
stage2: implement cImport
| -rw-r--r-- | src/AstGen.zig | 6 | ||||
| -rw-r--r-- | src/Compilation.zig | 2 | ||||
| -rw-r--r-- | src/Module.zig | 3 | ||||
| -rw-r--r-- | src/Sema.zig | 88 |
4 files changed, 92 insertions, 7 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index f1eabe4c0c..32b62fc3f5 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7269,6 +7269,7 @@ fn builtinCall( return rvalue(gz, rl, result, node); }, .c_define => { + if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); const value = try comptimeExpr(gz, scope, .none, params[1]); const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ @@ -7641,6 +7642,8 @@ fn simpleCBuiltin( operand_node: Ast.Node.Index, tag: Zir.Inst.Extended, ) InnerError!Zir.Inst.Ref { + const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; + if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), @@ -7698,6 +7701,7 @@ fn cImport( var block_scope = gz.makeSubBlock(scope); block_scope.force_comptime = true; + block_scope.c_import = true; defer block_scope.instructions.deinit(gpa); const block_inst = try gz.addBlock(.c_import, node); @@ -9025,6 +9029,7 @@ const GenZir = struct { base: Scope = Scope{ .tag = base_tag }, force_comptime: bool, in_defer: bool, + c_import: bool = false, /// How decls created in this scope should be named. anon_name_strategy: Zir.Inst.NameStrategy = .anon, /// The containing decl AST node. @@ -9070,6 +9075,7 @@ const GenZir = struct { return .{ .force_comptime = gz.force_comptime, .in_defer = gz.in_defer, + .c_import = gz.c_import, .decl_node_index = gz.decl_node_index, .decl_line = gz.decl_line, .parent = scope, diff --git a/src/Compilation.zig b/src/Compilation.zig index c1dfe91dc2..55cc9d0867 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2644,7 +2644,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { const dep_basename = std.fs.path.basename(out_dep_path); try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); - try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + if (build_options.is_stage1) try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); const digest = man.final(); const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); diff --git a/src/Module.zig b/src/Module.zig index 500c34bcb0..6a183db21f 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1325,6 +1325,8 @@ pub const Scope = struct { /// when null, it is determined by build mode, changed by @setRuntimeSafety want_safety: ?bool = null, + c_import_buf: ?*std.ArrayList(u8) = null, + const Param = struct { /// `noreturn` means `anytype`. ty: Type, @@ -1377,6 +1379,7 @@ pub const Scope = struct { .runtime_loop = parent.runtime_loop, .runtime_index = parent.runtime_index, .want_safety = parent.want_safety, + .c_import_buf = parent.c_import_buf, }; } diff --git a/src/Sema.zig b/src/Sema.zig index ff32ce49ca..ac11cf4dcc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2138,10 +2138,72 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com const tracy = trace(@src()); defer tracy.end(); - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); + const pl_node = sema.code.instructions.items(.data)[inst].pl_node; + const src = pl_node.src(); + const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); + const body = sema.code.extra[extra.end..][0..extra.data.body_len]; + + // we check this here to avoid undefined symbols + if (!@import("build_options").have_llvm) + return sema.mod.fail(&parent_block.base, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{}); + + var c_import_buf = std.ArrayList(u8).init(sema.gpa); + defer c_import_buf.deinit(); + + var child_block: Scope.Block = .{ + .parent = parent_block, + .sema = sema, + .src_decl = parent_block.src_decl, + .instructions = .{}, + .inlining = parent_block.inlining, + .is_comptime = parent_block.is_comptime, + .c_import_buf = &c_import_buf, + }; + defer child_block.instructions.deinit(sema.gpa); + + _ = try sema.analyzeBody(&child_block, body); + + const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err| + return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)}); - return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{}); + if (c_import_res.errors.len != 0) { + const msg = try sema.mod.errMsg(&child_block.base, src, "C import failed", .{}); + errdefer msg.destroy(sema.gpa); + + if (!sema.mod.comp.bin_file.options.link_libc) + try sema.mod.errNote(&child_block.base, src, msg, "libc headers not available; compilation does not link against libc", .{}); + + for (c_import_res.errors) |_| { + // TODO integrate with LazySrcLoc + // try sema.mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]}); + // if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)", + // clang_err.line + 1, + // clang_err.column + 1, + } + @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); + return sema.mod.failWithOwnedErrorMsg(&child_block.base, msg); + } + const c_import_pkg = @import("Package.zig").createWithDir( + sema.gpa, + sema.mod.comp.local_cache_directory, + null, + std.fs.path.basename(c_import_res.out_zig_path), + ) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => unreachable, // we pass null for root_src_dir_path + }; + const std_pkg = sema.mod.main_pkg.table.get("std").?; + const builtin_pkg = sema.mod.main_pkg.table.get("builtin").?; + try c_import_pkg.add(sema.gpa, "builtin", builtin_pkg); + try c_import_pkg.add(sema.gpa, "std", std_pkg); + + const result = sema.mod.importPkg(c_import_pkg) catch |err| + return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)}); + + try sema.mod.semaFile(result.file); + const file_root_decl = result.file.root_decl.?; + try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl); + return sema.addType(file_root_decl.ty); } fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -8226,7 +8288,10 @@ fn zirCUndef( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCUndef", .{}); + + const name = try sema.resolveConstString(block, src, extra.operand); + try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name}); + return Air.Inst.Ref.void_value; } fn zirCInclude( @@ -8236,7 +8301,10 @@ fn zirCInclude( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCInclude", .{}); + + const name = try sema.resolveConstString(block, src, extra.operand); + try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); + return Air.Inst.Ref.void_value; } fn zirCDefine( @@ -8246,7 +8314,15 @@ fn zirCDefine( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCDefine", .{}); + + const name = try sema.resolveConstString(block, src, extra.lhs); + if (sema.typeOf(extra.rhs).zigTypeTag() != .Void) { + const value = try sema.resolveConstString(block, src, extra.rhs); + try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); + } else { + try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); + } + return Air.Inst.Ref.void_value; } fn zirWasmMemorySize( |
