mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 03:03:09 +00:00
stage2: handle extern lib name annotation for vars
For example, a situation like this is allowed ```zig extern "c" var stderrp: c_int; ``` In this case, `Module.Var` wrapping `stderrp` will have `lib_name` populated with the library name where this import is expected.
This commit is contained in:
parent
556f0ce5bf
commit
db9500a314
@ -510,6 +510,7 @@ pub const Decl = struct {
|
|||||||
gpa.destroy(func);
|
gpa.destroy(func);
|
||||||
}
|
}
|
||||||
if (decl.getVariable()) |variable| {
|
if (decl.getVariable()) |variable| {
|
||||||
|
variable.deinit(gpa);
|
||||||
gpa.destroy(variable);
|
gpa.destroy(variable);
|
||||||
}
|
}
|
||||||
if (decl.value_arena) |arena_state| {
|
if (decl.value_arena) |arena_state| {
|
||||||
@ -694,6 +695,8 @@ pub const Decl = struct {
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the Decl has a value and it is an extern function, returns it,
|
||||||
|
/// otherwise null.
|
||||||
pub fn getExternFn(decl: *const Decl) ?*ExternFn {
|
pub fn getExternFn(decl: *const Decl) ?*ExternFn {
|
||||||
if (!decl.owns_tv) return null;
|
if (!decl.owns_tv) return null;
|
||||||
const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data;
|
const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data;
|
||||||
@ -701,6 +704,8 @@ pub const Decl = struct {
|
|||||||
return extern_fn;
|
return extern_fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the Decl has a value and it is a variable, returns it,
|
||||||
|
/// otherwise null.
|
||||||
pub fn getVariable(decl: *Decl) ?*Var {
|
pub fn getVariable(decl: *Decl) ?*Var {
|
||||||
if (!decl.owns_tv) return null;
|
if (!decl.owns_tv) return null;
|
||||||
const variable = (decl.val.castTag(.variable) orelse return null).data;
|
const variable = (decl.val.castTag(.variable) orelse return null).data;
|
||||||
@ -1469,9 +1474,20 @@ pub const Var = struct {
|
|||||||
init: Value,
|
init: Value,
|
||||||
owner_decl: *Decl,
|
owner_decl: *Decl,
|
||||||
|
|
||||||
|
/// Library name if specified.
|
||||||
|
/// For example `extern "c" var stderrp = ...` would have 'c' as library name.
|
||||||
|
/// Allocated with Module's allocator; outlives the ZIR code.
|
||||||
|
lib_name: ?[*:0]const u8,
|
||||||
|
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
|
|
||||||
|
pub fn deinit(variable: *Var, gpa: Allocator) void {
|
||||||
|
if (variable.lib_name) |lib_name| {
|
||||||
|
gpa.free(mem.sliceTo(lib_name, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The container that structs, enums, unions, and opaques have.
|
/// The container that structs, enums, unions, and opaques have.
|
||||||
|
|||||||
134
src/Sema.zig
134
src/Sema.zig
@ -5430,6 +5430,69 @@ fn zirFunc(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a library name, examines if the library name should end up in
|
||||||
|
/// `link.File.Options.system_libs` table (for example, libc is always
|
||||||
|
/// specified via dedicated flag `link.File.Options.link_libc` instead),
|
||||||
|
/// and puts it there if it doesn't exist.
|
||||||
|
/// It also dupes the library name which can then be saved as part of the
|
||||||
|
/// respective `Decl` (either `ExternFn` or `Var`).
|
||||||
|
/// The liveness of the duped library name is tied to liveness of `Module`.
|
||||||
|
/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
|
||||||
|
fn handleExternLibName(
|
||||||
|
sema: *Sema,
|
||||||
|
block: *Block,
|
||||||
|
src_loc: LazySrcLoc,
|
||||||
|
lib_name: []const u8,
|
||||||
|
) CompileError![:0]u8 {
|
||||||
|
blk: {
|
||||||
|
const mod = sema.mod;
|
||||||
|
const target = mod.getTarget();
|
||||||
|
log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
|
||||||
|
if (target_util.is_libc_lib_name(target, lib_name)) {
|
||||||
|
if (!mod.comp.bin_file.options.link_libc) {
|
||||||
|
return sema.fail(
|
||||||
|
block,
|
||||||
|
src_loc,
|
||||||
|
"dependency on libc must be explicitly specified in the build command",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
mod.comp.bin_file.options.link_libc = true;
|
||||||
|
break :blk;
|
||||||
|
}
|
||||||
|
if (target_util.is_libcpp_lib_name(target, lib_name)) {
|
||||||
|
if (!mod.comp.bin_file.options.link_libcpp) {
|
||||||
|
return sema.fail(
|
||||||
|
block,
|
||||||
|
src_loc,
|
||||||
|
"dependency on libc++ must be explicitly specified in the build command",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
mod.comp.bin_file.options.link_libcpp = true;
|
||||||
|
break :blk;
|
||||||
|
}
|
||||||
|
if (mem.eql(u8, lib_name, "unwind")) {
|
||||||
|
mod.comp.bin_file.options.link_libunwind = true;
|
||||||
|
break :blk;
|
||||||
|
}
|
||||||
|
if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
|
||||||
|
return sema.fail(
|
||||||
|
block,
|
||||||
|
src_loc,
|
||||||
|
"dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
|
||||||
|
.{ lib_name, lib_name },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
mod.comp.stage1AddLinkLib(lib_name) catch |err| {
|
||||||
|
return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
|
||||||
|
lib_name, @errorName(err),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return sema.gpa.dupeZ(u8, lib_name);
|
||||||
|
}
|
||||||
|
|
||||||
fn funcCommon(
|
fn funcCommon(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
block: *Block,
|
block: *Block,
|
||||||
@ -5567,65 +5630,21 @@ fn funcCommon(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opt_lib_name) |lib_name| blk: {
|
|
||||||
const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset };
|
|
||||||
log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
|
|
||||||
if (target_util.is_libc_lib_name(target, lib_name)) {
|
|
||||||
if (!mod.comp.bin_file.options.link_libc) {
|
|
||||||
return sema.fail(
|
|
||||||
block,
|
|
||||||
lib_name_src,
|
|
||||||
"dependency on libc must be explicitly specified in the build command",
|
|
||||||
.{},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
mod.comp.bin_file.options.link_libc = true;
|
|
||||||
break :blk;
|
|
||||||
}
|
|
||||||
if (target_util.is_libcpp_lib_name(target, lib_name)) {
|
|
||||||
if (!mod.comp.bin_file.options.link_libcpp) {
|
|
||||||
return sema.fail(
|
|
||||||
block,
|
|
||||||
lib_name_src,
|
|
||||||
"dependency on libc++ must be explicitly specified in the build command",
|
|
||||||
.{},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
mod.comp.bin_file.options.link_libcpp = true;
|
|
||||||
break :blk;
|
|
||||||
}
|
|
||||||
if (mem.eql(u8, lib_name, "unwind")) {
|
|
||||||
mod.comp.bin_file.options.link_libunwind = true;
|
|
||||||
break :blk;
|
|
||||||
}
|
|
||||||
if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
|
|
||||||
return sema.fail(
|
|
||||||
block,
|
|
||||||
lib_name_src,
|
|
||||||
"dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
|
|
||||||
.{ lib_name, lib_name },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
mod.comp.stage1AddLinkLib(lib_name) catch |err| {
|
|
||||||
return sema.fail(block, lib_name_src, "unable to add link lib '{s}': {s}", .{
|
|
||||||
lib_name, @errorName(err),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_extern) {
|
if (is_extern) {
|
||||||
const new_extern_fn = try sema.gpa.create(Module.ExternFn);
|
const new_extern_fn = try sema.gpa.create(Module.ExternFn);
|
||||||
errdefer sema.gpa.destroy(new_extern_fn);
|
errdefer sema.gpa.destroy(new_extern_fn);
|
||||||
|
|
||||||
const lib_name: ?[*:0]const u8 = if (opt_lib_name) |lib_name| blk: {
|
|
||||||
break :blk try sema.gpa.dupeZ(u8, lib_name);
|
|
||||||
} else null;
|
|
||||||
|
|
||||||
new_extern_fn.* = Module.ExternFn{
|
new_extern_fn.* = Module.ExternFn{
|
||||||
.owner_decl = sema.owner_decl,
|
.owner_decl = sema.owner_decl,
|
||||||
.lib_name = lib_name,
|
.lib_name = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (opt_lib_name) |lib_name| {
|
||||||
|
new_extern_fn.lib_name = try sema.handleExternLibName(block, .{
|
||||||
|
.node_offset_lib_name = src_node_offset,
|
||||||
|
}, lib_name);
|
||||||
|
}
|
||||||
|
|
||||||
const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn);
|
const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn);
|
||||||
extern_fn_payload.* = .{
|
extern_fn_payload.* = .{
|
||||||
.base = .{ .tag = .extern_fn },
|
.base = .{ .tag = .extern_fn },
|
||||||
@ -12456,13 +12475,8 @@ fn zirVarExtended(
|
|||||||
|
|
||||||
try sema.validateVarType(block, mut_src, var_ty, small.is_extern);
|
try sema.validateVarType(block, mut_src, var_ty, small.is_extern);
|
||||||
|
|
||||||
if (lib_name != null) {
|
|
||||||
// Look at the sema code for functions which has this logic, it just needs to
|
|
||||||
// be extracted and shared by both var and func
|
|
||||||
return sema.fail(block, src, "TODO: handle var with lib_name in Sema", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
const new_var = try sema.gpa.create(Module.Var);
|
const new_var = try sema.gpa.create(Module.Var);
|
||||||
|
errdefer sema.gpa.destroy(new_var);
|
||||||
|
|
||||||
log.debug("created variable {*} owner_decl: {*} ({s})", .{
|
log.debug("created variable {*} owner_decl: {*} ({s})", .{
|
||||||
new_var, sema.owner_decl, sema.owner_decl.name,
|
new_var, sema.owner_decl, sema.owner_decl.name,
|
||||||
@ -12474,7 +12488,13 @@ fn zirVarExtended(
|
|||||||
.is_extern = small.is_extern,
|
.is_extern = small.is_extern,
|
||||||
.is_mutable = true, // TODO get rid of this unused field
|
.is_mutable = true, // TODO get rid of this unused field
|
||||||
.is_threadlocal = small.is_threadlocal,
|
.is_threadlocal = small.is_threadlocal,
|
||||||
|
.lib_name = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (lib_name) |lname| {
|
||||||
|
new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname);
|
||||||
|
}
|
||||||
|
|
||||||
const result = try sema.addConstant(
|
const result = try sema.addConstant(
|
||||||
var_ty,
|
var_ty,
|
||||||
try Value.Tag.variable.create(sema.arena, new_var),
|
try Value.Tag.variable.create(sema.arena, new_var),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user