mirror of
https://github.com/ziglang/zig.git
synced 2026-02-09 11:03:30 +00:00
Merge pull request #11917 from motiejus/wl-search-paths
macho: implement `-search_paths_first` and `-search_dylibs_first`
This commit is contained in:
commit
0078d36ff3
@ -1586,6 +1586,13 @@ pub const LibExeObjStep = struct {
|
||||
/// (Darwin) Size of the pagezero segment.
|
||||
pagezero_size: ?u64 = null,
|
||||
|
||||
/// (Darwin) Search strategy for searching system libraries. Either `paths_first` or `dylibs_first`.
|
||||
/// The former lowers to `-search_paths_first` linker option, while the latter to `-search_dylibs_first`
|
||||
/// option.
|
||||
/// By default, if no option is specified, the linker assumes `paths_first` as the default
|
||||
/// search strategy.
|
||||
search_strategy: ?enum { paths_first, dylibs_first } = null,
|
||||
|
||||
/// Position Independent Code
|
||||
force_pic: ?bool = null,
|
||||
|
||||
@ -2650,6 +2657,10 @@ pub const LibExeObjStep = struct {
|
||||
const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{pagezero_size});
|
||||
try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
|
||||
}
|
||||
if (self.search_strategy) |strat| switch (strat) {
|
||||
.paths_first => try zig_args.append("-search_paths_first"),
|
||||
.dylibs_first => try zig_args.append("-search_dylibs_first"),
|
||||
};
|
||||
|
||||
if (self.bundle_compiler_rt) |x| {
|
||||
if (x) {
|
||||
|
||||
@ -905,6 +905,8 @@ pub const InitOptions = struct {
|
||||
entitlements: ?[]const u8 = null,
|
||||
/// (Darwin) size of the __PAGEZERO segment
|
||||
pagezero_size: ?u64 = null,
|
||||
/// (Darwin) search strategy for system libraries
|
||||
search_strategy: ?link.File.MachO.SearchStrategy = null,
|
||||
};
|
||||
|
||||
fn addPackageTableToCacheHash(
|
||||
@ -1745,6 +1747,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
||||
.install_name = options.install_name,
|
||||
.entitlements = options.entitlements,
|
||||
.pagezero_size = options.pagezero_size,
|
||||
.search_strategy = options.search_strategy,
|
||||
});
|
||||
errdefer bin_file.destroy();
|
||||
comp.* = .{
|
||||
@ -2360,7 +2363,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo
|
||||
/// to remind the programmer to update multiple related pieces of code that
|
||||
/// are in different locations. Bump this number when adding or deleting
|
||||
/// anything from the link cache manifest.
|
||||
pub const link_hash_implementation_version = 4;
|
||||
pub const link_hash_implementation_version = 5;
|
||||
|
||||
fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
|
||||
const gpa = comp.gpa;
|
||||
@ -2370,7 +2373,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
comptime assert(link_hash_implementation_version == 4);
|
||||
comptime assert(link_hash_implementation_version == 5);
|
||||
|
||||
if (comp.bin_file.options.module) |mod| {
|
||||
const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{
|
||||
@ -2476,6 +2479,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
|
||||
man.hash.addListOfBytes(comp.bin_file.options.frameworks);
|
||||
try man.addOptionalFile(comp.bin_file.options.entitlements);
|
||||
man.hash.addOptional(comp.bin_file.options.pagezero_size);
|
||||
man.hash.addOptional(comp.bin_file.options.search_strategy);
|
||||
|
||||
// COFF specific stuff
|
||||
man.hash.addOptional(comp.bin_file.options.subsystem);
|
||||
|
||||
@ -190,6 +190,9 @@ pub const Options = struct {
|
||||
/// (Darwin) size of the __PAGEZERO segment
|
||||
pagezero_size: ?u64 = null,
|
||||
|
||||
/// (Darwin) search strategy for system libraries
|
||||
search_strategy: ?File.MachO.SearchStrategy = null,
|
||||
|
||||
pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
|
||||
return if (options.use_lld) .Obj else options.output_mode;
|
||||
}
|
||||
|
||||
@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
|
||||
man = comp.cache_parent.obtain();
|
||||
self.base.releaseLock();
|
||||
|
||||
comptime assert(Compilation.link_hash_implementation_version == 4);
|
||||
comptime assert(Compilation.link_hash_implementation_version == 5);
|
||||
|
||||
for (self.base.options.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
|
||||
@ -1298,7 +1298,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
|
||||
// We are about to obtain this lock, so here we give other processes a chance first.
|
||||
self.base.releaseLock();
|
||||
|
||||
comptime assert(Compilation.link_hash_implementation_version == 4);
|
||||
comptime assert(Compilation.link_hash_implementation_version == 5);
|
||||
|
||||
try man.addOptionalFile(self.base.options.linker_script);
|
||||
try man.addOptionalFile(self.base.options.version_script);
|
||||
|
||||
@ -47,6 +47,11 @@ pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
|
||||
|
||||
pub const base_tag: File.Tag = File.Tag.macho;
|
||||
|
||||
pub const SearchStrategy = enum {
|
||||
paths_first,
|
||||
dylibs_first,
|
||||
};
|
||||
|
||||
base: File,
|
||||
|
||||
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
|
||||
@ -536,7 +541,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
// We are about to obtain this lock, so here we give other processes a chance first.
|
||||
self.base.releaseLock();
|
||||
|
||||
comptime assert(Compilation.link_hash_implementation_version == 4);
|
||||
comptime assert(Compilation.link_hash_implementation_version == 5);
|
||||
|
||||
for (self.base.options.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
@ -550,6 +555,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
// installation sources because they are always a product of the compiler version + target information.
|
||||
man.hash.add(stack_size);
|
||||
man.hash.addOptional(self.base.options.pagezero_size);
|
||||
man.hash.addOptional(self.base.options.search_strategy);
|
||||
man.hash.addListOfBytes(self.base.options.lib_dirs);
|
||||
man.hash.addListOfBytes(self.base.options.framework_dirs);
|
||||
man.hash.addListOfBytes(self.base.options.frameworks);
|
||||
@ -784,18 +790,43 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
}
|
||||
|
||||
var libs = std.ArrayList([]const u8).init(arena);
|
||||
for (search_lib_names.items) |lib_name| {
|
||||
// Assume ld64 default: -search_paths_first
|
||||
// Look in each directory for a dylib (stub first), and then for archive
|
||||
// TODO implement alternative: -search_dylibs_first
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
|
||||
if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| {
|
||||
try libs.append(full_path);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
log.warn("library not found for '-l{s}'", .{lib_name});
|
||||
lib_not_found = true;
|
||||
|
||||
// Assume ld64 default -search_paths_first if no strategy specified.
|
||||
const search_strategy = self.base.options.search_strategy orelse .paths_first;
|
||||
outer: for (search_lib_names.items) |lib_name| {
|
||||
switch (search_strategy) {
|
||||
.paths_first => {
|
||||
// Look in each directory for a dylib (stub first), and then for archive
|
||||
for (lib_dirs.items) |dir| {
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
|
||||
if (try resolveLib(arena, dir, lib_name, ext)) |full_path| {
|
||||
try libs.append(full_path);
|
||||
continue :outer;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("library not found for '-l{s}'", .{lib_name});
|
||||
lib_not_found = true;
|
||||
}
|
||||
},
|
||||
.dylibs_first => {
|
||||
// First, look for a dylib in each search dir
|
||||
for (lib_dirs.items) |dir| {
|
||||
for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| {
|
||||
if (try resolveLib(arena, dir, lib_name, ext)) |full_path| {
|
||||
try libs.append(full_path);
|
||||
continue :outer;
|
||||
}
|
||||
}
|
||||
} else for (lib_dirs.items) |dir| {
|
||||
if (try resolveLib(arena, dir, lib_name, ".a")) |full_path| {
|
||||
try libs.append(full_path);
|
||||
} else {
|
||||
log.warn("library not found for '-l{s}'", .{lib_name});
|
||||
lib_not_found = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -811,19 +842,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
if (self.base.options.sysroot != null) blk: {
|
||||
// Try stub file first. If we hit it, then we're done as the stub file
|
||||
// re-exports every single symbol definition.
|
||||
if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| {
|
||||
try libs.append(full_path);
|
||||
libsystem_available = true;
|
||||
break :blk;
|
||||
for (lib_dirs.items) |dir| {
|
||||
if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| {
|
||||
try libs.append(full_path);
|
||||
libsystem_available = true;
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
// If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
|
||||
// doesn't export libc.dylib which we'll need to resolve subsequently also.
|
||||
if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| {
|
||||
if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| {
|
||||
try libs.append(libsystem_path);
|
||||
try libs.append(libc_path);
|
||||
libsystem_available = true;
|
||||
break :blk;
|
||||
for (lib_dirs.items) |dir| {
|
||||
if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| {
|
||||
if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| {
|
||||
try libs.append(libsystem_path);
|
||||
try libs.append(libc_path);
|
||||
libsystem_available = true;
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -847,11 +882,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
}
|
||||
}
|
||||
|
||||
for (self.base.options.frameworks) |framework| {
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
||||
if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| {
|
||||
try libs.append(full_path);
|
||||
break;
|
||||
outer: for (self.base.options.frameworks) |framework| {
|
||||
for (framework_dirs.items) |dir| {
|
||||
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
||||
if (try resolveFramework(arena, dir, framework, ext)) |full_path| {
|
||||
try libs.append(full_path);
|
||||
continue :outer;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.warn("framework not found for '-framework {s}'", .{framework});
|
||||
@ -934,12 +971,36 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size}));
|
||||
}
|
||||
|
||||
if (self.base.options.search_strategy) |strat| switch (strat) {
|
||||
.paths_first => try argv.append("-search_paths_first"),
|
||||
.dylibs_first => try argv.append("-search_dylibs_first"),
|
||||
};
|
||||
|
||||
if (self.base.options.entry) |entry| {
|
||||
try argv.append("-e");
|
||||
try argv.append(entry);
|
||||
}
|
||||
|
||||
try argv.appendSlice(positionals.items);
|
||||
for (self.base.options.objects) |obj| {
|
||||
try argv.append(obj.path);
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
try argv.append(p);
|
||||
}
|
||||
|
||||
if (comp.compiler_rt_lib) |lib| {
|
||||
try argv.append(lib.full_object_path);
|
||||
}
|
||||
|
||||
if (self.base.options.link_libcpp) {
|
||||
try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
|
||||
try argv.append(comp.libcxx_static_lib.?.full_object_path);
|
||||
}
|
||||
|
||||
try argv.append("-o");
|
||||
try argv.append(full_out_path);
|
||||
@ -947,7 +1008,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
try argv.append("-lSystem");
|
||||
try argv.append("-lc");
|
||||
|
||||
for (search_lib_names.items) |l_name| {
|
||||
for (self.base.options.system_libs.keys()) |l_name| {
|
||||
try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{l_name}));
|
||||
}
|
||||
|
||||
@ -1183,51 +1244,41 @@ fn resolveSearchDir(
|
||||
|
||||
fn resolveLib(
|
||||
arena: Allocator,
|
||||
search_dirs: []const []const u8,
|
||||
search_dir: []const u8,
|
||||
name: []const u8,
|
||||
ext: []const u8,
|
||||
) !?[]const u8 {
|
||||
const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext });
|
||||
const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, search_name });
|
||||
|
||||
for (search_dirs) |dir| {
|
||||
const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name });
|
||||
// Check if the file exists.
|
||||
const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer tmp.close();
|
||||
|
||||
// Check if the file exists.
|
||||
const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => continue,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer tmp.close();
|
||||
|
||||
return full_path;
|
||||
}
|
||||
|
||||
return null;
|
||||
return full_path;
|
||||
}
|
||||
|
||||
fn resolveFramework(
|
||||
arena: Allocator,
|
||||
search_dirs: []const []const u8,
|
||||
search_dir: []const u8,
|
||||
name: []const u8,
|
||||
ext: []const u8,
|
||||
) !?[]const u8 {
|
||||
const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext });
|
||||
const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
|
||||
const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, prefix_path, search_name });
|
||||
|
||||
for (search_dirs) |dir| {
|
||||
const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name });
|
||||
// Check if the file exists.
|
||||
const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer tmp.close();
|
||||
|
||||
// Check if the file exists.
|
||||
const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => continue,
|
||||
else => |e| return e,
|
||||
};
|
||||
defer tmp.close();
|
||||
|
||||
return full_path;
|
||||
}
|
||||
|
||||
return null;
|
||||
return full_path;
|
||||
}
|
||||
|
||||
fn parseObject(self: *MachO, path: []const u8) !bool {
|
||||
|
||||
@ -2481,7 +2481,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
|
||||
// We are about to obtain this lock, so here we give other processes a chance first.
|
||||
self.base.releaseLock();
|
||||
|
||||
comptime assert(Compilation.link_hash_implementation_version == 4);
|
||||
comptime assert(Compilation.link_hash_implementation_version == 5);
|
||||
|
||||
for (self.base.options.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
|
||||
13
src/main.zig
13
src/main.zig
@ -448,6 +448,8 @@ const usage_build_generic =
|
||||
\\ -install_name=[value] (Darwin) add dylib's install name
|
||||
\\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
|
||||
\\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation
|
||||
\\ -search_paths_first (Darwin) search each dir in library search paths for `libx.dylib` then `libx.a`
|
||||
\\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a`
|
||||
\\ --import-memory (WebAssembly) import memory from the environment
|
||||
\\ --import-table (WebAssembly) import function table from the host environment
|
||||
\\ --export-table (WebAssembly) export function table to the host environment
|
||||
@ -696,6 +698,7 @@ fn buildOutputType(
|
||||
var hash_style: link.HashStyle = .both;
|
||||
var entitlements: ?[]const u8 = null;
|
||||
var pagezero_size: ?u64 = null;
|
||||
var search_strategy: ?link.File.MachO.SearchStrategy = null;
|
||||
|
||||
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
|
||||
// This array is populated by zig cc frontend and then has to be converted to zig-style
|
||||
@ -917,6 +920,10 @@ fn buildOutputType(
|
||||
pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
|
||||
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
|
||||
};
|
||||
} else if (mem.eql(u8, arg, "-search_paths_first")) {
|
||||
search_strategy = .paths_first;
|
||||
} else if (mem.eql(u8, arg, "-search_dylibs_first")) {
|
||||
search_strategy = .dylibs_first;
|
||||
} else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
|
||||
linker_script = args_iter.next() orelse {
|
||||
fatal("expected parameter after {s}", .{arg});
|
||||
@ -1475,6 +1482,10 @@ fn buildOutputType(
|
||||
mem.eql(u8, linker_arg, "-static"))
|
||||
{
|
||||
force_static_libs = true;
|
||||
} else if (mem.eql(u8, linker_arg, "-search_paths_first")) {
|
||||
search_strategy = .paths_first;
|
||||
} else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) {
|
||||
search_strategy = .dylibs_first;
|
||||
} else {
|
||||
try linker_args.append(linker_arg);
|
||||
}
|
||||
@ -2141,6 +2152,7 @@ fn buildOutputType(
|
||||
}
|
||||
|
||||
for (lib_dirs.items) |lib_dir_path| {
|
||||
if (cross_target.isDarwin()) break; // Targeting Darwin we let the linker resolve the libraries in the correct order
|
||||
test_path.clearRetainingCapacity();
|
||||
try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{
|
||||
lib_dir_path,
|
||||
@ -2782,6 +2794,7 @@ fn buildOutputType(
|
||||
.install_name = install_name,
|
||||
.entitlements = entitlements,
|
||||
.pagezero_size = pagezero_size,
|
||||
.search_strategy = search_strategy,
|
||||
}) catch |err| switch (err) {
|
||||
error.LibCUnavailable => {
|
||||
const target = target_info.target;
|
||||
|
||||
@ -60,5 +60,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
cases.addBuildFile("test/link/macho/stack_size/build.zig", .{
|
||||
.build_modes = true,
|
||||
});
|
||||
|
||||
cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{
|
||||
.build_modes = true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
7
test/link/macho/search_strategy/a.c
Normal file
7
test/link/macho/search_strategy/a.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
char world[] = "world";
|
||||
|
||||
char* hello() {
|
||||
return "Hello";
|
||||
}
|
||||
68
test/link/macho/search_strategy/build.zig
Normal file
68
test/link/macho/search_strategy/build.zig
Normal file
@ -0,0 +1,68 @@
|
||||
const std = @import("std");
|
||||
const Builder = std.build.Builder;
|
||||
const LibExeObjectStep = std.build.LibExeObjStep;
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const test_step = b.step("test", "Test");
|
||||
test_step.dependOn(b.getInstallStep());
|
||||
|
||||
{
|
||||
// -search_dylibs_first
|
||||
const exe = createScenario(b, mode);
|
||||
exe.search_strategy = .dylibs_first;
|
||||
|
||||
const check = exe.checkObject(.macho);
|
||||
check.checkStart("cmd LOAD_DYLIB");
|
||||
check.checkNext("name @rpath/liba.dylib");
|
||||
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
const run = exe.run();
|
||||
run.cwd = b.pathFromRoot(".");
|
||||
run.expectStdOutEqual("Hello world");
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
{
|
||||
// -search_paths_first
|
||||
const exe = createScenario(b, mode);
|
||||
exe.search_strategy = .paths_first;
|
||||
|
||||
const run = exe.run();
|
||||
run.cwd = b.pathFromRoot(".");
|
||||
run.expectStdOutEqual("Hello world");
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
}
|
||||
|
||||
fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
|
||||
const static = b.addStaticLibrary("a", null);
|
||||
static.setBuildMode(mode);
|
||||
static.addCSourceFile("a.c", &.{});
|
||||
static.linkLibC();
|
||||
static.override_dest_dir = std.build.InstallDir{
|
||||
.custom = "static",
|
||||
};
|
||||
static.install();
|
||||
|
||||
const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
|
||||
dylib.setBuildMode(mode);
|
||||
dylib.addCSourceFile("a.c", &.{});
|
||||
dylib.linkLibC();
|
||||
dylib.override_dest_dir = std.build.InstallDir{
|
||||
.custom = "dynamic",
|
||||
};
|
||||
dylib.install();
|
||||
|
||||
const exe = b.addExecutable("main", null);
|
||||
exe.setBuildMode(mode);
|
||||
exe.addCSourceFile("main.c", &.{});
|
||||
exe.linkSystemLibraryName("a");
|
||||
exe.linkLibC();
|
||||
exe.addLibraryPath(b.pathFromRoot("zig-out/static"));
|
||||
exe.addLibraryPath(b.pathFromRoot("zig-out/dynamic"));
|
||||
exe.addRPath(b.pathFromRoot("zig-out/dynamic"));
|
||||
return exe;
|
||||
}
|
||||
9
test/link/macho/search_strategy/main.c
Normal file
9
test/link/macho/search_strategy/main.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
|
||||
char* hello();
|
||||
extern char world[];
|
||||
|
||||
int main() {
|
||||
printf("%s %s", hello(), world);
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user