mirror of
https://github.com/ziglang/zig.git
synced 2026-01-09 17:05:16 +00:00
stage2: progress towards LLD linking
* add `zig libc` command * add `--libc` CLI and integrate it with Module and linker code * implement libc detection and paths resolution * port LLD ELF linker line construction to stage2 * integrate dynamic linker option into Module and linker code * implement default link_mode detection and error handling if user requests static when it cannot be fulfilled * integrate more linker options * implement detection of .so.X.Y.Z file extension as a shared object file. nice try, you can't fool me. * correct usage text for -dynamic and -static
This commit is contained in:
parent
5746a8658e
commit
e05ecbf165
@ -24,6 +24,7 @@ const liveness = @import("liveness.zig");
|
||||
const astgen = @import("astgen.zig");
|
||||
const zir_sema = @import("zir_sema.zig");
|
||||
const build_options = @import("build_options");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
|
||||
/// General-purpose allocator. Used for both temporary and long-term storage.
|
||||
gpa: *Allocator,
|
||||
@ -82,8 +83,6 @@ next_anon_name_index: usize = 0,
|
||||
/// contains Decls that need to be deleted if they end up having no references to them.
|
||||
deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
|
||||
|
||||
/// Owned by Module.
|
||||
root_name: []u8,
|
||||
keep_source_files_loaded: bool,
|
||||
use_clang: bool,
|
||||
sanitize_c: bool,
|
||||
@ -106,6 +105,19 @@ zig_cache_dir_path: []const u8,
|
||||
libc_include_dir_list: []const []const u8,
|
||||
rand: *std.rand.Random,
|
||||
|
||||
/// Populated when we build libc++.a. A WorkItem to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libcxx_static_lib: ?[]const u8 = null,
|
||||
/// Populated when we build libc++abi.a. A WorkItem to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libcxxabi_static_lib: ?[]const u8 = null,
|
||||
/// Populated when we build libunwind.a. A WorkItem to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libunwind_static_lib: ?[]const u8 = null,
|
||||
/// Populated when we build c.a. A WorkItem to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libc_static_lib: ?[]const u8 = null,
|
||||
|
||||
pub const InnerError = error{ OutOfMemory, AnalysisFail };
|
||||
|
||||
const WorkItem = union(enum) {
|
||||
@ -932,6 +944,7 @@ pub const InitOptions = struct {
|
||||
root_pkg: ?*Package,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
rand: *std.rand.Random,
|
||||
dynamic_linker: ?[]const u8 = null,
|
||||
bin_file_dir_path: ?[]const u8 = null,
|
||||
bin_file_dir: ?std.fs.Dir = null,
|
||||
bin_file_path: []const u8,
|
||||
@ -941,6 +954,7 @@ pub const InitOptions = struct {
|
||||
optimize_mode: std.builtin.Mode = .Debug,
|
||||
keep_source_files_loaded: bool = false,
|
||||
clang_argv: []const []const u8 = &[0][]const u8{},
|
||||
lld_argv: []const []const u8 = &[0][]const u8{},
|
||||
lib_dirs: []const []const u8 = &[0][]const u8{},
|
||||
rpath_list: []const []const u8 = &[0][]const u8{},
|
||||
c_source_files: []const []const u8 = &[0][]const u8{},
|
||||
@ -957,10 +971,11 @@ pub const InitOptions = struct {
|
||||
use_clang: ?bool = null,
|
||||
rdynamic: bool = false,
|
||||
strip: bool = false,
|
||||
is_native_os: bool,
|
||||
link_eh_frame_hdr: bool = false,
|
||||
linker_script: ?[]const u8 = null,
|
||||
version_script: ?[]const u8 = null,
|
||||
override_soname: ?[]const u8 = null,
|
||||
linker_optimization: ?[]const u8 = null,
|
||||
linker_gc_sections: ?bool = null,
|
||||
function_sections: ?bool = null,
|
||||
linker_allow_shlib_undefined: ?bool = null,
|
||||
@ -969,8 +984,10 @@ pub const InitOptions = struct {
|
||||
linker_z_nodelete: bool = false,
|
||||
linker_z_defs: bool = false,
|
||||
clang_passthrough_mode: bool = false,
|
||||
stack_size_override: u64 = 0,
|
||||
stack_size_override: ?u64 = null,
|
||||
self_exe_path: ?[]const u8 = null,
|
||||
version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 },
|
||||
libc_installation: ?*const LibCInstallation = null,
|
||||
};
|
||||
|
||||
pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
@ -1002,6 +1019,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
options.frameworks.len != 0 or
|
||||
options.system_libs.len != 0 or
|
||||
options.link_libc or options.link_libcpp or
|
||||
options.link_eh_frame_hdr or
|
||||
options.linker_script != null or options.version_script != null)
|
||||
{
|
||||
break :blk true;
|
||||
@ -1017,6 +1035,35 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
break :blk false;
|
||||
};
|
||||
|
||||
const must_dynamic_link = dl: {
|
||||
if (target_util.cannotDynamicLink(options.target))
|
||||
break :dl false;
|
||||
if (target_util.osRequiresLibC(options.target))
|
||||
break :dl true;
|
||||
if (options.link_libc and options.target.isGnuLibC())
|
||||
break :dl true;
|
||||
if (options.system_libs.len != 0)
|
||||
break :dl true;
|
||||
|
||||
break :dl false;
|
||||
};
|
||||
const default_link_mode: std.builtin.LinkMode = if (must_dynamic_link) .Dynamic else .Static;
|
||||
const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: {
|
||||
if (lm == .Static and must_dynamic_link) {
|
||||
return error.UnableToStaticLink;
|
||||
}
|
||||
break :blk lm;
|
||||
} else default_link_mode;
|
||||
|
||||
const libc_dirs = try detectLibCIncludeDirs(
|
||||
arena,
|
||||
options.zig_lib_dir,
|
||||
options.target,
|
||||
options.is_native_os,
|
||||
options.link_libc,
|
||||
options.libc_installation,
|
||||
);
|
||||
|
||||
const bin_file = try link.File.openPath(gpa, .{
|
||||
.dir = options.bin_file_dir orelse std.fs.cwd(),
|
||||
.dir_path = options.bin_file_dir_path,
|
||||
@ -1024,8 +1071,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
.root_name = root_name,
|
||||
.root_pkg = options.root_pkg,
|
||||
.target = options.target,
|
||||
.dynamic_linker = options.dynamic_linker,
|
||||
.output_mode = options.output_mode,
|
||||
.link_mode = options.link_mode orelse .Static,
|
||||
.link_mode = link_mode,
|
||||
.object_format = ofmt,
|
||||
.optimize_mode = options.optimize_mode,
|
||||
.use_lld = use_lld,
|
||||
@ -1039,7 +1087,22 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
.lib_dirs = options.lib_dirs,
|
||||
.rpath_list = options.rpath_list,
|
||||
.strip = options.strip,
|
||||
.is_native_os = options.is_native_os,
|
||||
.function_sections = options.function_sections orelse false,
|
||||
.allow_shlib_undefined = options.linker_allow_shlib_undefined,
|
||||
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
|
||||
.z_nodelete = options.linker_z_nodelete,
|
||||
.z_defs = options.linker_z_defs,
|
||||
.stack_size_override = options.stack_size_override,
|
||||
.linker_script = options.linker_script,
|
||||
.version_script = options.version_script,
|
||||
.gc_sections = options.linker_gc_sections,
|
||||
.eh_frame_hdr = options.link_eh_frame_hdr,
|
||||
.rdynamic = options.rdynamic,
|
||||
.extra_lld_args = options.lld_argv,
|
||||
.override_soname = options.override_soname,
|
||||
.version = options.version,
|
||||
.libc_installation = libc_dirs.libc_installation,
|
||||
});
|
||||
errdefer bin_file.destroy();
|
||||
|
||||
@ -1146,13 +1209,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
break :blk true;
|
||||
};
|
||||
|
||||
const libc_include_dir_list = try detectLibCIncludeDirs(
|
||||
arena,
|
||||
options.zig_lib_dir,
|
||||
options.target,
|
||||
options.link_libc,
|
||||
);
|
||||
|
||||
const sanitize_c: bool = options.want_sanitize_c orelse switch (options.optimize_mode) {
|
||||
.Debug, .ReleaseSafe => true,
|
||||
.ReleaseSmall, .ReleaseFast => false,
|
||||
@ -1163,7 +1219,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
.arena_state = arena_allocator.state,
|
||||
.zig_lib_dir = options.zig_lib_dir,
|
||||
.zig_cache_dir_path = zig_cache_dir_path,
|
||||
.root_name = root_name,
|
||||
.root_pkg = options.root_pkg,
|
||||
.root_scope = root_scope,
|
||||
.bin_file = bin_file,
|
||||
@ -1174,7 +1229,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
.c_source_files = options.c_source_files,
|
||||
.cache = cache,
|
||||
.self_exe_path = options.self_exe_path,
|
||||
.libc_include_dir_list = libc_include_dir_list,
|
||||
.libc_include_dir_list = libc_dirs.libc_include_dir_list,
|
||||
.sanitize_c = sanitize_c,
|
||||
.rand = options.rand,
|
||||
.clang_passthrough_mode = options.clang_passthrough_mode,
|
||||
@ -1544,7 +1599,10 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void {
|
||||
// directly to the output file.
|
||||
const direct_o = mod.c_source_files.len == 1 and mod.root_pkg == null and
|
||||
mod.bin_file.options.output_mode == .Obj and mod.bin_file.options.objects.len == 0;
|
||||
const o_basename_noext = if (direct_o) mod.root_name else mem.split(c_source_basename, ".").next().?;
|
||||
const o_basename_noext = if (direct_o)
|
||||
mod.bin_file.options.root_name
|
||||
else
|
||||
mem.split(c_source_basename, ".").next().?;
|
||||
const o_basename = try std.fmt.allocPrint(arena, "{}{}", .{ o_basename_noext, mod.getTarget().oFileExt() });
|
||||
|
||||
// We can't know the digest until we do the C compiler invocation, so we need a temporary filename.
|
||||
@ -1749,7 +1807,7 @@ fn addCCArgs(
|
||||
try argv.append(p);
|
||||
}
|
||||
},
|
||||
.assembly, .ll, .bc, .unknown => {},
|
||||
.so, .assembly, .ll, .bc, .unknown => {},
|
||||
}
|
||||
// TODO CLI args for cpu features when compiling assembly
|
||||
//for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) {
|
||||
@ -4259,6 +4317,7 @@ pub const FileExt = enum {
|
||||
ll,
|
||||
bc,
|
||||
assembly,
|
||||
so,
|
||||
unknown,
|
||||
};
|
||||
|
||||
@ -4290,10 +4349,36 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
|
||||
return .assembly;
|
||||
} else if (mem.endsWith(u8, filename, ".h")) {
|
||||
return .h;
|
||||
} else {
|
||||
// TODO look for .so, .so.X, .so.X.Y, .so.X.Y.Z
|
||||
return .unknown;
|
||||
} else if (mem.endsWith(u8, filename, ".so")) {
|
||||
return .so;
|
||||
}
|
||||
// Look for .so.X, .so.X.Y, .so.X.Y.Z
|
||||
var it = mem.split(filename, ".");
|
||||
_ = it.next().?;
|
||||
var so_txt = it.next() orelse return .unknown;
|
||||
while (!mem.eql(u8, so_txt, "so")) {
|
||||
so_txt = it.next() orelse return .unknown;
|
||||
}
|
||||
const n1 = it.next() orelse return .unknown;
|
||||
const n2 = it.next();
|
||||
const n3 = it.next();
|
||||
|
||||
_ = std.fmt.parseInt(u32, n1, 10) catch return .unknown;
|
||||
if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown;
|
||||
if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown;
|
||||
if (it.next() != null) return .unknown;
|
||||
|
||||
return .so;
|
||||
}
|
||||
|
||||
test "classifyFileExt" {
|
||||
std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc"));
|
||||
std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim"));
|
||||
std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so"));
|
||||
std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so.1"));
|
||||
std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so.1.2"));
|
||||
std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so.1.2.3"));
|
||||
std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
|
||||
}
|
||||
|
||||
fn haveFramePointer(mod: *Module) bool {
|
||||
@ -4303,16 +4388,29 @@ fn haveFramePointer(mod: *Module) bool {
|
||||
};
|
||||
}
|
||||
|
||||
const LibCDirs = struct {
|
||||
libc_include_dir_list: []const []const u8,
|
||||
libc_installation: ?*const LibCInstallation,
|
||||
};
|
||||
|
||||
fn detectLibCIncludeDirs(
|
||||
arena: *Allocator,
|
||||
zig_lib_dir: []const u8,
|
||||
target: Target,
|
||||
is_native_os: bool,
|
||||
link_libc: bool,
|
||||
) ![]const []const u8 {
|
||||
if (!link_libc) return &[0][]u8{};
|
||||
libc_installation: ?*const LibCInstallation,
|
||||
) !LibCDirs {
|
||||
if (!link_libc) {
|
||||
return LibCDirs{
|
||||
.libc_include_dir_list = &[0][]u8{},
|
||||
.libc_installation = null,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO Support --libc file explicitly providing libc paths. Or not? Maybe we are better off
|
||||
// deleting that feature.
|
||||
if (libc_installation) |lci| {
|
||||
return detectLibCFromLibCInstallation(arena, target, lci);
|
||||
}
|
||||
|
||||
if (target_util.canBuildLibC(target)) {
|
||||
const generic_name = target_util.libCGenericName(target);
|
||||
@ -4348,9 +4446,52 @@ fn detectLibCIncludeDirs(
|
||||
list[1] = generic_include_dir;
|
||||
list[2] = arch_os_include_dir;
|
||||
list[3] = generic_os_include_dir;
|
||||
return list;
|
||||
return LibCDirs{
|
||||
.libc_include_dir_list = list,
|
||||
.libc_installation = null,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO finish porting detect_libc from codegen.cpp
|
||||
return error.LibCDetectionUnimplemented;
|
||||
if (is_native_os) {
|
||||
const libc = try arena.create(LibCInstallation);
|
||||
libc.* = try LibCInstallation.findNative(.{ .allocator = arena });
|
||||
return detectLibCFromLibCInstallation(arena, target, libc);
|
||||
}
|
||||
|
||||
return LibCDirs{
|
||||
.libc_include_dir_list = &[0][]u8{},
|
||||
.libc_installation = null,
|
||||
};
|
||||
}
|
||||
|
||||
fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs {
|
||||
var list = std.ArrayList([]const u8).init(arena);
|
||||
try list.ensureCapacity(4);
|
||||
|
||||
list.appendAssumeCapacity(lci.include_dir.?);
|
||||
|
||||
const is_redundant = mem.eql(u8, lci.sys_include_dir.?, lci.include_dir.?);
|
||||
if (!is_redundant) list.appendAssumeCapacity(lci.sys_include_dir.?);
|
||||
|
||||
if (target.os.tag == .windows) {
|
||||
if (std.fs.path.dirname(lci.include_dir.?)) |include_dir_parent| {
|
||||
const um_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "um" });
|
||||
list.appendAssumeCapacity(um_dir);
|
||||
|
||||
const shared_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "shared" });
|
||||
list.appendAssumeCapacity(shared_dir);
|
||||
}
|
||||
}
|
||||
return LibCDirs{
|
||||
.libc_include_dir_list = list.items,
|
||||
.libc_installation = lci,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 {
|
||||
// TODO port support for building crt files from stage1
|
||||
const lci = mod.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;
|
||||
const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
|
||||
const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
|
||||
return full_path;
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ const is_gnu = Target.current.isGnu();
|
||||
|
||||
usingnamespace @import("windows_sdk.zig");
|
||||
|
||||
// TODO Rework this abstraction to use std.log instead of taking a stderr stream.
|
||||
|
||||
/// See the render function implementation for documentation of the fields.
|
||||
pub const LibCInstallation = struct {
|
||||
include_dir: ?[]const u8 = null,
|
||||
|
||||
@ -6,6 +6,7 @@ const trace = @import("tracy.zig").trace;
|
||||
const Package = @import("Package.zig");
|
||||
const Type = @import("type.zig").Type;
|
||||
const build_options = @import("build_options");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
|
||||
pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
|
||||
|
||||
@ -23,6 +24,7 @@ pub const Options = struct {
|
||||
optimize_mode: std.builtin.Mode,
|
||||
root_name: []const u8,
|
||||
root_pkg: ?*const Package,
|
||||
dynamic_linker: ?[]const u8 = null,
|
||||
/// Used for calculating how much space to reserve for symbols in case the binary file
|
||||
/// does not already have a symbol table.
|
||||
symbol_count_hint: u64 = 32,
|
||||
@ -30,6 +32,7 @@ pub const Options = struct {
|
||||
/// the binary file does not already have such a section.
|
||||
program_code_size_hint: u64 = 256 * 1024,
|
||||
entry_addr: ?u64 = null,
|
||||
stack_size_override: ?u64 = null,
|
||||
/// Set to `true` to omit debug info.
|
||||
strip: bool = false,
|
||||
/// If this is true then this link code is responsible for outputting an object
|
||||
@ -44,6 +47,19 @@ pub const Options = struct {
|
||||
link_libc: bool = false,
|
||||
link_libcpp: bool = false,
|
||||
function_sections: bool = false,
|
||||
eh_frame_hdr: bool = false,
|
||||
rdynamic: bool = false,
|
||||
z_nodelete: bool = false,
|
||||
z_defs: bool = false,
|
||||
bind_global_refs_locally: bool,
|
||||
is_native_os: bool,
|
||||
gc_sections: ?bool = null,
|
||||
allow_shlib_undefined: ?bool = null,
|
||||
linker_script: ?[]const u8 = null,
|
||||
version_script: ?[]const u8 = null,
|
||||
override_soname: ?[]const u8 = null,
|
||||
/// Extra args passed directly to LLD. Ignored when not linking with LLD.
|
||||
extra_lld_args: []const []const u8 = &[0][]const u8,
|
||||
|
||||
objects: []const []const u8 = &[0][]const u8{},
|
||||
framework_dirs: []const []const u8 = &[0][]const u8{},
|
||||
@ -52,6 +68,9 @@ pub const Options = struct {
|
||||
lib_dirs: []const []const u8 = &[0][]const u8{},
|
||||
rpath_list: []const []const u8 = &[0][]const u8{},
|
||||
|
||||
version: std.builtin.Version,
|
||||
libc_installation: ?*const LibCInstallation,
|
||||
|
||||
pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
|
||||
return if (options.use_lld) .Obj else options.output_mode;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ const link = @import("../link.zig");
|
||||
const File = link.File;
|
||||
const Elf = @This();
|
||||
const build_options = @import("build_options");
|
||||
const target_util = @import("../target.zig");
|
||||
|
||||
const default_entry_addr = 0x8000000;
|
||||
|
||||
@ -709,12 +710,7 @@ pub const abbrev_parameter = 6;
|
||||
|
||||
pub fn flush(self: *Elf, module: *Module) !void {
|
||||
if (build_options.have_llvm and self.base.options.use_lld) {
|
||||
// If there is no Zig code to compile, then we should skip flushing the output file because it
|
||||
// will not be part of the linker line anyway.
|
||||
if (module.root_pkg != null) {
|
||||
try self.flushInner(module);
|
||||
}
|
||||
std.debug.print("TODO create an LLD command line and invoke it\n", .{});
|
||||
return self.linkWithLLD(module);
|
||||
} else {
|
||||
switch (self.base.options.effectiveOutputMode()) {
|
||||
.Exe, .Obj => {},
|
||||
@ -1202,6 +1198,275 @@ fn flushInner(self: *Elf, module: *Module) !void {
|
||||
assert(!self.debug_strtab_dirty);
|
||||
}
|
||||
|
||||
fn linkWithLLD(self: *Elf, module: *Module) !void {
|
||||
// If there is no Zig code to compile, then we should skip flushing the output file because it
|
||||
// will not be part of the linker line anyway.
|
||||
if (module.root_pkg != null) {
|
||||
try self.flushInner(module);
|
||||
}
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = &arena_allocator.allocator;
|
||||
|
||||
const target = self.base.options.target;
|
||||
const is_obj = self.base.options.output_mode == .Obj;
|
||||
|
||||
// Create an LLD command line and invoke it.
|
||||
var argv = std.ArrayList([]const u8).init(self.base.allocator);
|
||||
defer argv.deinit();
|
||||
// Even though we're calling LLD as a library it thinks the first argument is its own exe name.
|
||||
try argv.append("lld");
|
||||
if (is_obj) {
|
||||
try argv.append("-r");
|
||||
}
|
||||
if (self.base.options.output_mode == .Lib and
|
||||
self.base.options.link_mode == .Static and
|
||||
!target.isWasm())
|
||||
{
|
||||
// TODO port the code from link.cpp
|
||||
return error.TODOMakeArchive;
|
||||
}
|
||||
const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe;
|
||||
|
||||
try argv.append("-error-limit=0");
|
||||
|
||||
if (self.base.options.output_mode == .Exe) {
|
||||
try argv.append("-z");
|
||||
const stack_size = self.base.options.stack_size_override orelse 16777216;
|
||||
const arg = try std.fmt.allocPrint(arena, "stack-size={}", .{stack_size});
|
||||
try argv.append(arg);
|
||||
}
|
||||
|
||||
if (self.base.options.linker_script) |linker_script| {
|
||||
try argv.append("-T");
|
||||
try argv.append(linker_script);
|
||||
}
|
||||
|
||||
const gc_sections = self.base.options.gc_sections orelse !is_obj;
|
||||
if (gc_sections) {
|
||||
try argv.append("--gc-sections");
|
||||
}
|
||||
|
||||
if (self.base.options.eh_frame_hdr) {
|
||||
try argv.append("--eh-frame-hdr");
|
||||
}
|
||||
|
||||
if (self.base.options.rdynamic) {
|
||||
try argv.append("--export-dynamic");
|
||||
}
|
||||
|
||||
try argv.appendSlice(self.base.options.extra_lld_args);
|
||||
|
||||
if (self.base.options.z_nodelete) {
|
||||
try argv.append("-z");
|
||||
try argv.append("nodelete");
|
||||
}
|
||||
if (self.base.options.z_defs) {
|
||||
try argv.append("-z");
|
||||
try argv.append("defs");
|
||||
}
|
||||
|
||||
if (getLDMOption(target)) |ldm| {
|
||||
// Any target ELF will use the freebsd osabi if suffixed with "_fbsd".
|
||||
const arg = if (target.os.tag == .freebsd)
|
||||
try std.fmt.allocPrint(arena, "{}_fbsd", .{ldm})
|
||||
else
|
||||
ldm;
|
||||
try argv.append("-m");
|
||||
try argv.append(arg);
|
||||
}
|
||||
|
||||
const is_lib = self.base.options.output_mode == .Lib;
|
||||
const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
|
||||
if (self.base.options.link_mode == .Static) {
|
||||
if (target.cpu.arch.isARM() or target.cpu.arch.isThumb()) {
|
||||
try argv.append("-Bstatic");
|
||||
} else {
|
||||
try argv.append("-static");
|
||||
}
|
||||
} else if (is_dyn_lib) {
|
||||
try argv.append("-shared");
|
||||
}
|
||||
|
||||
if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
|
||||
try argv.append("-pie");
|
||||
}
|
||||
|
||||
const full_out_path = if (self.base.options.dir_path) |dir_path|
|
||||
try std.fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path})
|
||||
else
|
||||
self.base.options.sub_path;
|
||||
try argv.append("-o");
|
||||
try argv.append(full_out_path);
|
||||
|
||||
if (link_in_crt) {
|
||||
const crt1o: []const u8 = o: {
|
||||
if (target.os.tag == .netbsd) {
|
||||
break :o "crt0.o";
|
||||
} else if (target.isAndroid()) {
|
||||
if (self.base.options.link_mode == .Dynamic) {
|
||||
break :o "crtbegin_dynamic.o";
|
||||
} else {
|
||||
break :o "crtbegin_static.o";
|
||||
}
|
||||
} else if (self.base.options.link_mode == .Static) {
|
||||
break :o "crt1.o";
|
||||
} else {
|
||||
break :o "Scrt1.o";
|
||||
}
|
||||
};
|
||||
try argv.append(try module.get_libc_crt_file(arena, crt1o));
|
||||
if (target_util.libc_needs_crti_crtn(target)) {
|
||||
try argv.append(try module.get_libc_crt_file(arena, "crti.o"));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO rpaths
|
||||
//for (size_t i = 0; i < g->rpath_list.length; i += 1) {
|
||||
// Buf *rpath = g->rpath_list.at(i);
|
||||
// add_rpath(lj, rpath);
|
||||
//}
|
||||
//if (g->each_lib_rpath) {
|
||||
// for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
|
||||
// const char *lib_dir = g->lib_dirs.at(i);
|
||||
// for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
|
||||
// LinkLib *link_lib = g->link_libs_list.at(i);
|
||||
// if (buf_eql_str(link_lib->name, "c")) {
|
||||
// continue;
|
||||
// }
|
||||
// bool does_exist;
|
||||
// Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name));
|
||||
// if (os_file_exists(test_path, &does_exist) != ErrorNone) {
|
||||
// zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path));
|
||||
// }
|
||||
// if (does_exist) {
|
||||
// add_rpath(lj, buf_create_from_str(lib_dir));
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
for (self.base.options.lib_dirs) |lib_dir| {
|
||||
try argv.append("-L");
|
||||
try argv.append(lib_dir);
|
||||
}
|
||||
|
||||
if (self.base.options.link_libc) {
|
||||
if (self.base.options.libc_installation) |libc_installation| {
|
||||
try argv.append("-L");
|
||||
try argv.append(libc_installation.crt_dir.?);
|
||||
}
|
||||
|
||||
if (self.base.options.link_mode == .Dynamic and (is_dyn_lib or self.base.options.output_mode == .Exe)) {
|
||||
if (self.base.options.dynamic_linker) |dynamic_linker| {
|
||||
try argv.append("-dynamic-linker");
|
||||
try argv.append(dynamic_linker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dyn_lib) {
|
||||
const soname = self.base.options.override_soname orelse
|
||||
try std.fmt.allocPrint(arena, "lib{}.so.{}", .{self.base.options.root_name,
|
||||
self.base.options.version.major,});
|
||||
try argv.append("-soname");
|
||||
try argv.append(soname);
|
||||
|
||||
if (self.base.options.version_script) |version_script| {
|
||||
try argv.append("-version-script");
|
||||
try argv.append(version_script);
|
||||
}
|
||||
}
|
||||
|
||||
// Positional arguments to the linker such as object files.
|
||||
try argv.appendSlice(self.base.options.objects);
|
||||
|
||||
// TODO compiler-rt and libc
|
||||
//if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
|
||||
// if (g->libc_link_lib == nullptr) {
|
||||
// Buf *libc_a_path = build_c(g, OutTypeLib, lj->build_dep_prog_node);
|
||||
// try argv.append(buf_ptr(libc_a_path));
|
||||
// }
|
||||
|
||||
// Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib, lj->build_dep_prog_node);
|
||||
// try argv.append(buf_ptr(compiler_rt_o_path));
|
||||
//}
|
||||
|
||||
// Shared libraries.
|
||||
try argv.ensureCapacity(argv.items.len + self.base.options.system_libs.len);
|
||||
for (self.base.options.system_libs) |link_lib| {
|
||||
// By this time, we depend on these libs being dynamically linked libraries and not static libraries
|
||||
// (the check for that needs to be earlier), but they could be full paths to .so files, in which
|
||||
// case we want to avoid prepending "-l".
|
||||
const ext = Module.classifyFileExt(link_lib);
|
||||
const arg = if (ext == .so) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
|
||||
argv.appendAssumeCapacity(arg);
|
||||
}
|
||||
|
||||
if (!is_obj) {
|
||||
// libc++ dep
|
||||
if (self.base.options.link_libcpp) {
|
||||
try argv.append(module.libcxxabi_static_lib.?);
|
||||
try argv.append(module.libcxx_static_lib.?);
|
||||
}
|
||||
|
||||
// libc dep
|
||||
if (self.base.options.link_libc) {
|
||||
if (self.base.options.libc_installation != null) {
|
||||
if (self.base.options.link_mode == .Static) {
|
||||
try argv.append("--start-group");
|
||||
try argv.append("-lc");
|
||||
try argv.append("-lm");
|
||||
try argv.append("--end-group");
|
||||
} else {
|
||||
try argv.append("-lc");
|
||||
try argv.append("-lm");
|
||||
}
|
||||
|
||||
if (target.os.tag == .freebsd or target.os.tag == .netbsd) {
|
||||
try argv.append("-lpthread");
|
||||
}
|
||||
} else if (target.isGnuLibC()) {
|
||||
try argv.append(module.libunwind_static_lib.?);
|
||||
// TODO here we need to iterate over the glibc libs and add the .so files to the linker line.
|
||||
std.log.warn("TODO port add_glibc_libs to stage2", .{});
|
||||
try argv.append(try module.get_libc_crt_file(arena, "libc_nonshared.a"));
|
||||
} else if (target.isMusl()) {
|
||||
try argv.append(module.libunwind_static_lib.?);
|
||||
try argv.append(module.libc_static_lib.?);
|
||||
} else if (self.base.options.link_libcpp) {
|
||||
try argv.append(module.libunwind_static_lib.?);
|
||||
} else {
|
||||
unreachable; // Compiler was supposed to emit an error for not being able to provide libc.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// crt end
|
||||
if (link_in_crt) {
|
||||
if (target.isAndroid()) {
|
||||
try argv.append(try module.get_libc_crt_file(arena, "crtend_android.o"));
|
||||
} else if (target_util.libc_needs_crti_crtn(target)) {
|
||||
try argv.append(try module.get_libc_crt_file(arena, "crtn.o"));
|
||||
}
|
||||
}
|
||||
|
||||
const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
|
||||
if (allow_shlib_undefined) {
|
||||
try argv.append("--allow-shlib-undefined");
|
||||
}
|
||||
|
||||
if (self.base.options.bind_global_refs_locally) {
|
||||
try argv.append("-Bsymbolic");
|
||||
}
|
||||
|
||||
for (argv.items) |arg| {
|
||||
std.debug.print("{} ", .{arg});
|
||||
}
|
||||
@panic("invoke LLD");
|
||||
}
|
||||
|
||||
fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
|
||||
const target_endian = self.base.options.target.cpu.arch.endian();
|
||||
switch (self.ptr_width) {
|
||||
@ -2616,3 +2881,36 @@ fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {
|
||||
.sh_entsize = @intCast(u32, shdr.sh_entsize),
|
||||
};
|
||||
}
|
||||
|
||||
fn getLDMOption(target: std.Target) ?[]const u8 {
|
||||
switch (target.cpu.arch) {
|
||||
.i386 => return "elf_i386",
|
||||
.aarch64 => return "aarch64linux",
|
||||
.aarch64_be => return "aarch64_be_linux",
|
||||
.arm, .thumb => return "armelf_linux_eabi",
|
||||
.armeb, .thumbeb => return "armebelf_linux_eabi",
|
||||
.powerpc => return "elf32ppclinux",
|
||||
.powerpc64 => return "elf64ppc",
|
||||
.powerpc64le => return "elf64lppc",
|
||||
.sparc, .sparcel => return "elf32_sparc",
|
||||
.sparcv9 => return "elf64_sparc",
|
||||
.mips => return "elf32btsmip",
|
||||
.mipsel => return "elf32ltsmip",
|
||||
.mips64 => return "elf64btsmip",
|
||||
.mips64el => return "elf64ltsmip",
|
||||
.s390x => return "elf64_s390",
|
||||
.x86_64 => {
|
||||
if (target.abi == .gnux32) {
|
||||
return "elf32_x86_64";
|
||||
}
|
||||
// Any target elf will use the freebsd osabi if suffixed with "_fbsd".
|
||||
if (target.os.tag == .freebsd) {
|
||||
return "elf_x86_64_fbsd";
|
||||
}
|
||||
return "elf_x86_64";
|
||||
},
|
||||
.riscv32 => return "elf32lriscv",
|
||||
.riscv64 => return "elf64lriscv",
|
||||
else => return null,
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ const zir = @import("zir.zig");
|
||||
const build_options = @import("build_options");
|
||||
const warn = std.log.warn;
|
||||
const introspect = @import("introspect.zig");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.emerg(format, args);
|
||||
@ -33,18 +34,22 @@ const usage =
|
||||
\\
|
||||
\\Commands:
|
||||
\\
|
||||
\\ build-exe [source] Create executable from source or object files
|
||||
\\ build-lib [source] Create library from source or object files
|
||||
\\ build-obj [source] Create object from source or assembly
|
||||
\\ cc Use Zig as a drop-in C compiler
|
||||
\\ c++ Use Zig as a drop-in C++ compiler
|
||||
\\ env Print lib path, std path, compiler id and version
|
||||
\\ fmt [source] Parse file and render in canonical zig format
|
||||
\\ translate-c [source] Convert C code to Zig code
|
||||
\\ targets List available compilation targets
|
||||
\\ version Print version number and exit
|
||||
\\ zen Print zen of zig and exit
|
||||
\\ build-exe Create executable from source or object files
|
||||
\\ build-lib Create library from source or object files
|
||||
\\ build-obj Create object from source or assembly
|
||||
\\ cc Use Zig as a drop-in C compiler
|
||||
\\ c++ Use Zig as a drop-in C++ compiler
|
||||
\\ env Print lib path, std path, compiler id and version
|
||||
\\ fmt Parse file and render in canonical zig format
|
||||
\\ libc Display native libc paths file or validate one
|
||||
\\ translate-c Convert C code to Zig code
|
||||
\\ targets List available compilation targets
|
||||
\\ version Print version number and exit
|
||||
\\ zen Print zen of zig and exit
|
||||
\\
|
||||
\\General Options:
|
||||
\\
|
||||
\\ --help Print command-specific usage
|
||||
\\
|
||||
;
|
||||
|
||||
@ -126,6 +131,8 @@ pub fn main() !void {
|
||||
return punt_to_clang(arena, args);
|
||||
} else if (mem.eql(u8, cmd, "fmt")) {
|
||||
return cmdFmt(gpa, cmd_args);
|
||||
} else if (mem.eql(u8, cmd, "libc")) {
|
||||
return cmdLibC(gpa, cmd_args);
|
||||
} else if (mem.eql(u8, cmd, "targets")) {
|
||||
const info = try std.zig.system.NativeTargetInfo.detect(arena, .{});
|
||||
const stdout = io.getStdOut().outStream();
|
||||
@ -184,7 +191,6 @@ const usage_build_generic =
|
||||
\\ ReleaseSmall Optimize for small binary, safety off
|
||||
\\ -fPIC Force-enable Position Independent Code
|
||||
\\ -fno-PIC Force-disable Position Independent Code
|
||||
\\ --dynamic Force output to be dynamically linked
|
||||
\\ --strip Exclude debug symbols
|
||||
\\ -ofmt=[mode] Override target object format
|
||||
\\ elf Executable and Linking Format
|
||||
@ -199,6 +205,7 @@ const usage_build_generic =
|
||||
\\ -isystem [dir] Add directory to SYSTEM include search path
|
||||
\\ -I[dir] Add directory to include search path
|
||||
\\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted)
|
||||
\\ --libc [file] Provide a file which specifies libc paths
|
||||
\\
|
||||
\\Link Options:
|
||||
\\ -l[lib], --library [lib] Link against system library
|
||||
@ -208,6 +215,9 @@ const usage_build_generic =
|
||||
\\ --version [ver] Dynamic library semver
|
||||
\\ -rdynamic Add all symbols to the dynamic symbol table
|
||||
\\ -rpath [path] Add directory to the runtime library search path
|
||||
\\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
|
||||
\\ -dynamic Force output to be dynamically linked
|
||||
\\ -static Force output to be statically linked
|
||||
\\
|
||||
\\Debug Options (Zig Compiler Development):
|
||||
\\ -ftime-report Print timing diagnostics
|
||||
@ -220,6 +230,14 @@ const usage_build_generic =
|
||||
\\
|
||||
;
|
||||
|
||||
const repl_help =
|
||||
\\Commands:
|
||||
\\ update Detect changes to source files and update output files.
|
||||
\\ help Print this text
|
||||
\\ exit Quit this repl
|
||||
\\
|
||||
;
|
||||
|
||||
const Emit = union(enum) {
|
||||
no,
|
||||
yes_default_path,
|
||||
@ -275,16 +293,17 @@ pub fn buildOutputType(
|
||||
var version_script: ?[]const u8 = null;
|
||||
var disable_c_depfile = false;
|
||||
var override_soname: ?[]const u8 = null;
|
||||
var linker_optimization: ?[]const u8 = null;
|
||||
var linker_gc_sections: ?bool = null;
|
||||
var linker_allow_shlib_undefined: ?bool = null;
|
||||
var linker_bind_global_refs_locally: ?bool = null;
|
||||
var linker_z_nodelete = false;
|
||||
var linker_z_defs = false;
|
||||
var stack_size_override: u64 = 0;
|
||||
var stack_size_override: ?u64 = null;
|
||||
var use_llvm: ?bool = null;
|
||||
var use_lld: ?bool = null;
|
||||
var use_clang: ?bool = null;
|
||||
var link_eh_frame_hdr = false;
|
||||
var libc_paths_file: ?[]const u8 = null;
|
||||
|
||||
var system_libs = std.ArrayList([]const u8).init(gpa);
|
||||
defer system_libs.deinit();
|
||||
@ -292,6 +311,9 @@ pub fn buildOutputType(
|
||||
var clang_argv = std.ArrayList([]const u8).init(gpa);
|
||||
defer clang_argv.deinit();
|
||||
|
||||
var lld_argv = std.ArrayList([]const u8).init(gpa);
|
||||
defer lld_argv.deinit();
|
||||
|
||||
var lib_dirs = std.ArrayList([]const u8).init(gpa);
|
||||
defer lib_dirs.deinit();
|
||||
|
||||
@ -414,15 +436,11 @@ pub fn buildOutputType(
|
||||
fatal("unable to parse --version '{}': {}", .{ args[i], @errorName(err) });
|
||||
};
|
||||
} else if (mem.eql(u8, arg, "-target")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected parameter after -target", .{});
|
||||
}
|
||||
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
|
||||
i += 1;
|
||||
target_arch_os_abi = args[i];
|
||||
} else if (mem.eql(u8, arg, "-mcpu")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected parameter after -mcpu", .{});
|
||||
}
|
||||
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
|
||||
i += 1;
|
||||
target_mcpu = args[i];
|
||||
} else if (mem.startsWith(u8, arg, "-ofmt=")) {
|
||||
@ -430,11 +448,13 @@ pub fn buildOutputType(
|
||||
} else if (mem.startsWith(u8, arg, "-mcpu=")) {
|
||||
target_mcpu = arg["-mcpu=".len..];
|
||||
} else if (mem.eql(u8, arg, "--dynamic-linker")) {
|
||||
if (i + 1 >= args.len) {
|
||||
fatal("expected parameter after --dynamic-linker", .{});
|
||||
}
|
||||
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
|
||||
i += 1;
|
||||
target_dynamic_linker = args[i];
|
||||
} else if (mem.eql(u8, arg, "--libc")) {
|
||||
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
|
||||
i += 1;
|
||||
libc_paths_file = args[i];
|
||||
} else if (mem.eql(u8, arg, "--watch")) {
|
||||
watch = true;
|
||||
} else if (mem.eql(u8, arg, "-ftime-report")) {
|
||||
@ -481,6 +501,8 @@ pub fn buildOutputType(
|
||||
link_mode = .Static;
|
||||
} else if (mem.eql(u8, arg, "--strip")) {
|
||||
strip = true;
|
||||
} else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
|
||||
link_eh_frame_hdr = true;
|
||||
} else if (mem.eql(u8, arg, "-Bsymbolic")) {
|
||||
linker_bind_global_refs_locally = true;
|
||||
} else if (mem.eql(u8, arg, "--debug-tokenize")) {
|
||||
@ -565,7 +587,7 @@ pub fn buildOutputType(
|
||||
const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg));
|
||||
switch (file_ext) {
|
||||
.assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg),
|
||||
.unknown => try link_objects.append(it.only_arg),
|
||||
.unknown, .so => try link_objects.append(it.only_arg),
|
||||
}
|
||||
},
|
||||
.l => {
|
||||
@ -716,7 +738,7 @@ pub fn buildOutputType(
|
||||
}
|
||||
version_script = linker_args.items[i];
|
||||
} else if (mem.startsWith(u8, arg, "-O")) {
|
||||
linker_optimization = arg;
|
||||
try lld_argv.append(arg);
|
||||
} else if (mem.eql(u8, arg, "--gc-sections")) {
|
||||
linker_gc_sections = true;
|
||||
} else if (mem.eql(u8, arg, "--no-gc-sections")) {
|
||||
@ -994,10 +1016,21 @@ pub fn buildOutputType(
|
||||
};
|
||||
var default_prng = std.rand.DefaultPrng.init(random_seed);
|
||||
|
||||
var libc_installation: ?LibCInstallation = null;
|
||||
defer if (libc_installation) |*l| l.deinit(gpa);
|
||||
|
||||
if (libc_paths_file) |paths_file| {
|
||||
libc_installation = LibCInstallation.parse(gpa, paths_file, io.getStdErr().writer()) catch |err| {
|
||||
fatal("unable to parse libc paths file: {}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
|
||||
const module = Module.create(gpa, .{
|
||||
.zig_lib_dir = zig_lib_dir,
|
||||
.root_name = root_name,
|
||||
.target = target_info.target,
|
||||
.is_native_os = cross_target.isNativeOs(),
|
||||
.dynamic_linker = target_info.dynamic_linker.get(),
|
||||
.output_mode = output_mode,
|
||||
.root_pkg = root_pkg,
|
||||
.bin_file_dir_path = null,
|
||||
@ -1008,6 +1041,7 @@ pub fn buildOutputType(
|
||||
.optimize_mode = build_mode,
|
||||
.keep_source_files_loaded = zir_out_path != null,
|
||||
.clang_argv = clang_argv.items,
|
||||
.lld_argv = lld_argv.items,
|
||||
.lib_dirs = lib_dirs.items,
|
||||
.rpath_list = rpath_list.items,
|
||||
.c_source_files = c_source_files.items,
|
||||
@ -1028,17 +1062,19 @@ pub fn buildOutputType(
|
||||
.version_script = version_script,
|
||||
.disable_c_depfile = disable_c_depfile,
|
||||
.override_soname = override_soname,
|
||||
.linker_optimization = linker_optimization,
|
||||
.linker_gc_sections = linker_gc_sections,
|
||||
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
|
||||
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
|
||||
.linker_z_nodelete = linker_z_nodelete,
|
||||
.linker_z_defs = linker_z_defs,
|
||||
.link_eh_frame_hdr = link_eh_frame_hdr,
|
||||
.stack_size_override = stack_size_override,
|
||||
.strip = strip,
|
||||
.self_exe_path = self_exe_path,
|
||||
.rand = &default_prng.random,
|
||||
.clang_passthrough_mode = arg_mode != .build,
|
||||
.version = version,
|
||||
.libc_installation = if (libc_installation) |*lci| lci else null,
|
||||
}) catch |err| {
|
||||
fatal("unable to create module: {}", .{@errorName(err)});
|
||||
};
|
||||
@ -1116,16 +1152,64 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo
|
||||
}
|
||||
}
|
||||
|
||||
const repl_help =
|
||||
\\Commands:
|
||||
\\ update Detect changes to source files and update output files.
|
||||
\\ help Print this text
|
||||
\\ exit Quit this repl
|
||||
pub const usage_libc =
|
||||
\\Usage: zig libc
|
||||
\\
|
||||
\\ Detect the native libc installation and print the resulting
|
||||
\\ paths to stdout. You can save this into a file and then edit
|
||||
\\ the paths to create a cross compilation libc kit. Then you
|
||||
\\ can pass `--libc [file]` for Zig to use it.
|
||||
\\
|
||||
\\Usage: zig libc [paths_file]
|
||||
\\
|
||||
\\ Parse a libc installation text file and validate it.
|
||||
\\
|
||||
;
|
||||
|
||||
pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void {
|
||||
var input_file: ?[]const u8 = null;
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (mem.startsWith(u8, arg, "-")) {
|
||||
if (mem.eql(u8, arg, "--help")) {
|
||||
const stdout = io.getStdOut().writer();
|
||||
try stdout.writeAll(usage_libc);
|
||||
process.exit(0);
|
||||
} else {
|
||||
fatal("unrecognized parameter: '{}'", .{arg});
|
||||
}
|
||||
} else if (input_file != null) {
|
||||
fatal("unexpected extra parameter: '{}'", .{arg});
|
||||
} else {
|
||||
input_file = arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (input_file) |libc_file| {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
var libc = LibCInstallation.parse(gpa, libc_file, stderr) catch |err| {
|
||||
fatal("unable to parse libc file: {}", .{@errorName(err)});
|
||||
};
|
||||
defer libc.deinit(gpa);
|
||||
} else {
|
||||
var libc = LibCInstallation.findNative(.{
|
||||
.allocator = gpa,
|
||||
.verbose = true,
|
||||
}) catch |err| {
|
||||
fatal("unable to detect native libc: {}", .{@errorName(err)});
|
||||
};
|
||||
defer libc.deinit(gpa);
|
||||
|
||||
var bos = io.bufferedOutStream(io.getStdOut().writer());
|
||||
try libc.render(bos.writer());
|
||||
try bos.flush();
|
||||
}
|
||||
}
|
||||
|
||||
pub const usage_fmt =
|
||||
\\usage: zig fmt [file]...
|
||||
\\Usage: zig fmt [file]...
|
||||
\\
|
||||
\\ Formats the input files and modifies them in-place.
|
||||
\\ Arguments can be files or directories, which are searched
|
||||
|
||||
@ -109,3 +109,28 @@ pub fn canBuildLibC(target: std.Target) bool {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn cannotDynamicLink(target: std.Target) bool {
|
||||
return switch (target.os.tag) {
|
||||
.freestanding, .other => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn osRequiresLibC(target: std.Target) bool {
|
||||
// On Darwin, we always link libSystem which contains libc.
|
||||
// Similarly on FreeBSD and NetBSD we always link system libc
|
||||
// since this is the stable syscall interface.
|
||||
return switch (target.os.tag) {
|
||||
.freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn requiresPIE(target: std.Target) bool {
|
||||
return target.isAndroid();
|
||||
}
|
||||
|
||||
pub fn libc_needs_crti_crtn(target: std.Target) bool {
|
||||
return !(target.cpu.arch.isRISCV() or target.isAndroid());
|
||||
}
|
||||
|
||||
@ -472,6 +472,7 @@ pub const TestContext = struct {
|
||||
.root_pkg = root_pkg,
|
||||
.keep_source_files_loaded = true,
|
||||
.object_format = ofmt,
|
||||
.is_native_os = case.target.isNativeOs(),
|
||||
});
|
||||
defer module.destroy();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user