diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-15 10:58:40 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-24 12:34:40 +0100 |
| commit | abeb0e3ea41888dd2f4ac04ae335927aba2e7b07 (patch) | |
| tree | a6c521d1a62a922abe1fed06f02f655d5afa757f | |
| parent | 7c65f0be375c7e4f0d2ecdc846ae5e9b49cf2737 (diff) | |
| download | zig-abeb0e3ea41888dd2f4ac04ae335927aba2e7b07.tar.gz zig-abeb0e3ea41888dd2f4ac04ae335927aba2e7b07.zip | |
test/link/macho: test force-loading objects containing ObjC from archives
| -rw-r--r-- | src/link/MachO.zig | 5 | ||||
| -rw-r--r-- | test/link/link.zig | 139 | ||||
| -rw-r--r-- | test/link/macho.zig | 29 |
3 files changed, 75 insertions, 98 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index cbc0c8ec65..8d959275aa 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -116,6 +116,9 @@ platform: Platform, sdk_version: ?std.SemanticVersion, /// When set to true, the linker will hoist all dylibs including system dependent dylibs. no_implicit_dylibs: bool = false, +/// Whether the linker should parse and always force load objects containing ObjC in archives. +// TODO: in Zig we currently take -ObjC as always on +force_load_objc: bool = true, /// Hot-code swapping state. hot_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 // Finally, we do a post-parse check for -ObjC to see if we need to force load this member // anyhow. - // TODO: object.alive = object.alive or (self.options.force_load_objc and object.hasObjc()); + object.alive = object.alive or (self.force_load_objc and object.hasObjc()); } if (has_parse_error) return error.MalformedArchive; } diff --git a/test/link/link.zig b/test/link/link.zig index c17f8b0b5a..8ef497424f 100644 --- a/test/link/link.zig +++ b/test/link/link.zig @@ -46,121 +46,66 @@ const OverlayOptions = struct { c_source_flags: []const []const u8 = &.{}, cpp_source_bytes: ?[]const u8 = null, cpp_source_flags: []const []const u8 = &.{}, + objc_source_bytes: ?[]const u8 = null, + objc_source_flags: []const []const u8 = &.{}, zig_source_bytes: ?[]const u8 = null, pic: ?bool = null, strip: ?bool = null, }; -pub fn addExecutable(b: *std.Build, base: Options, overlay: OverlayOptions) *Step.Compile { - const compile_step = b.addExecutable(.{ - .name = overlay.name, - .root_source_file = rsf: { - const bytes = overlay.zig_source_bytes orelse break :rsf null; - break :rsf b.addWriteFiles().add("a.zig", bytes); - }, - .target = base.target, - .optimize = base.optimize, - .use_llvm = base.use_llvm, - .use_lld = base.use_lld, - .pic = overlay.pic, - .strip = overlay.strip, - }); - if (overlay.cpp_source_bytes) |bytes| { - compile_step.addCSourceFile(.{ - .file = b.addWriteFiles().add("a.cpp", bytes), - .flags = overlay.cpp_source_flags, - }); - } - if (overlay.c_source_bytes) |bytes| { - compile_step.addCSourceFile(.{ - .file = b.addWriteFiles().add("a.c", bytes), - .flags = overlay.c_source_flags, - }); - } - if (overlay.asm_source_bytes) |bytes| { - compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes)); - } - return compile_step; +pub fn addExecutable(b: *std.Build, base: Options, overlay: OverlayOptions) *Compile { + return addCompileStep(b, base, overlay, .exe); } -pub fn addObject(b: *Build, base: Options, overlay: OverlayOptions) *Step.Compile { - const compile_step = b.addObject(.{ - .name = overlay.name, - .root_source_file = rsf: { - const bytes = overlay.zig_source_bytes orelse break :rsf null; - break :rsf b.addWriteFiles().add("a.zig", bytes); - }, - .target = base.target, - .optimize = base.optimize, - .use_llvm = base.use_llvm, - .use_lld = base.use_lld, - .pic = overlay.pic, - .strip = overlay.strip, - }); - if (overlay.cpp_source_bytes) |bytes| { - compile_step.addCSourceFile(.{ - .file = b.addWriteFiles().add("a.cpp", bytes), - .flags = overlay.cpp_source_flags, - }); - } - if (overlay.c_source_bytes) |bytes| { - compile_step.addCSourceFile(.{ - .file = b.addWriteFiles().add("a.c", bytes), - .flags = overlay.c_source_flags, - }); - } - if (overlay.asm_source_bytes) |bytes| { - compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes)); - } - return compile_step; +pub fn addObject(b: *Build, base: Options, overlay: OverlayOptions) *Compile { + return addCompileStep(b, base, overlay, .obj); } pub fn addStaticLibrary(b: *Build, base: Options, overlay: OverlayOptions) *Compile { - const compile_step = b.addStaticLibrary(.{ - .name = overlay.name, - .root_source_file = rsf: { - const bytes = overlay.zig_source_bytes orelse break :rsf null; - break :rsf b.addWriteFiles().add("a.zig", bytes); - }, - .target = base.target, - .optimize = base.optimize, - .use_llvm = base.use_llvm, - .use_lld = base.use_lld, - .pic = overlay.pic, - .strip = overlay.strip, - }); - if (overlay.cpp_source_bytes) |bytes| { - compile_step.addCSourceFile(.{ - .file = b.addWriteFiles().add("a.cpp", bytes), - .flags = overlay.cpp_source_flags, - }); - } - if (overlay.c_source_bytes) |bytes| { - compile_step.addCSourceFile(.{ - .file = b.addWriteFiles().add("a.c", bytes), - .flags = overlay.c_source_flags, - }); - } - if (overlay.asm_source_bytes) |bytes| { - compile_step.addAssemblyFile(b.addWriteFiles().add("a.s", bytes)); - } - return compile_step; + return addCompileStep(b, base, overlay, .static_lib); } pub fn addSharedLibrary(b: *Build, base: Options, overlay: OverlayOptions) *Compile { - const compile_step = b.addSharedLibrary(.{ + return addCompileStep(b, base, overlay, .shared_lib); +} + +fn addCompileStep( + b: *Build, + base: Options, + overlay: OverlayOptions, + kind: enum { exe, obj, shared_lib, static_lib }, +) *Compile { + const compile_step = Compile.create(b, .{ .name = overlay.name, - .root_source_file = rsf: { - const bytes = overlay.zig_source_bytes orelse break :rsf null; - break :rsf b.addWriteFiles().add("a.zig", bytes); + .root_module = .{ + .target = base.target, + .optimize = base.optimize, + .root_source_file = rsf: { + const bytes = overlay.zig_source_bytes orelse break :rsf null; + break :rsf b.addWriteFiles().add("a.zig", bytes); + }, + .pic = overlay.pic, + .strip = overlay.strip, }, - .target = base.target, - .optimize = base.optimize, .use_llvm = base.use_llvm, .use_lld = base.use_lld, - .pic = overlay.pic, - .strip = overlay.strip, + .kind = switch (kind) { + .exe => .exe, + .obj => .obj, + .shared_lib, .static_lib => .lib, + }, + .linkage = switch (kind) { + .exe, .obj => null, + .shared_lib => .dynamic, + .static_lib => .static, + }, }); + if (overlay.objc_source_bytes) |bytes| { + compile_step.addCSourceFile(.{ + .file = b.addWriteFiles().add("a.m", bytes), + .flags = overlay.objc_source_flags, + }); + } if (overlay.cpp_source_bytes) |bytes| { compile_step.addCSourceFile(.{ .file = b.addWriteFiles().add("a.cpp", bytes), diff --git a/test/link/macho.zig b/test/link/macho.zig index 91f60246f2..9b63a9a5e9 100644 --- a/test/link/macho.zig +++ b/test/link/macho.zig @@ -52,6 +52,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { macho_step.dependOn(testDeadStripDylibs(b, .{ .target = b.host })); macho_step.dependOn(testHeaderpad(b, .{ .target = b.host })); macho_step.dependOn(testNeededFramework(b, .{ .target = b.host })); + macho_step.dependOn(testObjc(b, .{ .target = b.host })); macho_step.dependOn(testWeakFramework(b, .{ .target = b.host })); } } @@ -830,6 +831,34 @@ fn testNeededLibrary(b: *Build, opts: Options) *Step { return test_step; } +fn testObjc(b: *Build, opts: Options) *Step { + const test_step = addTestStep(b, "macho-objc", opts); + + const lib = addStaticLibrary(b, opts, .{ .name = "a", .objc_source_bytes = + \\#import <Foundation/Foundation.h> + \\@interface Foo : NSObject + \\@end + \\@implementation Foo + \\@end + }); + + const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); + exe.root_module.linkSystemLibrary("a", .{}); + exe.root_module.linkFramework("Foundation", .{}); + exe.addLibraryPath(lib.getEmittedBinDirectory()); + + const check = exe.checkObject(); + check.checkInSymtab(); + check.checkContains("_OBJC_"); + test_step.dependOn(&check.step); + + const run = addRunArtifact(exe); + run.expectExitCode(0); + test_step.dependOn(&run.step); + + return test_step; +} + fn testRelocatable(b: *Build, opts: Options) *Step { const test_step = addTestStep(b, "macho-relocatable", opts); |
