authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-15 10:58:40+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:40+01:00
logabeb0e3ea41888dd2f4ac04ae335927aba2e7b07
treea6c521d1a62a922abe1fed06f02f655d5afa757f
parent7c65f0be375c7e4f0d2ecdc846ae5e9b49cf2737

test/link/macho: test force-loading objects containing ObjC from archives


3 files changed, 75 insertions(+), 98 deletions(-)

src/link/MachO.zig+4-1
...@@ -116,6 +116,9 @@ platform: Platform,...@@ -116,6 +116,9 @@ platform: Platform,
116sdk_version: ?std.SemanticVersion,116sdk_version: ?std.SemanticVersion,
117/// When set to true, the linker will hoist all dylibs including system dependent dylibs.117/// When set to true, the linker will hoist all dylibs including system dependent dylibs.
118no_implicit_dylibs: bool = false,118no_implicit_dylibs: bool = false,
119/// Whether the linker should parse and always force load objects containing ObjC in archives.
120// TODO: in Zig we currently take -ObjC as always on
121force_load_objc: bool = true,
119122
120/// Hot-code swapping state.123/// Hot-code swapping state.
121hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},124hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
...@@ -998,7 +1001,7 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar...@@ -998,7 +1001,7 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
9981001
999 // Finally, we do a post-parse check for -ObjC to see if we need to force load this member1002 // Finally, we do a post-parse check for -ObjC to see if we need to force load this member
1000 // anyhow.1003 // anyhow.
1001 // TODO: object.alive = object.alive or (self.options.force_load_objc and object.hasObjc());1004 object.alive = object.alive or (self.force_load_objc and object.hasObjc());
1002 }1005 }
1003 if (has_parse_error) return error.MalformedArchive;1006 if (has_parse_error) return error.MalformedArchive;
1004}1007}
test/link/link.zig+42-97
...@@ -46,121 +46,66 @@ const OverlayOptions = struct {...@@ -46,121 +46,66 @@ const OverlayOptions = struct {
46 c_source_flags: []const []const u8 = &.{},46 c_source_flags: []const []const u8 = &.{},
47 cpp_source_bytes: ?[]const u8 = null,47 cpp_source_bytes: ?[]const u8 = null,
48 cpp_source_flags: []const []const u8 = &.{},48 cpp_source_flags: []const []const u8 = &.{},
49 objc_source_bytes: ?[]const u8 = null,
50 objc_source_flags: []const []const u8 = &.{},
49 zig_source_bytes: ?[]const u8 = null,51 zig_source_bytes: ?[]const u8 = null,
50 pic: ?bool = null,52 pic: ?bool = null,
51 strip: ?bool = null,53 strip: ?bool = null,
52};54};
5355
54pub fn addExecutable(b: *std.Build, base: Options, overlay: OverlayOptions) *Step.Compile {56pub fn addExecutable(b: *std.Build, base: Options, overlay: OverlayOptions) *Compile {
55 const compile_step = b.addExecutable(.{57 return addCompileStep(b, base, overlay, .exe);
56 .name = overlay.name,
57 .root_source_file = rsf: {
58 const bytes = overlay.zig_source_bytes orelse break :rsf null;
59 break :rsf b.addWriteFiles().add("a.zig", bytes);
60 },
61 .target = base.target,
62 .optimize = base.optimize,
63 .use_llvm = base.use_llvm,
64 .use_lld = base.use_lld,
65 .pic = overlay.pic,
66 .strip = overlay.strip,
67 });
68 if (overlay.cpp_source_bytes) |bytes| {
69 compile_step.addCSourceFile(.{
70 .file = b.addWriteFiles().add("a.cpp", bytes),
71 .flags = overlay.cpp_source_flags,
72 });
73 }
74 if (overlay.c_source_bytes) |bytes| {
75 compile_step.addCSourceFile(.{
76 .file = b.addWriteFiles().add("a.c", bytes),
77 .flags = overlay.c_source_flags,
78 });
79 }
80 if (overlay.asm_source_bytes) |bytes| {
81 compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes));
82 }
83 return compile_step;
84}58}
8559
86pub fn addObject(b: *Build, base: Options, overlay: OverlayOptions) *Step.Compile {60pub fn addObject(b: *Build, base: Options, overlay: OverlayOptions) *Compile {
87 const compile_step = b.addObject(.{61 return addCompileStep(b, base, overlay, .obj);
88 .name = overlay.name,
89 .root_source_file = rsf: {
90 const bytes = overlay.zig_source_bytes orelse break :rsf null;
91 break :rsf b.addWriteFiles().add("a.zig", bytes);
92 },
93 .target = base.target,
94 .optimize = base.optimize,
95 .use_llvm = base.use_llvm,
96 .use_lld = base.use_lld,
97 .pic = overlay.pic,
98 .strip = overlay.strip,
99 });
100 if (overlay.cpp_source_bytes) |bytes| {
101 compile_step.addCSourceFile(.{
102 .file = b.addWriteFiles().add("a.cpp", bytes),
103 .flags = overlay.cpp_source_flags,
104 });
105 }
106 if (overlay.c_source_bytes) |bytes| {
107 compile_step.addCSourceFile(.{
108 .file = b.addWriteFiles().add("a.c", bytes),
109 .flags = overlay.c_source_flags,
110 });
111 }
112 if (overlay.asm_source_bytes) |bytes| {
113 compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes));
114 }
115 return compile_step;
116}62}
11763
118pub fn addStaticLibrary(b: *Build, base: Options, overlay: OverlayOptions) *Compile {64pub fn addStaticLibrary(b: *Build, base: Options, overlay: OverlayOptions) *Compile {
119 const compile_step = b.addStaticLibrary(.{65 return addCompileStep(b, base, overlay, .static_lib);
120 .name = overlay.name,
121 .root_source_file = rsf: {
122 const bytes = overlay.zig_source_bytes orelse break :rsf null;
123 break :rsf b.addWriteFiles().add("a.zig", bytes);
124 },
125 .target = base.target,
126 .optimize = base.optimize,
127 .use_llvm = base.use_llvm,
128 .use_lld = base.use_lld,
129 .pic = overlay.pic,
130 .strip = overlay.strip,
131 });
132 if (overlay.cpp_source_bytes) |bytes| {
133 compile_step.addCSourceFile(.{
134 .file = b.addWriteFiles().add("a.cpp", bytes),
135 .flags = overlay.cpp_source_flags,
136 });
137 }
138 if (overlay.c_source_bytes) |bytes| {
139 compile_step.addCSourceFile(.{
140 .file = b.addWriteFiles().add("a.c", bytes),
141 .flags = overlay.c_source_flags,
142 });
143 }
144 if (overlay.asm_source_bytes) |bytes| {
145 compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes));
146 }
147 return compile_step;
148}66}
14967
150pub fn addSharedLibrary(b: *Build, base: Options, overlay: OverlayOptions) *Compile {68pub fn addSharedLibrary(b: *Build, base: Options, overlay: OverlayOptions) *Compile {
151 const compile_step = b.addSharedLibrary(.{69 return addCompileStep(b, base, overlay, .shared_lib);
70}
71
72fn addCompileStep(
73 b: *Build,
74 base: Options,
75 overlay: OverlayOptions,
76 kind: enum { exe, obj, shared_lib, static_lib },
77) *Compile {
78 const compile_step = Compile.create(b, .{
152 .name = overlay.name,79 .name = overlay.name,
153 .root_source_file = rsf: {80 .root_module = .{
154 const bytes = overlay.zig_source_bytes orelse break :rsf null;81 .target = base.target,
155 break :rsf b.addWriteFiles().add("a.zig", bytes);82 .optimize = base.optimize,
83 .root_source_file = rsf: {
84 const bytes = overlay.zig_source_bytes orelse break :rsf null;
85 break :rsf b.addWriteFiles().add("a.zig", bytes);
86 },
87 .pic = overlay.pic,
88 .strip = overlay.strip,
156 },89 },
157 .target = base.target,
158 .optimize = base.optimize,
159 .use_llvm = base.use_llvm,90 .use_llvm = base.use_llvm,
160 .use_lld = base.use_lld,91 .use_lld = base.use_lld,
161 .pic = overlay.pic,92 .kind = switch (kind) {
162 .strip = overlay.strip,93 .exe => .exe,
94 .obj => .obj,
95 .shared_lib, .static_lib => .lib,
96 },
97 .linkage = switch (kind) {
98 .exe, .obj => null,
99 .shared_lib => .dynamic,
100 .static_lib => .static,
101 },
163 });102 });
103 if (overlay.objc_source_bytes) |bytes| {
104 compile_step.addCSourceFile(.{
105 .file = b.addWriteFiles().add("a.m", bytes),
106 .flags = overlay.objc_source_flags,
107 });
108 }
164 if (overlay.cpp_source_bytes) |bytes| {109 if (overlay.cpp_source_bytes) |bytes| {
165 compile_step.addCSourceFile(.{110 compile_step.addCSourceFile(.{
166 .file = b.addWriteFiles().add("a.cpp", bytes),111 .file = b.addWriteFiles().add("a.cpp", bytes),
test/link/macho.zig+29
...@@ -52,6 +52,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -52,6 +52,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
52 macho_step.dependOn(testDeadStripDylibs(b, .{ .target = b.host }));52 macho_step.dependOn(testDeadStripDylibs(b, .{ .target = b.host }));
53 macho_step.dependOn(testHeaderpad(b, .{ .target = b.host }));53 macho_step.dependOn(testHeaderpad(b, .{ .target = b.host }));
54 macho_step.dependOn(testNeededFramework(b, .{ .target = b.host }));54 macho_step.dependOn(testNeededFramework(b, .{ .target = b.host }));
55 macho_step.dependOn(testObjc(b, .{ .target = b.host }));
55 macho_step.dependOn(testWeakFramework(b, .{ .target = b.host }));56 macho_step.dependOn(testWeakFramework(b, .{ .target = b.host }));
56 }57 }
57 }58 }
...@@ -830,6 +831,34 @@ fn testNeededLibrary(b: *Build, opts: Options) *Step {...@@ -830,6 +831,34 @@ fn testNeededLibrary(b: *Build, opts: Options) *Step {
830 return test_step;831 return test_step;
831}832}
832833
834fn testObjc(b: *Build, opts: Options) *Step {
835 const test_step = addTestStep(b, "macho-objc", opts);
836
837 const lib = addStaticLibrary(b, opts, .{ .name = "a", .objc_source_bytes =
838 \\#import <Foundation/Foundation.h>
839 \\@interface Foo : NSObject
840 \\@end
841 \\@implementation Foo
842 \\@end
843 });
844
845 const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
846 exe.root_module.linkSystemLibrary("a", .{});
847 exe.root_module.linkFramework("Foundation", .{});
848 exe.addLibraryPath(lib.getEmittedBinDirectory());
849
850 const check = exe.checkObject();
851 check.checkInSymtab();
852 check.checkContains("_OBJC_");
853 test_step.dependOn(&check.step);
854
855 const run = addRunArtifact(exe);
856 run.expectExitCode(0);
857 test_step.dependOn(&run.step);
858
859 return test_step;
860}
861
833fn testRelocatable(b: *Build, opts: Options) *Step {862fn testRelocatable(b: *Build, opts: Options) *Step {
834 const test_step = addTestStep(b, "macho-relocatable", opts);863 const test_step = addTestStep(b, "macho-relocatable", opts);
835864