| author | |
| committer | |
| log | 78f643c46d36d296d17b332b577c966fd0dd21bb |
| tree | daa72a84c587ed47377d6db27bf9725f95d94cb2 |
| parent | 6bf52b0505ad7317b5f0d6fa77b7c41318b9c73b |
| parent | 7edd69d8aade6da2339cb0d9a027c52b3015bc31 |
| signature |
Add `is_dll_import` to @extern, to support `__declspec(dllimport)` with the MSVC ABI12 files changed, 99 insertions(+), 19 deletions(-)
lib/std/builtin.zig+1| ... | ... | @@ -969,6 +969,7 @@ pub const ExternOptions = struct { |
| 969 | 969 | library_name: ?[]const u8 = null, |
| 970 | 970 | linkage: GlobalLinkage = .strong, |
| 971 | 971 | is_thread_local: bool = false, |
| 972 | is_dll_import: bool = false, | |
| 972 | 973 | }; |
| 973 | 974 | |
| 974 | 975 | /// This data structure is used by the Zig language code generation and |
src/InternPool.zig+9-2| ... | ... | @@ -2054,6 +2054,7 @@ pub const Key = union(enum) { |
| 2054 | 2054 | is_const: bool, |
| 2055 | 2055 | is_threadlocal: bool, |
| 2056 | 2056 | is_weak_linkage: bool, |
| 2057 | is_dll_import: bool, | |
| 2057 | 2058 | alignment: Alignment, |
| 2058 | 2059 | @"addrspace": std.builtin.AddressSpace, |
| 2059 | 2060 | /// The ZIR instruction which created this extern; used only for source locations. |
| ... | ... | @@ -2675,7 +2676,8 @@ pub const Key = union(enum) { |
| 2675 | 2676 | asBytes(&e.ty) ++ asBytes(&e.lib_name) ++ |
| 2676 | 2677 | asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++ |
| 2677 | 2678 | asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++ |
| 2678 | asBytes(&e.@"addrspace") ++ asBytes(&e.zir_index)), | |
| 2679 | asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++ | |
| 2680 | asBytes(&e.zir_index)), | |
| 2679 | 2681 | }; |
| 2680 | 2682 | } |
| 2681 | 2683 | |
| ... | ... | @@ -2771,6 +2773,7 @@ pub const Key = union(enum) { |
| 2771 | 2773 | a_info.is_const == b_info.is_const and |
| 2772 | 2774 | a_info.is_threadlocal == b_info.is_threadlocal and |
| 2773 | 2775 | a_info.is_weak_linkage == b_info.is_weak_linkage and |
| 2776 | a_info.is_dll_import == b_info.is_dll_import and | |
| 2774 | 2777 | a_info.alignment == b_info.alignment and |
| 2775 | 2778 | a_info.@"addrspace" == b_info.@"addrspace" and |
| 2776 | 2779 | a_info.zir_index == b_info.zir_index; |
| ... | ... | @@ -5370,7 +5373,8 @@ pub const Tag = enum(u8) { |
| 5370 | 5373 | is_const: bool, |
| 5371 | 5374 | is_threadlocal: bool, |
| 5372 | 5375 | is_weak_linkage: bool, |
| 5373 | _: u29 = 0, | |
| 5376 | is_dll_import: bool, | |
| 5377 | _: u28 = 0, | |
| 5374 | 5378 | }; |
| 5375 | 5379 | }; |
| 5376 | 5380 | |
| ... | ... | @@ -6714,6 +6718,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6714 | 6718 | .is_const = extra.flags.is_const, |
| 6715 | 6719 | .is_threadlocal = extra.flags.is_threadlocal, |
| 6716 | 6720 | .is_weak_linkage = extra.flags.is_weak_linkage, |
| 6721 | .is_dll_import = extra.flags.is_dll_import, | |
| 6717 | 6722 | .alignment = nav.status.resolved.alignment, |
| 6718 | 6723 | .@"addrspace" = nav.status.resolved.@"addrspace", |
| 6719 | 6724 | .zir_index = extra.zir_index, |
| ... | ... | @@ -7380,6 +7385,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All |
| 7380 | 7385 | .is_const = false, |
| 7381 | 7386 | .is_threadlocal = variable.is_threadlocal, |
| 7382 | 7387 | .is_weak_linkage = variable.is_weak_linkage, |
| 7388 | .is_dll_import = false, | |
| 7383 | 7389 | }, |
| 7384 | 7390 | }), |
| 7385 | 7391 | }); |
| ... | ... | @@ -8643,6 +8649,7 @@ pub fn getExtern( |
| 8643 | 8649 | .is_const = key.is_const, |
| 8644 | 8650 | .is_threadlocal = key.is_threadlocal, |
| 8645 | 8651 | .is_weak_linkage = key.is_weak_linkage, |
| 8652 | .is_dll_import = key.is_dll_import, | |
| 8646 | 8653 | }, |
| 8647 | 8654 | .zir_index = key.zir_index, |
| 8648 | 8655 | .owner_nav = owner_nav, |
src/Sema.zig+22-1| ... | ... | @@ -876,6 +876,7 @@ const InferredAlloc = struct { |
| 876 | 876 | |
| 877 | 877 | const NeededComptimeReason = struct { |
| 878 | 878 | needed_comptime_reason: []const u8, |
| 879 | value_comptime_reason: ?[]const u8 = null, | |
| 879 | 880 | block_comptime_reason: ?*const Block.ComptimeReason = null, |
| 880 | 881 | }; |
| 881 | 882 | |
| ... | ... | @@ -2246,7 +2247,7 @@ fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Val |
| 2246 | 2247 | } |
| 2247 | 2248 | }; |
| 2248 | 2249 | const val = Value.fromInterned(ip_index); |
| 2249 | if (val.isPtrToThreadLocal(pt.zcu)) return null; | |
| 2250 | if (val.isPtrRuntimeValue(pt.zcu)) return null; | |
| 2250 | 2251 | return val; |
| 2251 | 2252 | } |
| 2252 | 2253 | |
| ... | ... | @@ -2272,8 +2273,14 @@ pub fn resolveFinalDeclValue( |
| 2272 | 2273 | const zcu = sema.pt.zcu; |
| 2273 | 2274 | |
| 2274 | 2275 | const val = try sema.resolveValueAllowVariables(air_ref) orelse { |
| 2276 | const value_comptime_reason: ?[]const u8 = if (air_ref.toInterned()) |_| | |
| 2277 | "thread local and dll imported variables have runtime-known addresses" | |
| 2278 | else | |
| 2279 | null; | |
| 2280 | ||
| 2275 | 2281 | return sema.failWithNeededComptime(block, src, .{ |
| 2276 | 2282 | .needed_comptime_reason = "global variable initializer must be comptime-known", |
| 2283 | .value_comptime_reason = value_comptime_reason, | |
| 2277 | 2284 | }); |
| 2278 | 2285 | }; |
| 2279 | 2286 | if (val.isGenericPoison()) return error.GenericPoison; |
| ... | ... | @@ -2291,6 +2298,9 @@ fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: N |
| 2291 | 2298 | const msg = try sema.errMsg(src, "unable to resolve comptime value", .{}); |
| 2292 | 2299 | errdefer msg.destroy(sema.gpa); |
| 2293 | 2300 | try sema.errNote(src, msg, "{s}", .{reason.needed_comptime_reason}); |
| 2301 | if (reason.value_comptime_reason) |value_comptime_reason| { | |
| 2302 | try sema.errNote(src, msg, "{s}", .{value_comptime_reason}); | |
| 2303 | } | |
| 2294 | 2304 | |
| 2295 | 2305 | if (reason.block_comptime_reason) |block_comptime_reason| { |
| 2296 | 2306 | try block_comptime_reason.explain(sema, msg); |
| ... | ... | @@ -10023,6 +10033,7 @@ fn funcCommon( |
| 10023 | 10033 | .is_const = true, |
| 10024 | 10034 | .is_threadlocal = false, |
| 10025 | 10035 | .is_weak_linkage = false, |
| 10036 | .is_dll_import = false, | |
| 10026 | 10037 | .alignment = alignment orelse .none, |
| 10027 | 10038 | .@"addrspace" = address_space orelse .generic, |
| 10028 | 10039 | .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction |
| ... | ... | @@ -26577,6 +26588,7 @@ fn zirVarExtended( |
| 26577 | 26588 | .is_const = small.is_const, |
| 26578 | 26589 | .is_threadlocal = small.is_threadlocal, |
| 26579 | 26590 | .is_weak_linkage = false, |
| 26591 | .is_dll_import = false, | |
| 26580 | 26592 | .alignment = alignment, |
| 26581 | 26593 | .@"addrspace" = @"addrspace", |
| 26582 | 26594 | .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction |
| ... | ... | @@ -27030,6 +27042,7 @@ fn resolveExternOptions( |
| 27030 | 27042 | library_name: InternPool.OptionalNullTerminatedString = .none, |
| 27031 | 27043 | linkage: std.builtin.GlobalLinkage = .strong, |
| 27032 | 27044 | is_thread_local: bool = false, |
| 27045 | is_dll_import: bool = false, | |
| 27033 | 27046 | } { |
| 27034 | 27047 | const pt = sema.pt; |
| 27035 | 27048 | const zcu = pt.zcu; |
| ... | ... | @@ -27043,6 +27056,7 @@ fn resolveExternOptions( |
| 27043 | 27056 | const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node }); |
| 27044 | 27057 | const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node }); |
| 27045 | 27058 | const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node }); |
| 27059 | const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node }); | |
| 27046 | 27060 | |
| 27047 | 27061 | const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src); |
| 27048 | 27062 | const name = try sema.toConstString(block, name_src, name_ref, .{ |
| ... | ... | @@ -27076,6 +27090,11 @@ fn resolveExternOptions( |
| 27076 | 27090 | break :library_name library_name; |
| 27077 | 27091 | } else null; |
| 27078 | 27092 | |
| 27093 | const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src); | |
| 27094 | const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ | |
| 27095 | .needed_comptime_reason = "it must be comptime-known if the symbol is imported from a dll", | |
| 27096 | }); | |
| 27097 | ||
| 27079 | 27098 | if (name.len == 0) { |
| 27080 | 27099 | return sema.fail(block, name_src, "extern symbol name cannot be empty", .{}); |
| 27081 | 27100 | } |
| ... | ... | @@ -27089,6 +27108,7 @@ fn resolveExternOptions( |
| 27089 | 27108 | .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls), |
| 27090 | 27109 | .linkage = linkage, |
| 27091 | 27110 | .is_thread_local = is_thread_local_val.toBool(), |
| 27111 | .is_dll_import = is_dll_import_val.toBool(), | |
| 27092 | 27112 | }; |
| 27093 | 27113 | } |
| 27094 | 27114 | |
| ... | ... | @@ -27134,6 +27154,7 @@ fn zirBuiltinExtern( |
| 27134 | 27154 | .is_const = ptr_info.flags.is_const, |
| 27135 | 27155 | .is_threadlocal = options.is_thread_local, |
| 27136 | 27156 | .is_weak_linkage = options.linkage == .weak, |
| 27157 | .is_dll_import = options.is_dll_import, | |
| 27137 | 27158 | .alignment = ptr_info.flags.alignment, |
| 27138 | 27159 | .@"addrspace" = ptr_info.flags.address_space, |
| 27139 | 27160 | // This instruction is just for source locations. |
src/Value.zig+2-2| ... | ... | @@ -1340,11 +1340,11 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool { |
| 1340 | 1340 | }; |
| 1341 | 1341 | } |
| 1342 | 1342 | |
| 1343 | pub fn isPtrToThreadLocal(val: Value, zcu: *Zcu) bool { | |
| 1343 | pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool { | |
| 1344 | 1344 | const ip = &zcu.intern_pool; |
| 1345 | 1345 | const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false; |
| 1346 | 1346 | return switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) { |
| 1347 | .@"extern" => |e| e.is_threadlocal, | |
| 1347 | .@"extern" => |e| e.is_threadlocal or e.is_dll_import, | |
| 1348 | 1348 | .variable => |v| v.is_threadlocal, |
| 1349 | 1349 | else => false, |
| 1350 | 1350 | }; |
src/Zcu.zig+3| ... | ... | @@ -1522,6 +1522,7 @@ pub const SrcLoc = struct { |
| 1522 | 1522 | .init_field_cache, |
| 1523 | 1523 | .init_field_library, |
| 1524 | 1524 | .init_field_thread_local, |
| 1525 | .init_field_dll_import, | |
| 1525 | 1526 | => |builtin_call_node| { |
| 1526 | 1527 | const wanted = switch (src_loc.lazy) { |
| 1527 | 1528 | .init_field_name => "name", |
| ... | ... | @@ -1533,6 +1534,7 @@ pub const SrcLoc = struct { |
| 1533 | 1534 | .init_field_cache => "cache", |
| 1534 | 1535 | .init_field_library => "library", |
| 1535 | 1536 | .init_field_thread_local => "thread_local", |
| 1537 | .init_field_dll_import => "dll_import", | |
| 1536 | 1538 | else => unreachable, |
| 1537 | 1539 | }; |
| 1538 | 1540 | const tree = try src_loc.file_scope.getTree(gpa); |
| ... | ... | @@ -1959,6 +1961,7 @@ pub const LazySrcLoc = struct { |
| 1959 | 1961 | init_field_cache: i32, |
| 1960 | 1962 | init_field_library: i32, |
| 1961 | 1963 | init_field_thread_local: i32, |
| 1964 | init_field_dll_import: i32, | |
| 1962 | 1965 | /// The source location points to the value of an item in a specific |
| 1963 | 1966 | /// case of a `switch`. |
| 1964 | 1967 | switch_case_item: SwitchItem, |
src/Zcu/PerThread.zig+1| ... | ... | @@ -2763,6 +2763,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V |
| 2763 | 2763 | .is_const = e.is_const, |
| 2764 | 2764 | .is_threadlocal = e.is_threadlocal, |
| 2765 | 2765 | .is_weak_linkage = e.is_weak_linkage, |
| 2766 | .is_dll_import = e.is_dll_import, | |
| 2766 | 2767 | .alignment = e.alignment, |
| 2767 | 2768 | .@"addrspace" = e.@"addrspace", |
| 2768 | 2769 | .zir_index = e.zir_index, |
src/codegen/llvm.zig+13-9| ... | ... | @@ -3260,10 +3260,10 @@ pub const Object = struct { |
| 3260 | 3260 | const ip = &zcu.intern_pool; |
| 3261 | 3261 | const nav = ip.getNav(nav_index); |
| 3262 | 3262 | const resolved = nav.status.resolved; |
| 3263 | const is_extern, const is_threadlocal, const is_weak_linkage = switch (ip.indexToKey(resolved.val)) { | |
| 3264 | .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage }, | |
| 3265 | .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage }, | |
| 3266 | else => .{ false, false, false }, | |
| 3263 | const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (ip.indexToKey(resolved.val)) { | |
| 3264 | .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false }, | |
| 3265 | .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import }, | |
| 3266 | else => .{ false, false, false, false }, | |
| 3267 | 3267 | }; |
| 3268 | 3268 | |
| 3269 | 3269 | const variable_index = try o.builder.addVariable( |
| ... | ... | @@ -3280,6 +3280,7 @@ pub const Object = struct { |
| 3280 | 3280 | if (is_threadlocal and !zcu.navFileScope(nav_index).mod.single_threaded) |
| 3281 | 3281 | variable_index.setThreadLocal(.generaldynamic, &o.builder); |
| 3282 | 3282 | if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder); |
| 3283 | if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder); | |
| 3283 | 3284 | } else { |
| 3284 | 3285 | variable_index.setLinkage(.internal, &o.builder); |
| 3285 | 3286 | variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); |
| ... | ... | @@ -4810,10 +4811,10 @@ pub const NavGen = struct { |
| 4810 | 4811 | const nav = ip.getNav(nav_index); |
| 4811 | 4812 | const resolved = nav.status.resolved; |
| 4812 | 4813 | |
| 4813 | const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) { | |
| 4814 | .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, variable.init, variable.owner_nav }, | |
| 4815 | .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_const, .none, @"extern".owner_nav }, | |
| 4816 | else => .{ false, .none, false, false, true, resolved.val, nav_index }, | |
| 4814 | const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) { | |
| 4815 | .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav }, | |
| 4816 | .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav }, | |
| 4817 | else => .{ false, .none, false, false, false, true, resolved.val, nav_index }, | |
| 4817 | 4818 | }; |
| 4818 | 4819 | const ty = Type.fromInterned(nav.typeOf(ip)); |
| 4819 | 4820 | |
| ... | ... | @@ -4888,8 +4889,11 @@ pub const NavGen = struct { |
| 4888 | 4889 | try global_index.rename(decl_name, &o.builder); |
| 4889 | 4890 | global_index.setLinkage(.external, &o.builder); |
| 4890 | 4891 | global_index.setUnnamedAddr(.default, &o.builder); |
| 4891 | if (zcu.comp.config.dll_export_fns) | |
| 4892 | if (is_dll_import) { | |
| 4893 | global_index.setDllStorageClass(.dllimport, &o.builder); | |
| 4894 | } else if (zcu.comp.config.dll_export_fns) { | |
| 4892 | 4895 | global_index.setDllStorageClass(.default, &o.builder); |
| 4896 | } | |
| 4893 | 4897 | |
| 4894 | 4898 | if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder); |
| 4895 | 4899 | } |
src/codegen/llvm/Builder.zig+4| ... | ... | @@ -2541,6 +2541,10 @@ pub const Variable = struct { |
| 2541 | 2541 | return self.ptrConst(builder).global.setLinkage(linkage, builder); |
| 2542 | 2542 | } |
| 2543 | 2543 | |
| 2544 | pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void { | |
| 2545 | return self.ptrConst(builder).global.setDllStorageClass(class, builder); | |
| 2546 | } | |
| 2547 | ||
| 2544 | 2548 | pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void { |
| 2545 | 2549 | return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder); |
| 2546 | 2550 | } |
test/cases/compile_errors/builtin_extern_in_comptime_scope.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const foo_tl = @extern(*i32, .{ .name = "foo", .is_thread_local = true }); | |
| 2 | const foo_dll = @extern(*i32, .{ .name = "foo", .is_dll_import = true }); | |
| 3 | pub export fn entry() void { | |
| 4 | _ = foo_tl; | |
| 5 | } | |
| 6 | pub export fn entry2() void { | |
| 7 | _ = foo_dll; | |
| 8 | } | |
| 9 | // error | |
| 10 | // backend=stage2 | |
| 11 | // target=native | |
| 12 | // | |
| 13 | // :1:16: error: unable to resolve comptime value | |
| 14 | // :1:16: note: global variable initializer must be comptime-known | |
| 15 | // :1:16: note: thread local and dll imported variables have runtime-known addresses | |
| 16 | // :2:17: error: unable to resolve comptime value | |
| 17 | // :2:17: note: global variable initializer must be comptime-known | |
| 18 | // :2:17: note: thread local and dll imported variables have runtime-known addresses |
test/standalone/extern/build.zig+15-4| ... | ... | @@ -1,6 +1,9 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn build(b: *std.Build) void { |
| 4 | const test_step = b.step("test", "Test it"); | |
| 5 | b.default_step = test_step; | |
| 6 | ||
| 4 | 7 | const optimize: std.builtin.OptimizeMode = .Debug; |
| 5 | 8 | |
| 6 | 9 | const obj = b.addObject(.{ |
| ... | ... | @@ -9,12 +12,20 @@ pub fn build(b: *std.Build) void { |
| 9 | 12 | .target = b.graph.host, |
| 10 | 13 | .optimize = optimize, |
| 11 | 14 | }); |
| 12 | const main = b.addTest(.{ | |
| 15 | const shared = b.addSharedLibrary(.{ | |
| 16 | .name = "shared", | |
| 17 | .target = b.graph.host, | |
| 18 | .optimize = optimize, | |
| 19 | .link_libc = true, | |
| 20 | }); | |
| 21 | if (b.graph.host.result.abi == .msvc) shared.defineCMacro("API", "__declspec(dllexport)"); | |
| 22 | shared.addCSourceFile(.{ .file = b.path("shared.c"), .flags = &.{} }); | |
| 23 | const test_exe = b.addTest(.{ | |
| 13 | 24 | .root_source_file = b.path("main.zig"), |
| 14 | 25 | .optimize = optimize, |
| 15 | 26 | }); |
| 16 | main.addObject(obj); | |
| 27 | test_exe.addObject(obj); | |
| 28 | test_exe.linkLibrary(shared); | |
| 17 | 29 | |
| 18 | const test_step = b.step("test", "Test it"); | |
| 19 | test_step.dependOn(&main.step); | |
| 30 | test_step.dependOn(&b.addRunArtifact(test_exe).step); | |
| 20 | 31 | } |
test/standalone/extern/main.zig+6-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const assert = @import("std").debug.assert; |
| 2 | const testing = @import("std").testing; | |
| 2 | 3 | |
| 3 | 4 | const updateHidden = @extern(*const fn (u32) callconv(.C) void, .{ .name = "updateHidden" }); |
| 4 | 5 | const getHidden = @extern(*const fn () callconv(.C) u32, .{ .name = "getHidden" }); |
| ... | ... | @@ -8,14 +9,18 @@ const T = extern struct { x: u32 }; |
| 8 | 9 | test { |
| 9 | 10 | const mut_val_ptr = @extern(*f64, .{ .name = "mut_val" }); |
| 10 | 11 | const const_val_ptr = @extern(*const T, .{ .name = "const_val" }); |
| 12 | const shared_val_ptr = @extern(*c_int, .{ .name = "shared_val", .is_dll_import = true }); | |
| 11 | 13 | |
| 12 | 14 | assert(getHidden() == 0); |
| 13 | 15 | updateHidden(123); |
| 14 | 16 | assert(getHidden() == 123); |
| 15 | ||
| 16 | 17 | assert(mut_val_ptr.* == 1.23); |
| 17 | 18 | mut_val_ptr.* = 10.0; |
| 18 | 19 | assert(mut_val_ptr.* == 10.0); |
| 19 | 20 | |
| 20 | 21 | assert(const_val_ptr.x == 42); |
| 22 | ||
| 23 | assert(shared_val_ptr.* == 1234); | |
| 24 | shared_val_ptr.* = 1235; | |
| 25 | assert(shared_val_ptr.* == 1235); | |
| 21 | 26 | } |
test/standalone/extern/shared.c created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | #ifndef API | |
| 2 | #define API | |
| 3 | #endif | |
| 4 | ||
| 5 | API int shared_val = 1234; |