| author | |
| committer | |
| log | e05ecbf165931d14440e6e5d089b64788b82d14f |
| tree | 93ec39e42c1fdc0f0949d75de95363477c6a62c8 |
| parent | 5746a8658ea52dee4bf310c1290d76b1255cb5ec |
* 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 -static7 files changed, 634 insertions(+), 64 deletions(-)
src-self-hosted/Module.zig+167-26| ... | @@ -24,6 +24,7 @@ const liveness = @import("liveness.zig"); | ... | @@ -24,6 +24,7 @@ const liveness = @import("liveness.zig"); |
| 24 | const astgen = @import("astgen.zig"); | 24 | const astgen = @import("astgen.zig"); |
| 25 | const zir_sema = @import("zir_sema.zig"); | 25 | const zir_sema = @import("zir_sema.zig"); |
| 26 | const build_options = @import("build_options"); | 26 | const build_options = @import("build_options"); |
| 27 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 27 | 28 | ||
| 28 | /// General-purpose allocator. Used for both temporary and long-term storage. | 29 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 29 | gpa: *Allocator, | 30 | gpa: *Allocator, |
| ... | @@ -82,8 +83,6 @@ next_anon_name_index: usize = 0, | ... | @@ -82,8 +83,6 @@ next_anon_name_index: usize = 0, |
| 82 | /// contains Decls that need to be deleted if they end up having no references to them. | 83 | /// contains Decls that need to be deleted if they end up having no references to them. |
| 83 | deletion_set: std.ArrayListUnmanaged(*Decl) = .{}, | 84 | deletion_set: std.ArrayListUnmanaged(*Decl) = .{}, |
| 84 | 85 | ||
| 85 | /// Owned by Module. | ||
| 86 | root_name: []u8, | ||
| 87 | keep_source_files_loaded: bool, | 86 | keep_source_files_loaded: bool, |
| 88 | use_clang: bool, | 87 | use_clang: bool, |
| 89 | sanitize_c: bool, | 88 | sanitize_c: bool, |
| ... | @@ -106,6 +105,19 @@ zig_cache_dir_path: []const u8, | ... | @@ -106,6 +105,19 @@ zig_cache_dir_path: []const u8, |
| 106 | libc_include_dir_list: []const []const u8, | 105 | libc_include_dir_list: []const []const u8, |
| 107 | rand: *std.rand.Random, | 106 | rand: *std.rand.Random, |
| 108 | 107 | ||
| 108 | /// Populated when we build libc++.a. A WorkItem to build this is placed in the queue | ||
| 109 | /// and resolved before calling linker.flush(). | ||
| 110 | libcxx_static_lib: ?[]const u8 = null, | ||
| 111 | /// Populated when we build libc++abi.a. A WorkItem to build this is placed in the queue | ||
| 112 | /// and resolved before calling linker.flush(). | ||
| 113 | libcxxabi_static_lib: ?[]const u8 = null, | ||
| 114 | /// Populated when we build libunwind.a. A WorkItem to build this is placed in the queue | ||
| 115 | /// and resolved before calling linker.flush(). | ||
| 116 | libunwind_static_lib: ?[]const u8 = null, | ||
| 117 | /// Populated when we build c.a. A WorkItem to build this is placed in the queue | ||
| 118 | /// and resolved before calling linker.flush(). | ||
| 119 | libc_static_lib: ?[]const u8 = null, | ||
| 120 | |||
| 109 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; | 121 | pub const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 110 | 122 | ||
| 111 | const WorkItem = union(enum) { | 123 | const WorkItem = union(enum) { |
| ... | @@ -932,6 +944,7 @@ pub const InitOptions = struct { | ... | @@ -932,6 +944,7 @@ pub const InitOptions = struct { |
| 932 | root_pkg: ?*Package, | 944 | root_pkg: ?*Package, |
| 933 | output_mode: std.builtin.OutputMode, | 945 | output_mode: std.builtin.OutputMode, |
| 934 | rand: *std.rand.Random, | 946 | rand: *std.rand.Random, |
| 947 | dynamic_linker: ?[]const u8 = null, | ||
| 935 | bin_file_dir_path: ?[]const u8 = null, | 948 | bin_file_dir_path: ?[]const u8 = null, |
| 936 | bin_file_dir: ?std.fs.Dir = null, | 949 | bin_file_dir: ?std.fs.Dir = null, |
| 937 | bin_file_path: []const u8, | 950 | bin_file_path: []const u8, |
| ... | @@ -941,6 +954,7 @@ pub const InitOptions = struct { | ... | @@ -941,6 +954,7 @@ pub const InitOptions = struct { |
| 941 | optimize_mode: std.builtin.Mode = .Debug, | 954 | optimize_mode: std.builtin.Mode = .Debug, |
| 942 | keep_source_files_loaded: bool = false, | 955 | keep_source_files_loaded: bool = false, |
| 943 | clang_argv: []const []const u8 = &[0][]const u8{}, | 956 | clang_argv: []const []const u8 = &[0][]const u8{}, |
| 957 | lld_argv: []const []const u8 = &[0][]const u8{}, | ||
| 944 | lib_dirs: []const []const u8 = &[0][]const u8{}, | 958 | lib_dirs: []const []const u8 = &[0][]const u8{}, |
| 945 | rpath_list: []const []const u8 = &[0][]const u8{}, | 959 | rpath_list: []const []const u8 = &[0][]const u8{}, |
| 946 | c_source_files: []const []const u8 = &[0][]const u8{}, | 960 | c_source_files: []const []const u8 = &[0][]const u8{}, |
| ... | @@ -957,10 +971,11 @@ pub const InitOptions = struct { | ... | @@ -957,10 +971,11 @@ pub const InitOptions = struct { |
| 957 | use_clang: ?bool = null, | 971 | use_clang: ?bool = null, |
| 958 | rdynamic: bool = false, | 972 | rdynamic: bool = false, |
| 959 | strip: bool = false, | 973 | strip: bool = false, |
| 974 | is_native_os: bool, | ||
| 975 | link_eh_frame_hdr: bool = false, | ||
| 960 | linker_script: ?[]const u8 = null, | 976 | linker_script: ?[]const u8 = null, |
| 961 | version_script: ?[]const u8 = null, | 977 | version_script: ?[]const u8 = null, |
| 962 | override_soname: ?[]const u8 = null, | 978 | override_soname: ?[]const u8 = null, |
| 963 | linker_optimization: ?[]const u8 = null, | ||
| 964 | linker_gc_sections: ?bool = null, | 979 | linker_gc_sections: ?bool = null, |
| 965 | function_sections: ?bool = null, | 980 | function_sections: ?bool = null, |
| 966 | linker_allow_shlib_undefined: ?bool = null, | 981 | linker_allow_shlib_undefined: ?bool = null, |
| ... | @@ -969,8 +984,10 @@ pub const InitOptions = struct { | ... | @@ -969,8 +984,10 @@ pub const InitOptions = struct { |
| 969 | linker_z_nodelete: bool = false, | 984 | linker_z_nodelete: bool = false, |
| 970 | linker_z_defs: bool = false, | 985 | linker_z_defs: bool = false, |
| 971 | clang_passthrough_mode: bool = false, | 986 | clang_passthrough_mode: bool = false, |
| 972 | stack_size_override: u64 = 0, | 987 | stack_size_override: ?u64 = null, |
| 973 | self_exe_path: ?[]const u8 = null, | 988 | self_exe_path: ?[]const u8 = null, |
| 989 | version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 }, | ||
| 990 | libc_installation: ?*const LibCInstallation = null, | ||
| 974 | }; | 991 | }; |
| 975 | 992 | ||
| 976 | pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | 993 | pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| ... | @@ -1002,6 +1019,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1002,6 +1019,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1002 | options.frameworks.len != 0 or | 1019 | options.frameworks.len != 0 or |
| 1003 | options.system_libs.len != 0 or | 1020 | options.system_libs.len != 0 or |
| 1004 | options.link_libc or options.link_libcpp or | 1021 | options.link_libc or options.link_libcpp or |
| 1022 | options.link_eh_frame_hdr or | ||
| 1005 | options.linker_script != null or options.version_script != null) | 1023 | options.linker_script != null or options.version_script != null) |
| 1006 | { | 1024 | { |
| 1007 | break :blk true; | 1025 | break :blk true; |
| ... | @@ -1017,6 +1035,35 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1017,6 +1035,35 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1017 | break :blk false; | 1035 | break :blk false; |
| 1018 | }; | 1036 | }; |
| 1019 | 1037 | ||
| 1038 | const must_dynamic_link = dl: { | ||
| 1039 | if (target_util.cannotDynamicLink(options.target)) | ||
| 1040 | break :dl false; | ||
| 1041 | if (target_util.osRequiresLibC(options.target)) | ||
| 1042 | break :dl true; | ||
| 1043 | if (options.link_libc and options.target.isGnuLibC()) | ||
| 1044 | break :dl true; | ||
| 1045 | if (options.system_libs.len != 0) | ||
| 1046 | break :dl true; | ||
| 1047 | |||
| 1048 | break :dl false; | ||
| 1049 | }; | ||
| 1050 | const default_link_mode: std.builtin.LinkMode = if (must_dynamic_link) .Dynamic else .Static; | ||
| 1051 | const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: { | ||
| 1052 | if (lm == .Static and must_dynamic_link) { | ||
| 1053 | return error.UnableToStaticLink; | ||
| 1054 | } | ||
| 1055 | break :blk lm; | ||
| 1056 | } else default_link_mode; | ||
| 1057 | |||
| 1058 | const libc_dirs = try detectLibCIncludeDirs( | ||
| 1059 | arena, | ||
| 1060 | options.zig_lib_dir, | ||
| 1061 | options.target, | ||
| 1062 | options.is_native_os, | ||
| 1063 | options.link_libc, | ||
| 1064 | options.libc_installation, | ||
| 1065 | ); | ||
| 1066 | |||
| 1020 | const bin_file = try link.File.openPath(gpa, .{ | 1067 | const bin_file = try link.File.openPath(gpa, .{ |
| 1021 | .dir = options.bin_file_dir orelse std.fs.cwd(), | 1068 | .dir = options.bin_file_dir orelse std.fs.cwd(), |
| 1022 | .dir_path = options.bin_file_dir_path, | 1069 | .dir_path = options.bin_file_dir_path, |
| ... | @@ -1024,8 +1071,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1024,8 +1071,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1024 | .root_name = root_name, | 1071 | .root_name = root_name, |
| 1025 | .root_pkg = options.root_pkg, | 1072 | .root_pkg = options.root_pkg, |
| 1026 | .target = options.target, | 1073 | .target = options.target, |
| 1074 | .dynamic_linker = options.dynamic_linker, | ||
| 1027 | .output_mode = options.output_mode, | 1075 | .output_mode = options.output_mode, |
| 1028 | .link_mode = options.link_mode orelse .Static, | 1076 | .link_mode = link_mode, |
| 1029 | .object_format = ofmt, | 1077 | .object_format = ofmt, |
| 1030 | .optimize_mode = options.optimize_mode, | 1078 | .optimize_mode = options.optimize_mode, |
| 1031 | .use_lld = use_lld, | 1079 | .use_lld = use_lld, |
| ... | @@ -1039,7 +1087,22 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1039,7 +1087,22 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1039 | .lib_dirs = options.lib_dirs, | 1087 | .lib_dirs = options.lib_dirs, |
| 1040 | .rpath_list = options.rpath_list, | 1088 | .rpath_list = options.rpath_list, |
| 1041 | .strip = options.strip, | 1089 | .strip = options.strip, |
| 1090 | .is_native_os = options.is_native_os, | ||
| 1042 | .function_sections = options.function_sections orelse false, | 1091 | .function_sections = options.function_sections orelse false, |
| 1092 | .allow_shlib_undefined = options.linker_allow_shlib_undefined, | ||
| 1093 | .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, | ||
| 1094 | .z_nodelete = options.linker_z_nodelete, | ||
| 1095 | .z_defs = options.linker_z_defs, | ||
| 1096 | .stack_size_override = options.stack_size_override, | ||
| 1097 | .linker_script = options.linker_script, | ||
| 1098 | .version_script = options.version_script, | ||
| 1099 | .gc_sections = options.linker_gc_sections, | ||
| 1100 | .eh_frame_hdr = options.link_eh_frame_hdr, | ||
| 1101 | .rdynamic = options.rdynamic, | ||
| 1102 | .extra_lld_args = options.lld_argv, | ||
| 1103 | .override_soname = options.override_soname, | ||
| 1104 | .version = options.version, | ||
| 1105 | .libc_installation = libc_dirs.libc_installation, | ||
| 1043 | }); | 1106 | }); |
| 1044 | errdefer bin_file.destroy(); | 1107 | errdefer bin_file.destroy(); |
| 1045 | 1108 | ||
| ... | @@ -1146,13 +1209,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1146,13 +1209,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1146 | break :blk true; | 1209 | break :blk true; |
| 1147 | }; | 1210 | }; |
| 1148 | 1211 | ||
| 1149 | const libc_include_dir_list = try detectLibCIncludeDirs( | ||
| 1150 | arena, | ||
| 1151 | options.zig_lib_dir, | ||
| 1152 | options.target, | ||
| 1153 | options.link_libc, | ||
| 1154 | ); | ||
| 1155 | |||
| 1156 | const sanitize_c: bool = options.want_sanitize_c orelse switch (options.optimize_mode) { | 1212 | const sanitize_c: bool = options.want_sanitize_c orelse switch (options.optimize_mode) { |
| 1157 | .Debug, .ReleaseSafe => true, | 1213 | .Debug, .ReleaseSafe => true, |
| 1158 | .ReleaseSmall, .ReleaseFast => false, | 1214 | .ReleaseSmall, .ReleaseFast => false, |
| ... | @@ -1163,7 +1219,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1163,7 +1219,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1163 | .arena_state = arena_allocator.state, | 1219 | .arena_state = arena_allocator.state, |
| 1164 | .zig_lib_dir = options.zig_lib_dir, | 1220 | .zig_lib_dir = options.zig_lib_dir, |
| 1165 | .zig_cache_dir_path = zig_cache_dir_path, | 1221 | .zig_cache_dir_path = zig_cache_dir_path, |
| 1166 | .root_name = root_name, | ||
| 1167 | .root_pkg = options.root_pkg, | 1222 | .root_pkg = options.root_pkg, |
| 1168 | .root_scope = root_scope, | 1223 | .root_scope = root_scope, |
| 1169 | .bin_file = bin_file, | 1224 | .bin_file = bin_file, |
| ... | @@ -1174,7 +1229,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { | ... | @@ -1174,7 +1229,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module { |
| 1174 | .c_source_files = options.c_source_files, | 1229 | .c_source_files = options.c_source_files, |
| 1175 | .cache = cache, | 1230 | .cache = cache, |
| 1176 | .self_exe_path = options.self_exe_path, | 1231 | .self_exe_path = options.self_exe_path, |
| 1177 | .libc_include_dir_list = libc_include_dir_list, | 1232 | .libc_include_dir_list = libc_dirs.libc_include_dir_list, |
| 1178 | .sanitize_c = sanitize_c, | 1233 | .sanitize_c = sanitize_c, |
| 1179 | .rand = options.rand, | 1234 | .rand = options.rand, |
| 1180 | .clang_passthrough_mode = options.clang_passthrough_mode, | 1235 | .clang_passthrough_mode = options.clang_passthrough_mode, |
| ... | @@ -1544,7 +1599,10 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void { | ... | @@ -1544,7 +1599,10 @@ fn buildCObject(mod: *Module, c_object: *CObject) !void { |
| 1544 | // directly to the output file. | 1599 | // directly to the output file. |
| 1545 | const direct_o = mod.c_source_files.len == 1 and mod.root_pkg == null and | 1600 | const direct_o = mod.c_source_files.len == 1 and mod.root_pkg == null and |
| 1546 | mod.bin_file.options.output_mode == .Obj and mod.bin_file.options.objects.len == 0; | 1601 | mod.bin_file.options.output_mode == .Obj and mod.bin_file.options.objects.len == 0; |
| 1547 | const o_basename_noext = if (direct_o) mod.root_name else mem.split(c_source_basename, ".").next().?; | 1602 | const o_basename_noext = if (direct_o) |
| 1603 | mod.bin_file.options.root_name | ||
| 1604 | else | ||
| 1605 | mem.split(c_source_basename, ".").next().?; | ||
| 1548 | const o_basename = try std.fmt.allocPrint(arena, "{}{}", .{ o_basename_noext, mod.getTarget().oFileExt() }); | 1606 | const o_basename = try std.fmt.allocPrint(arena, "{}{}", .{ o_basename_noext, mod.getTarget().oFileExt() }); |
| 1549 | 1607 | ||
| 1550 | // We can't know the digest until we do the C compiler invocation, so we need a temporary filename. | 1608 | // 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( | ... | @@ -1749,7 +1807,7 @@ fn addCCArgs( |
| 1749 | try argv.append(p); | 1807 | try argv.append(p); |
| 1750 | } | 1808 | } |
| 1751 | }, | 1809 | }, |
| 1752 | .assembly, .ll, .bc, .unknown => {}, | 1810 | .so, .assembly, .ll, .bc, .unknown => {}, |
| 1753 | } | 1811 | } |
| 1754 | // TODO CLI args for cpu features when compiling assembly | 1812 | // TODO CLI args for cpu features when compiling assembly |
| 1755 | //for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) { | 1813 | //for (size_t i = 0; i < g->zig_target->llvm_cpu_features_asm_len; i += 1) { |
| ... | @@ -4259,6 +4317,7 @@ pub const FileExt = enum { | ... | @@ -4259,6 +4317,7 @@ pub const FileExt = enum { |
| 4259 | ll, | 4317 | ll, |
| 4260 | bc, | 4318 | bc, |
| 4261 | assembly, | 4319 | assembly, |
| 4320 | so, | ||
| 4262 | unknown, | 4321 | unknown, |
| 4263 | }; | 4322 | }; |
| 4264 | 4323 | ||
| ... | @@ -4290,10 +4349,36 @@ pub fn classifyFileExt(filename: []const u8) FileExt { | ... | @@ -4290,10 +4349,36 @@ pub fn classifyFileExt(filename: []const u8) FileExt { |
| 4290 | return .assembly; | 4349 | return .assembly; |
| 4291 | } else if (mem.endsWith(u8, filename, ".h")) { | 4350 | } else if (mem.endsWith(u8, filename, ".h")) { |
| 4292 | return .h; | 4351 | return .h; |
| 4293 | } else { | 4352 | } else if (mem.endsWith(u8, filename, ".so")) { |
| 4294 | // TODO look for .so, .so.X, .so.X.Y, .so.X.Y.Z | 4353 | return .so; |
| 4295 | return .unknown; | 4354 | } |
| 4355 | // Look for .so.X, .so.X.Y, .so.X.Y.Z | ||
| 4356 | var it = mem.split(filename, "."); | ||
| 4357 | _ = it.next().?; | ||
| 4358 | var so_txt = it.next() orelse return .unknown; | ||
| 4359 | while (!mem.eql(u8, so_txt, "so")) { | ||
| 4360 | so_txt = it.next() orelse return .unknown; | ||
| 4296 | } | 4361 | } |
| 4362 | const n1 = it.next() orelse return .unknown; | ||
| 4363 | const n2 = it.next(); | ||
| 4364 | const n3 = it.next(); | ||
| 4365 | |||
| 4366 | _ = std.fmt.parseInt(u32, n1, 10) catch return .unknown; | ||
| 4367 | if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown; | ||
| 4368 | if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown; | ||
| 4369 | if (it.next() != null) return .unknown; | ||
| 4370 | |||
| 4371 | return .so; | ||
| 4372 | } | ||
| 4373 | |||
| 4374 | test "classifyFileExt" { | ||
| 4375 | std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc")); | ||
| 4376 | std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim")); | ||
| 4377 | std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so")); | ||
| 4378 | std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so.1")); | ||
| 4379 | std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so.1.2")); | ||
| 4380 | std.testing.expectEqual(FileExt.so, classifyFileExt("foo.so.1.2.3")); | ||
| 4381 | std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~")); | ||
| 4297 | } | 4382 | } |
| 4298 | 4383 | ||
| 4299 | fn haveFramePointer(mod: *Module) bool { | 4384 | fn haveFramePointer(mod: *Module) bool { |
| ... | @@ -4303,16 +4388,29 @@ fn haveFramePointer(mod: *Module) bool { | ... | @@ -4303,16 +4388,29 @@ fn haveFramePointer(mod: *Module) bool { |
| 4303 | }; | 4388 | }; |
| 4304 | } | 4389 | } |
| 4305 | 4390 | ||
| 4391 | const LibCDirs = struct { | ||
| 4392 | libc_include_dir_list: []const []const u8, | ||
| 4393 | libc_installation: ?*const LibCInstallation, | ||
| 4394 | }; | ||
| 4395 | |||
| 4306 | fn detectLibCIncludeDirs( | 4396 | fn detectLibCIncludeDirs( |
| 4307 | arena: *Allocator, | 4397 | arena: *Allocator, |
| 4308 | zig_lib_dir: []const u8, | 4398 | zig_lib_dir: []const u8, |
| 4309 | target: Target, | 4399 | target: Target, |
| 4400 | is_native_os: bool, | ||
| 4310 | link_libc: bool, | 4401 | link_libc: bool, |
| 4311 | ) ![]const []const u8 { | 4402 | libc_installation: ?*const LibCInstallation, |
| 4312 | if (!link_libc) return &[0][]u8{}; | 4403 | ) !LibCDirs { |
| 4404 | if (!link_libc) { | ||
| 4405 | return LibCDirs{ | ||
| 4406 | .libc_include_dir_list = &[0][]u8{}, | ||
| 4407 | .libc_installation = null, | ||
| 4408 | }; | ||
| 4409 | } | ||
| 4313 | 4410 | ||
| 4314 | // TODO Support --libc file explicitly providing libc paths. Or not? Maybe we are better off | 4411 | if (libc_installation) |lci| { |
| 4315 | // deleting that feature. | 4412 | return detectLibCFromLibCInstallation(arena, target, lci); |
| 4413 | } | ||
| 4316 | 4414 | ||
| 4317 | if (target_util.canBuildLibC(target)) { | 4415 | if (target_util.canBuildLibC(target)) { |
| 4318 | const generic_name = target_util.libCGenericName(target); | 4416 | const generic_name = target_util.libCGenericName(target); |
| ... | @@ -4348,9 +4446,52 @@ fn detectLibCIncludeDirs( | ... | @@ -4348,9 +4446,52 @@ fn detectLibCIncludeDirs( |
| 4348 | list[1] = generic_include_dir; | 4446 | list[1] = generic_include_dir; |
| 4349 | list[2] = arch_os_include_dir; | 4447 | list[2] = arch_os_include_dir; |
| 4350 | list[3] = generic_os_include_dir; | 4448 | list[3] = generic_os_include_dir; |
| 4351 | return list; | 4449 | return LibCDirs{ |
| 4450 | .libc_include_dir_list = list, | ||
| 4451 | .libc_installation = null, | ||
| 4452 | }; | ||
| 4453 | } | ||
| 4454 | |||
| 4455 | if (is_native_os) { | ||
| 4456 | const libc = try arena.create(LibCInstallation); | ||
| 4457 | libc.* = try LibCInstallation.findNative(.{ .allocator = arena }); | ||
| 4458 | return detectLibCFromLibCInstallation(arena, target, libc); | ||
| 4459 | } | ||
| 4460 | |||
| 4461 | return LibCDirs{ | ||
| 4462 | .libc_include_dir_list = &[0][]u8{}, | ||
| 4463 | .libc_installation = null, | ||
| 4464 | }; | ||
| 4465 | } | ||
| 4466 | |||
| 4467 | fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs { | ||
| 4468 | var list = std.ArrayList([]const u8).init(arena); | ||
| 4469 | try list.ensureCapacity(4); | ||
| 4470 | |||
| 4471 | list.appendAssumeCapacity(lci.include_dir.?); | ||
| 4472 | |||
| 4473 | const is_redundant = mem.eql(u8, lci.sys_include_dir.?, lci.include_dir.?); | ||
| 4474 | if (!is_redundant) list.appendAssumeCapacity(lci.sys_include_dir.?); | ||
| 4475 | |||
| 4476 | if (target.os.tag == .windows) { | ||
| 4477 | if (std.fs.path.dirname(lci.include_dir.?)) |include_dir_parent| { | ||
| 4478 | const um_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "um" }); | ||
| 4479 | list.appendAssumeCapacity(um_dir); | ||
| 4480 | |||
| 4481 | const shared_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "shared" }); | ||
| 4482 | list.appendAssumeCapacity(shared_dir); | ||
| 4483 | } | ||
| 4352 | } | 4484 | } |
| 4485 | return LibCDirs{ | ||
| 4486 | .libc_include_dir_list = list.items, | ||
| 4487 | .libc_installation = lci, | ||
| 4488 | }; | ||
| 4489 | } | ||
| 4353 | 4490 | ||
| 4354 | // TODO finish porting detect_libc from codegen.cpp | 4491 | pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8) ![]const u8 { |
| 4355 | return error.LibCDetectionUnimplemented; | 4492 | // TODO port support for building crt files from stage1 |
| 4493 | const lci = mod.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; | ||
| 4494 | const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir; | ||
| 4495 | const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename }); | ||
| 4496 | return full_path; | ||
| 4356 | } | 4497 | } |
src-self-hosted/libc_installation.zig+2| ... | @@ -11,6 +11,8 @@ const is_gnu = Target.current.isGnu(); | ... | @@ -11,6 +11,8 @@ const is_gnu = Target.current.isGnu(); |
| 11 | 11 | ||
| 12 | usingnamespace @import("windows_sdk.zig"); | 12 | usingnamespace @import("windows_sdk.zig"); |
| 13 | 13 | ||
| 14 | // TODO Rework this abstraction to use std.log instead of taking a stderr stream. | ||
| 15 | |||
| 14 | /// See the render function implementation for documentation of the fields. | 16 | /// See the render function implementation for documentation of the fields. |
| 15 | pub const LibCInstallation = struct { | 17 | pub const LibCInstallation = struct { |
| 16 | include_dir: ?[]const u8 = null, | 18 | include_dir: ?[]const u8 = null, |
src-self-hosted/link.zig+19| ... | @@ -6,6 +6,7 @@ const trace = @import("tracy.zig").trace; | ... | @@ -6,6 +6,7 @@ const trace = @import("tracy.zig").trace; |
| 6 | const Package = @import("Package.zig"); | 6 | const Package = @import("Package.zig"); |
| 7 | const Type = @import("type.zig").Type; | 7 | const Type = @import("type.zig").Type; |
| 8 | const build_options = @import("build_options"); | 8 | const build_options = @import("build_options"); |
| 9 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 9 | 10 | ||
| 10 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; | 11 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; |
| 11 | 12 | ||
| ... | @@ -23,6 +24,7 @@ pub const Options = struct { | ... | @@ -23,6 +24,7 @@ pub const Options = struct { |
| 23 | optimize_mode: std.builtin.Mode, | 24 | optimize_mode: std.builtin.Mode, |
| 24 | root_name: []const u8, | 25 | root_name: []const u8, |
| 25 | root_pkg: ?*const Package, | 26 | root_pkg: ?*const Package, |
| 27 | dynamic_linker: ?[]const u8 = null, | ||
| 26 | /// Used for calculating how much space to reserve for symbols in case the binary file | 28 | /// Used for calculating how much space to reserve for symbols in case the binary file |
| 27 | /// does not already have a symbol table. | 29 | /// does not already have a symbol table. |
| 28 | symbol_count_hint: u64 = 32, | 30 | symbol_count_hint: u64 = 32, |
| ... | @@ -30,6 +32,7 @@ pub const Options = struct { | ... | @@ -30,6 +32,7 @@ pub const Options = struct { |
| 30 | /// the binary file does not already have such a section. | 32 | /// the binary file does not already have such a section. |
| 31 | program_code_size_hint: u64 = 256 * 1024, | 33 | program_code_size_hint: u64 = 256 * 1024, |
| 32 | entry_addr: ?u64 = null, | 34 | entry_addr: ?u64 = null, |
| 35 | stack_size_override: ?u64 = null, | ||
| 33 | /// Set to `true` to omit debug info. | 36 | /// Set to `true` to omit debug info. |
| 34 | strip: bool = false, | 37 | strip: bool = false, |
| 35 | /// If this is true then this link code is responsible for outputting an object | 38 | /// If this is true then this link code is responsible for outputting an object |
| ... | @@ -44,6 +47,19 @@ pub const Options = struct { | ... | @@ -44,6 +47,19 @@ pub const Options = struct { |
| 44 | link_libc: bool = false, | 47 | link_libc: bool = false, |
| 45 | link_libcpp: bool = false, | 48 | link_libcpp: bool = false, |
| 46 | function_sections: bool = false, | 49 | function_sections: bool = false, |
| 50 | eh_frame_hdr: bool = false, | ||
| 51 | rdynamic: bool = false, | ||
| 52 | z_nodelete: bool = false, | ||
| 53 | z_defs: bool = false, | ||
| 54 | bind_global_refs_locally: bool, | ||
| 55 | is_native_os: bool, | ||
| 56 | gc_sections: ?bool = null, | ||
| 57 | allow_shlib_undefined: ?bool = null, | ||
| 58 | linker_script: ?[]const u8 = null, | ||
| 59 | version_script: ?[]const u8 = null, | ||
| 60 | override_soname: ?[]const u8 = null, | ||
| 61 | /// Extra args passed directly to LLD. Ignored when not linking with LLD. | ||
| 62 | extra_lld_args: []const []const u8 = &[0][]const u8, | ||
| 47 | 63 | ||
| 48 | objects: []const []const u8 = &[0][]const u8{}, | 64 | objects: []const []const u8 = &[0][]const u8{}, |
| 49 | framework_dirs: []const []const u8 = &[0][]const u8{}, | 65 | framework_dirs: []const []const u8 = &[0][]const u8{}, |
| ... | @@ -52,6 +68,9 @@ pub const Options = struct { | ... | @@ -52,6 +68,9 @@ pub const Options = struct { |
| 52 | lib_dirs: []const []const u8 = &[0][]const u8{}, | 68 | lib_dirs: []const []const u8 = &[0][]const u8{}, |
| 53 | rpath_list: []const []const u8 = &[0][]const u8{}, | 69 | rpath_list: []const []const u8 = &[0][]const u8{}, |
| 54 | 70 | ||
| 71 | version: std.builtin.Version, | ||
| 72 | libc_installation: ?*const LibCInstallation, | ||
| 73 | |||
| 55 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { | 74 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { |
| 56 | return if (options.use_lld) .Obj else options.output_mode; | 75 | return if (options.use_lld) .Obj else options.output_mode; |
| 57 | } | 76 | } |
src-self-hosted/link/Elf.zig+304-6| ... | @@ -18,6 +18,7 @@ const link = @import("../link.zig"); | ... | @@ -18,6 +18,7 @@ const link = @import("../link.zig"); |
| 18 | const File = link.File; | 18 | const File = link.File; |
| 19 | const Elf = @This(); | 19 | const Elf = @This(); |
| 20 | const build_options = @import("build_options"); | 20 | const build_options = @import("build_options"); |
| 21 | const target_util = @import("../target.zig"); | ||
| 21 | 22 | ||
| 22 | const default_entry_addr = 0x8000000; | 23 | const default_entry_addr = 0x8000000; |
| 23 | 24 | ||
| ... | @@ -709,12 +710,7 @@ pub const abbrev_parameter = 6; | ... | @@ -709,12 +710,7 @@ pub const abbrev_parameter = 6; |
| 709 | 710 | ||
| 710 | pub fn flush(self: *Elf, module: *Module) !void { | 711 | pub fn flush(self: *Elf, module: *Module) !void { |
| 711 | if (build_options.have_llvm and self.base.options.use_lld) { | 712 | if (build_options.have_llvm and self.base.options.use_lld) { |
| 712 | // If there is no Zig code to compile, then we should skip flushing the output file because it | 713 | return self.linkWithLLD(module); |
| 713 | // will not be part of the linker line anyway. | ||
| 714 | if (module.root_pkg != null) { | ||
| 715 | try self.flushInner(module); | ||
| 716 | } | ||
| 717 | std.debug.print("TODO create an LLD command line and invoke it\n", .{}); | ||
| 718 | } else { | 714 | } else { |
| 719 | switch (self.base.options.effectiveOutputMode()) { | 715 | switch (self.base.options.effectiveOutputMode()) { |
| 720 | .Exe, .Obj => {}, | 716 | .Exe, .Obj => {}, |
| ... | @@ -1202,6 +1198,275 @@ fn flushInner(self: *Elf, module: *Module) !void { | ... | @@ -1202,6 +1198,275 @@ fn flushInner(self: *Elf, module: *Module) !void { |
| 1202 | assert(!self.debug_strtab_dirty); | 1198 | assert(!self.debug_strtab_dirty); |
| 1203 | } | 1199 | } |
| 1204 | 1200 | ||
| 1201 | fn linkWithLLD(self: *Elf, module: *Module) !void { | ||
| 1202 | // If there is no Zig code to compile, then we should skip flushing the output file because it | ||
| 1203 | // will not be part of the linker line anyway. | ||
| 1204 | if (module.root_pkg != null) { | ||
| 1205 | try self.flushInner(module); | ||
| 1206 | } | ||
| 1207 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); | ||
| 1208 | defer arena_allocator.deinit(); | ||
| 1209 | const arena = &arena_allocator.allocator; | ||
| 1210 | |||
| 1211 | const target = self.base.options.target; | ||
| 1212 | const is_obj = self.base.options.output_mode == .Obj; | ||
| 1213 | |||
| 1214 | // Create an LLD command line and invoke it. | ||
| 1215 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | ||
| 1216 | defer argv.deinit(); | ||
| 1217 | // Even though we're calling LLD as a library it thinks the first argument is its own exe name. | ||
| 1218 | try argv.append("lld"); | ||
| 1219 | if (is_obj) { | ||
| 1220 | try argv.append("-r"); | ||
| 1221 | } | ||
| 1222 | if (self.base.options.output_mode == .Lib and | ||
| 1223 | self.base.options.link_mode == .Static and | ||
| 1224 | !target.isWasm()) | ||
| 1225 | { | ||
| 1226 | // TODO port the code from link.cpp | ||
| 1227 | return error.TODOMakeArchive; | ||
| 1228 | } | ||
| 1229 | const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe; | ||
| 1230 | |||
| 1231 | try argv.append("-error-limit=0"); | ||
| 1232 | |||
| 1233 | if (self.base.options.output_mode == .Exe) { | ||
| 1234 | try argv.append("-z"); | ||
| 1235 | const stack_size = self.base.options.stack_size_override orelse 16777216; | ||
| 1236 | const arg = try std.fmt.allocPrint(arena, "stack-size={}", .{stack_size}); | ||
| 1237 | try argv.append(arg); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | if (self.base.options.linker_script) |linker_script| { | ||
| 1241 | try argv.append("-T"); | ||
| 1242 | try argv.append(linker_script); | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | const gc_sections = self.base.options.gc_sections orelse !is_obj; | ||
| 1246 | if (gc_sections) { | ||
| 1247 | try argv.append("--gc-sections"); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | if (self.base.options.eh_frame_hdr) { | ||
| 1251 | try argv.append("--eh-frame-hdr"); | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | if (self.base.options.rdynamic) { | ||
| 1255 | try argv.append("--export-dynamic"); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | try argv.appendSlice(self.base.options.extra_lld_args); | ||
| 1259 | |||
| 1260 | if (self.base.options.z_nodelete) { | ||
| 1261 | try argv.append("-z"); | ||
| 1262 | try argv.append("nodelete"); | ||
| 1263 | } | ||
| 1264 | if (self.base.options.z_defs) { | ||
| 1265 | try argv.append("-z"); | ||
| 1266 | try argv.append("defs"); | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | if (getLDMOption(target)) |ldm| { | ||
| 1270 | // Any target ELF will use the freebsd osabi if suffixed with "_fbsd". | ||
| 1271 | const arg = if (target.os.tag == .freebsd) | ||
| 1272 | try std.fmt.allocPrint(arena, "{}_fbsd", .{ldm}) | ||
| 1273 | else | ||
| 1274 | ldm; | ||
| 1275 | try argv.append("-m"); | ||
| 1276 | try argv.append(arg); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | const is_lib = self.base.options.output_mode == .Lib; | ||
| 1280 | const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; | ||
| 1281 | if (self.base.options.link_mode == .Static) { | ||
| 1282 | if (target.cpu.arch.isARM() or target.cpu.arch.isThumb()) { | ||
| 1283 | try argv.append("-Bstatic"); | ||
| 1284 | } else { | ||
| 1285 | try argv.append("-static"); | ||
| 1286 | } | ||
| 1287 | } else if (is_dyn_lib) { | ||
| 1288 | try argv.append("-shared"); | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) { | ||
| 1292 | try argv.append("-pie"); | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | const full_out_path = if (self.base.options.dir_path) |dir_path| | ||
| 1296 | try std.fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path}) | ||
| 1297 | else | ||
| 1298 | self.base.options.sub_path; | ||
| 1299 | try argv.append("-o"); | ||
| 1300 | try argv.append(full_out_path); | ||
| 1301 | |||
| 1302 | if (link_in_crt) { | ||
| 1303 | const crt1o: []const u8 = o: { | ||
| 1304 | if (target.os.tag == .netbsd) { | ||
| 1305 | break :o "crt0.o"; | ||
| 1306 | } else if (target.isAndroid()) { | ||
| 1307 | if (self.base.options.link_mode == .Dynamic) { | ||
| 1308 | break :o "crtbegin_dynamic.o"; | ||
| 1309 | } else { | ||
| 1310 | break :o "crtbegin_static.o"; | ||
| 1311 | } | ||
| 1312 | } else if (self.base.options.link_mode == .Static) { | ||
| 1313 | break :o "crt1.o"; | ||
| 1314 | } else { | ||
| 1315 | break :o "Scrt1.o"; | ||
| 1316 | } | ||
| 1317 | }; | ||
| 1318 | try argv.append(try module.get_libc_crt_file(arena, crt1o)); | ||
| 1319 | if (target_util.libc_needs_crti_crtn(target)) { | ||
| 1320 | try argv.append(try module.get_libc_crt_file(arena, "crti.o")); | ||
| 1321 | } | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | // TODO rpaths | ||
| 1325 | //for (size_t i = 0; i < g->rpath_list.length; i += 1) { | ||
| 1326 | // Buf *rpath = g->rpath_list.at(i); | ||
| 1327 | // add_rpath(lj, rpath); | ||
| 1328 | //} | ||
| 1329 | //if (g->each_lib_rpath) { | ||
| 1330 | // for (size_t i = 0; i < g->lib_dirs.length; i += 1) { | ||
| 1331 | // const char *lib_dir = g->lib_dirs.at(i); | ||
| 1332 | // for (size_t i = 0; i < g->link_libs_list.length; i += 1) { | ||
| 1333 | // LinkLib *link_lib = g->link_libs_list.at(i); | ||
| 1334 | // if (buf_eql_str(link_lib->name, "c")) { | ||
| 1335 | // continue; | ||
| 1336 | // } | ||
| 1337 | // bool does_exist; | ||
| 1338 | // Buf *test_path = buf_sprintf("%s/lib%s.so", lib_dir, buf_ptr(link_lib->name)); | ||
| 1339 | // if (os_file_exists(test_path, &does_exist) != ErrorNone) { | ||
| 1340 | // zig_panic("link: unable to check if file exists: %s", buf_ptr(test_path)); | ||
| 1341 | // } | ||
| 1342 | // if (does_exist) { | ||
| 1343 | // add_rpath(lj, buf_create_from_str(lib_dir)); | ||
| 1344 | // break; | ||
| 1345 | // } | ||
| 1346 | // } | ||
| 1347 | // } | ||
| 1348 | //} | ||
| 1349 | |||
| 1350 | for (self.base.options.lib_dirs) |lib_dir| { | ||
| 1351 | try argv.append("-L"); | ||
| 1352 | try argv.append(lib_dir); | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | if (self.base.options.link_libc) { | ||
| 1356 | if (self.base.options.libc_installation) |libc_installation| { | ||
| 1357 | try argv.append("-L"); | ||
| 1358 | try argv.append(libc_installation.crt_dir.?); | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | if (self.base.options.link_mode == .Dynamic and (is_dyn_lib or self.base.options.output_mode == .Exe)) { | ||
| 1362 | if (self.base.options.dynamic_linker) |dynamic_linker| { | ||
| 1363 | try argv.append("-dynamic-linker"); | ||
| 1364 | try argv.append(dynamic_linker); | ||
| 1365 | } | ||
| 1366 | } | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | if (is_dyn_lib) { | ||
| 1370 | const soname = self.base.options.override_soname orelse | ||
| 1371 | try std.fmt.allocPrint(arena, "lib{}.so.{}", .{self.base.options.root_name, | ||
| 1372 | self.base.options.version.major,}); | ||
| 1373 | try argv.append("-soname"); | ||
| 1374 | try argv.append(soname); | ||
| 1375 | |||
| 1376 | if (self.base.options.version_script) |version_script| { | ||
| 1377 | try argv.append("-version-script"); | ||
| 1378 | try argv.append(version_script); | ||
| 1379 | } | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | // Positional arguments to the linker such as object files. | ||
| 1383 | try argv.appendSlice(self.base.options.objects); | ||
| 1384 | |||
| 1385 | // TODO compiler-rt and libc | ||
| 1386 | //if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) { | ||
| 1387 | // if (g->libc_link_lib == nullptr) { | ||
| 1388 | // Buf *libc_a_path = build_c(g, OutTypeLib, lj->build_dep_prog_node); | ||
| 1389 | // try argv.append(buf_ptr(libc_a_path)); | ||
| 1390 | // } | ||
| 1391 | |||
| 1392 | // Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib, lj->build_dep_prog_node); | ||
| 1393 | // try argv.append(buf_ptr(compiler_rt_o_path)); | ||
| 1394 | //} | ||
| 1395 | |||
| 1396 | // Shared libraries. | ||
| 1397 | try argv.ensureCapacity(argv.items.len + self.base.options.system_libs.len); | ||
| 1398 | for (self.base.options.system_libs) |link_lib| { | ||
| 1399 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries | ||
| 1400 | // (the check for that needs to be earlier), but they could be full paths to .so files, in which | ||
| 1401 | // case we want to avoid prepending "-l". | ||
| 1402 | const ext = Module.classifyFileExt(link_lib); | ||
| 1403 | const arg = if (ext == .so) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib}); | ||
| 1404 | argv.appendAssumeCapacity(arg); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | if (!is_obj) { | ||
| 1408 | // libc++ dep | ||
| 1409 | if (self.base.options.link_libcpp) { | ||
| 1410 | try argv.append(module.libcxxabi_static_lib.?); | ||
| 1411 | try argv.append(module.libcxx_static_lib.?); | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | // libc dep | ||
| 1415 | if (self.base.options.link_libc) { | ||
| 1416 | if (self.base.options.libc_installation != null) { | ||
| 1417 | if (self.base.options.link_mode == .Static) { | ||
| 1418 | try argv.append("--start-group"); | ||
| 1419 | try argv.append("-lc"); | ||
| 1420 | try argv.append("-lm"); | ||
| 1421 | try argv.append("--end-group"); | ||
| 1422 | } else { | ||
| 1423 | try argv.append("-lc"); | ||
| 1424 | try argv.append("-lm"); | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | if (target.os.tag == .freebsd or target.os.tag == .netbsd) { | ||
| 1428 | try argv.append("-lpthread"); | ||
| 1429 | } | ||
| 1430 | } else if (target.isGnuLibC()) { | ||
| 1431 | try argv.append(module.libunwind_static_lib.?); | ||
| 1432 | // TODO here we need to iterate over the glibc libs and add the .so files to the linker line. | ||
| 1433 | std.log.warn("TODO port add_glibc_libs to stage2", .{}); | ||
| 1434 | try argv.append(try module.get_libc_crt_file(arena, "libc_nonshared.a")); | ||
| 1435 | } else if (target.isMusl()) { | ||
| 1436 | try argv.append(module.libunwind_static_lib.?); | ||
| 1437 | try argv.append(module.libc_static_lib.?); | ||
| 1438 | } else if (self.base.options.link_libcpp) { | ||
| 1439 | try argv.append(module.libunwind_static_lib.?); | ||
| 1440 | } else { | ||
| 1441 | unreachable; // Compiler was supposed to emit an error for not being able to provide libc. | ||
| 1442 | } | ||
| 1443 | } | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | // crt end | ||
| 1447 | if (link_in_crt) { | ||
| 1448 | if (target.isAndroid()) { | ||
| 1449 | try argv.append(try module.get_libc_crt_file(arena, "crtend_android.o")); | ||
| 1450 | } else if (target_util.libc_needs_crti_crtn(target)) { | ||
| 1451 | try argv.append(try module.get_libc_crt_file(arena, "crtn.o")); | ||
| 1452 | } | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; | ||
| 1456 | if (allow_shlib_undefined) { | ||
| 1457 | try argv.append("--allow-shlib-undefined"); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | if (self.base.options.bind_global_refs_locally) { | ||
| 1461 | try argv.append("-Bsymbolic"); | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | for (argv.items) |arg| { | ||
| 1465 | std.debug.print("{} ", .{arg}); | ||
| 1466 | } | ||
| 1467 | @panic("invoke LLD"); | ||
| 1468 | } | ||
| 1469 | |||
| 1205 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { | 1470 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { |
| 1206 | const target_endian = self.base.options.target.cpu.arch.endian(); | 1471 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 1207 | switch (self.ptr_width) { | 1472 | switch (self.ptr_width) { |
| ... | @@ -2616,3 +2881,36 @@ fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { | ... | @@ -2616,3 +2881,36 @@ fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { |
| 2616 | .sh_entsize = @intCast(u32, shdr.sh_entsize), | 2881 | .sh_entsize = @intCast(u32, shdr.sh_entsize), |
| 2617 | }; | 2882 | }; |
| 2618 | } | 2883 | } |
| 2884 | |||
| 2885 | fn getLDMOption(target: std.Target) ?[]const u8 { | ||
| 2886 | switch (target.cpu.arch) { | ||
| 2887 | .i386 => return "elf_i386", | ||
| 2888 | .aarch64 => return "aarch64linux", | ||
| 2889 | .aarch64_be => return "aarch64_be_linux", | ||
| 2890 | .arm, .thumb => return "armelf_linux_eabi", | ||
| 2891 | .armeb, .thumbeb => return "armebelf_linux_eabi", | ||
| 2892 | .powerpc => return "elf32ppclinux", | ||
| 2893 | .powerpc64 => return "elf64ppc", | ||
| 2894 | .powerpc64le => return "elf64lppc", | ||
| 2895 | .sparc, .sparcel => return "elf32_sparc", | ||
| 2896 | .sparcv9 => return "elf64_sparc", | ||
| 2897 | .mips => return "elf32btsmip", | ||
| 2898 | .mipsel => return "elf32ltsmip", | ||
| 2899 | .mips64 => return "elf64btsmip", | ||
| 2900 | .mips64el => return "elf64ltsmip", | ||
| 2901 | .s390x => return "elf64_s390", | ||
| 2902 | .x86_64 => { | ||
| 2903 | if (target.abi == .gnux32) { | ||
| 2904 | return "elf32_x86_64"; | ||
| 2905 | } | ||
| 2906 | // Any target elf will use the freebsd osabi if suffixed with "_fbsd". | ||
| 2907 | if (target.os.tag == .freebsd) { | ||
| 2908 | return "elf_x86_64_fbsd"; | ||
| 2909 | } | ||
| 2910 | return "elf_x86_64"; | ||
| 2911 | }, | ||
| 2912 | .riscv32 => return "elf32lriscv", | ||
| 2913 | .riscv64 => return "elf64lriscv", | ||
| 2914 | else => return null, | ||
| 2915 | } | ||
| 2916 | } |
src-self-hosted/main.zig+116-32| ... | @@ -14,6 +14,7 @@ const zir = @import("zir.zig"); | ... | @@ -14,6 +14,7 @@ const zir = @import("zir.zig"); |
| 14 | const build_options = @import("build_options"); | 14 | const build_options = @import("build_options"); |
| 15 | const warn = std.log.warn; | 15 | const warn = std.log.warn; |
| 16 | const introspect = @import("introspect.zig"); | 16 | const introspect = @import("introspect.zig"); |
| 17 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 17 | 18 | ||
| 18 | fn fatal(comptime format: []const u8, args: anytype) noreturn { | 19 | fn fatal(comptime format: []const u8, args: anytype) noreturn { |
| 19 | std.log.emerg(format, args); | 20 | std.log.emerg(format, args); |
| ... | @@ -33,18 +34,22 @@ const usage = | ... | @@ -33,18 +34,22 @@ const usage = |
| 33 | \\ | 34 | \\ |
| 34 | \\Commands: | 35 | \\Commands: |
| 35 | \\ | 36 | \\ |
| 36 | \\ build-exe [source] Create executable from source or object files | 37 | \\ build-exe Create executable from source or object files |
| 37 | \\ build-lib [source] Create library from source or object files | 38 | \\ build-lib Create library from source or object files |
| 38 | \\ build-obj [source] Create object from source or assembly | 39 | \\ build-obj Create object from source or assembly |
| 39 | \\ cc Use Zig as a drop-in C compiler | 40 | \\ cc Use Zig as a drop-in C compiler |
| 40 | \\ c++ Use Zig as a drop-in C++ compiler | 41 | \\ c++ Use Zig as a drop-in C++ compiler |
| 41 | \\ env Print lib path, std path, compiler id and version | 42 | \\ env Print lib path, std path, compiler id and version |
| 42 | \\ fmt [source] Parse file and render in canonical zig format | 43 | \\ fmt Parse file and render in canonical zig format |
| 43 | \\ translate-c [source] Convert C code to Zig code | 44 | \\ libc Display native libc paths file or validate one |
| 44 | \\ targets List available compilation targets | 45 | \\ translate-c Convert C code to Zig code |
| 45 | \\ version Print version number and exit | 46 | \\ targets List available compilation targets |
| 46 | \\ zen Print zen of zig and exit | 47 | \\ version Print version number and exit |
| 48 | \\ zen Print zen of zig and exit | ||
| 47 | \\ | 49 | \\ |
| 50 | \\General Options: | ||
| 51 | \\ | ||
| 52 | \\ --help Print command-specific usage | ||
| 48 | \\ | 53 | \\ |
| 49 | ; | 54 | ; |
| 50 | 55 | ||
| ... | @@ -126,6 +131,8 @@ pub fn main() !void { | ... | @@ -126,6 +131,8 @@ pub fn main() !void { |
| 126 | return punt_to_clang(arena, args); | 131 | return punt_to_clang(arena, args); |
| 127 | } else if (mem.eql(u8, cmd, "fmt")) { | 132 | } else if (mem.eql(u8, cmd, "fmt")) { |
| 128 | return cmdFmt(gpa, cmd_args); | 133 | return cmdFmt(gpa, cmd_args); |
| 134 | } else if (mem.eql(u8, cmd, "libc")) { | ||
| 135 | return cmdLibC(gpa, cmd_args); | ||
| 129 | } else if (mem.eql(u8, cmd, "targets")) { | 136 | } else if (mem.eql(u8, cmd, "targets")) { |
| 130 | const info = try std.zig.system.NativeTargetInfo.detect(arena, .{}); | 137 | const info = try std.zig.system.NativeTargetInfo.detect(arena, .{}); |
| 131 | const stdout = io.getStdOut().outStream(); | 138 | const stdout = io.getStdOut().outStream(); |
| ... | @@ -184,7 +191,6 @@ const usage_build_generic = | ... | @@ -184,7 +191,6 @@ const usage_build_generic = |
| 184 | \\ ReleaseSmall Optimize for small binary, safety off | 191 | \\ ReleaseSmall Optimize for small binary, safety off |
| 185 | \\ -fPIC Force-enable Position Independent Code | 192 | \\ -fPIC Force-enable Position Independent Code |
| 186 | \\ -fno-PIC Force-disable Position Independent Code | 193 | \\ -fno-PIC Force-disable Position Independent Code |
| 187 | \\ --dynamic Force output to be dynamically linked | ||
| 188 | \\ --strip Exclude debug symbols | 194 | \\ --strip Exclude debug symbols |
| 189 | \\ -ofmt=[mode] Override target object format | 195 | \\ -ofmt=[mode] Override target object format |
| 190 | \\ elf Executable and Linking Format | 196 | \\ elf Executable and Linking Format |
| ... | @@ -199,6 +205,7 @@ const usage_build_generic = | ... | @@ -199,6 +205,7 @@ const usage_build_generic = |
| 199 | \\ -isystem [dir] Add directory to SYSTEM include search path | 205 | \\ -isystem [dir] Add directory to SYSTEM include search path |
| 200 | \\ -I[dir] Add directory to include search path | 206 | \\ -I[dir] Add directory to include search path |
| 201 | \\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted) | 207 | \\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted) |
| 208 | \\ --libc [file] Provide a file which specifies libc paths | ||
| 202 | \\ | 209 | \\ |
| 203 | \\Link Options: | 210 | \\Link Options: |
| 204 | \\ -l[lib], --library [lib] Link against system library | 211 | \\ -l[lib], --library [lib] Link against system library |
| ... | @@ -208,6 +215,9 @@ const usage_build_generic = | ... | @@ -208,6 +215,9 @@ const usage_build_generic = |
| 208 | \\ --version [ver] Dynamic library semver | 215 | \\ --version [ver] Dynamic library semver |
| 209 | \\ -rdynamic Add all symbols to the dynamic symbol table | 216 | \\ -rdynamic Add all symbols to the dynamic symbol table |
| 210 | \\ -rpath [path] Add directory to the runtime library search path | 217 | \\ -rpath [path] Add directory to the runtime library search path |
| 218 | \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker | ||
| 219 | \\ -dynamic Force output to be dynamically linked | ||
| 220 | \\ -static Force output to be statically linked | ||
| 211 | \\ | 221 | \\ |
| 212 | \\Debug Options (Zig Compiler Development): | 222 | \\Debug Options (Zig Compiler Development): |
| 213 | \\ -ftime-report Print timing diagnostics | 223 | \\ -ftime-report Print timing diagnostics |
| ... | @@ -220,6 +230,14 @@ const usage_build_generic = | ... | @@ -220,6 +230,14 @@ const usage_build_generic = |
| 220 | \\ | 230 | \\ |
| 221 | ; | 231 | ; |
| 222 | 232 | ||
| 233 | const repl_help = | ||
| 234 | \\Commands: | ||
| 235 | \\ update Detect changes to source files and update output files. | ||
| 236 | \\ help Print this text | ||
| 237 | \\ exit Quit this repl | ||
| 238 | \\ | ||
| 239 | ; | ||
| 240 | |||
| 223 | const Emit = union(enum) { | 241 | const Emit = union(enum) { |
| 224 | no, | 242 | no, |
| 225 | yes_default_path, | 243 | yes_default_path, |
| ... | @@ -275,16 +293,17 @@ pub fn buildOutputType( | ... | @@ -275,16 +293,17 @@ pub fn buildOutputType( |
| 275 | var version_script: ?[]const u8 = null; | 293 | var version_script: ?[]const u8 = null; |
| 276 | var disable_c_depfile = false; | 294 | var disable_c_depfile = false; |
| 277 | var override_soname: ?[]const u8 = null; | 295 | var override_soname: ?[]const u8 = null; |
| 278 | var linker_optimization: ?[]const u8 = null; | ||
| 279 | var linker_gc_sections: ?bool = null; | 296 | var linker_gc_sections: ?bool = null; |
| 280 | var linker_allow_shlib_undefined: ?bool = null; | 297 | var linker_allow_shlib_undefined: ?bool = null; |
| 281 | var linker_bind_global_refs_locally: ?bool = null; | 298 | var linker_bind_global_refs_locally: ?bool = null; |
| 282 | var linker_z_nodelete = false; | 299 | var linker_z_nodelete = false; |
| 283 | var linker_z_defs = false; | 300 | var linker_z_defs = false; |
| 284 | var stack_size_override: u64 = 0; | 301 | var stack_size_override: ?u64 = null; |
| 285 | var use_llvm: ?bool = null; | 302 | var use_llvm: ?bool = null; |
| 286 | var use_lld: ?bool = null; | 303 | var use_lld: ?bool = null; |
| 287 | var use_clang: ?bool = null; | 304 | var use_clang: ?bool = null; |
| 305 | var link_eh_frame_hdr = false; | ||
| 306 | var libc_paths_file: ?[]const u8 = null; | ||
| 288 | 307 | ||
| 289 | var system_libs = std.ArrayList([]const u8).init(gpa); | 308 | var system_libs = std.ArrayList([]const u8).init(gpa); |
| 290 | defer system_libs.deinit(); | 309 | defer system_libs.deinit(); |
| ... | @@ -292,6 +311,9 @@ pub fn buildOutputType( | ... | @@ -292,6 +311,9 @@ pub fn buildOutputType( |
| 292 | var clang_argv = std.ArrayList([]const u8).init(gpa); | 311 | var clang_argv = std.ArrayList([]const u8).init(gpa); |
| 293 | defer clang_argv.deinit(); | 312 | defer clang_argv.deinit(); |
| 294 | 313 | ||
| 314 | var lld_argv = std.ArrayList([]const u8).init(gpa); | ||
| 315 | defer lld_argv.deinit(); | ||
| 316 | |||
| 295 | var lib_dirs = std.ArrayList([]const u8).init(gpa); | 317 | var lib_dirs = std.ArrayList([]const u8).init(gpa); |
| 296 | defer lib_dirs.deinit(); | 318 | defer lib_dirs.deinit(); |
| 297 | 319 | ||
| ... | @@ -414,15 +436,11 @@ pub fn buildOutputType( | ... | @@ -414,15 +436,11 @@ pub fn buildOutputType( |
| 414 | fatal("unable to parse --version '{}': {}", .{ args[i], @errorName(err) }); | 436 | fatal("unable to parse --version '{}': {}", .{ args[i], @errorName(err) }); |
| 415 | }; | 437 | }; |
| 416 | } else if (mem.eql(u8, arg, "-target")) { | 438 | } else if (mem.eql(u8, arg, "-target")) { |
| 417 | if (i + 1 >= args.len) { | 439 | if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); |
| 418 | fatal("expected parameter after -target", .{}); | ||
| 419 | } | ||
| 420 | i += 1; | 440 | i += 1; |
| 421 | target_arch_os_abi = args[i]; | 441 | target_arch_os_abi = args[i]; |
| 422 | } else if (mem.eql(u8, arg, "-mcpu")) { | 442 | } else if (mem.eql(u8, arg, "-mcpu")) { |
| 423 | if (i + 1 >= args.len) { | 443 | if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); |
| 424 | fatal("expected parameter after -mcpu", .{}); | ||
| 425 | } | ||
| 426 | i += 1; | 444 | i += 1; |
| 427 | target_mcpu = args[i]; | 445 | target_mcpu = args[i]; |
| 428 | } else if (mem.startsWith(u8, arg, "-ofmt=")) { | 446 | } else if (mem.startsWith(u8, arg, "-ofmt=")) { |
| ... | @@ -430,11 +448,13 @@ pub fn buildOutputType( | ... | @@ -430,11 +448,13 @@ pub fn buildOutputType( |
| 430 | } else if (mem.startsWith(u8, arg, "-mcpu=")) { | 448 | } else if (mem.startsWith(u8, arg, "-mcpu=")) { |
| 431 | target_mcpu = arg["-mcpu=".len..]; | 449 | target_mcpu = arg["-mcpu=".len..]; |
| 432 | } else if (mem.eql(u8, arg, "--dynamic-linker")) { | 450 | } else if (mem.eql(u8, arg, "--dynamic-linker")) { |
| 433 | if (i + 1 >= args.len) { | 451 | if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); |
| 434 | fatal("expected parameter after --dynamic-linker", .{}); | ||
| 435 | } | ||
| 436 | i += 1; | 452 | i += 1; |
| 437 | target_dynamic_linker = args[i]; | 453 | target_dynamic_linker = args[i]; |
| 454 | } else if (mem.eql(u8, arg, "--libc")) { | ||
| 455 | if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); | ||
| 456 | i += 1; | ||
| 457 | libc_paths_file = args[i]; | ||
| 438 | } else if (mem.eql(u8, arg, "--watch")) { | 458 | } else if (mem.eql(u8, arg, "--watch")) { |
| 439 | watch = true; | 459 | watch = true; |
| 440 | } else if (mem.eql(u8, arg, "-ftime-report")) { | 460 | } else if (mem.eql(u8, arg, "-ftime-report")) { |
| ... | @@ -481,6 +501,8 @@ pub fn buildOutputType( | ... | @@ -481,6 +501,8 @@ pub fn buildOutputType( |
| 481 | link_mode = .Static; | 501 | link_mode = .Static; |
| 482 | } else if (mem.eql(u8, arg, "--strip")) { | 502 | } else if (mem.eql(u8, arg, "--strip")) { |
| 483 | strip = true; | 503 | strip = true; |
| 504 | } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { | ||
| 505 | link_eh_frame_hdr = true; | ||
| 484 | } else if (mem.eql(u8, arg, "-Bsymbolic")) { | 506 | } else if (mem.eql(u8, arg, "-Bsymbolic")) { |
| 485 | linker_bind_global_refs_locally = true; | 507 | linker_bind_global_refs_locally = true; |
| 486 | } else if (mem.eql(u8, arg, "--debug-tokenize")) { | 508 | } else if (mem.eql(u8, arg, "--debug-tokenize")) { |
| ... | @@ -565,7 +587,7 @@ pub fn buildOutputType( | ... | @@ -565,7 +587,7 @@ pub fn buildOutputType( |
| 565 | const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg)); | 587 | const file_ext = Module.classifyFileExt(mem.spanZ(it.only_arg)); |
| 566 | switch (file_ext) { | 588 | switch (file_ext) { |
| 567 | .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg), | 589 | .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(it.only_arg), |
| 568 | .unknown => try link_objects.append(it.only_arg), | 590 | .unknown, .so => try link_objects.append(it.only_arg), |
| 569 | } | 591 | } |
| 570 | }, | 592 | }, |
| 571 | .l => { | 593 | .l => { |
| ... | @@ -716,7 +738,7 @@ pub fn buildOutputType( | ... | @@ -716,7 +738,7 @@ pub fn buildOutputType( |
| 716 | } | 738 | } |
| 717 | version_script = linker_args.items[i]; | 739 | version_script = linker_args.items[i]; |
| 718 | } else if (mem.startsWith(u8, arg, "-O")) { | 740 | } else if (mem.startsWith(u8, arg, "-O")) { |
| 719 | linker_optimization = arg; | 741 | try lld_argv.append(arg); |
| 720 | } else if (mem.eql(u8, arg, "--gc-sections")) { | 742 | } else if (mem.eql(u8, arg, "--gc-sections")) { |
| 721 | linker_gc_sections = true; | 743 | linker_gc_sections = true; |
| 722 | } else if (mem.eql(u8, arg, "--no-gc-sections")) { | 744 | } else if (mem.eql(u8, arg, "--no-gc-sections")) { |
| ... | @@ -994,10 +1016,21 @@ pub fn buildOutputType( | ... | @@ -994,10 +1016,21 @@ pub fn buildOutputType( |
| 994 | }; | 1016 | }; |
| 995 | var default_prng = std.rand.DefaultPrng.init(random_seed); | 1017 | var default_prng = std.rand.DefaultPrng.init(random_seed); |
| 996 | 1018 | ||
| 1019 | var libc_installation: ?LibCInstallation = null; | ||
| 1020 | defer if (libc_installation) |*l| l.deinit(gpa); | ||
| 1021 | |||
| 1022 | if (libc_paths_file) |paths_file| { | ||
| 1023 | libc_installation = LibCInstallation.parse(gpa, paths_file, io.getStdErr().writer()) catch |err| { | ||
| 1024 | fatal("unable to parse libc paths file: {}", .{@errorName(err)}); | ||
| 1025 | }; | ||
| 1026 | } | ||
| 1027 | |||
| 997 | const module = Module.create(gpa, .{ | 1028 | const module = Module.create(gpa, .{ |
| 998 | .zig_lib_dir = zig_lib_dir, | 1029 | .zig_lib_dir = zig_lib_dir, |
| 999 | .root_name = root_name, | 1030 | .root_name = root_name, |
| 1000 | .target = target_info.target, | 1031 | .target = target_info.target, |
| 1032 | .is_native_os = cross_target.isNativeOs(), | ||
| 1033 | .dynamic_linker = target_info.dynamic_linker.get(), | ||
| 1001 | .output_mode = output_mode, | 1034 | .output_mode = output_mode, |
| 1002 | .root_pkg = root_pkg, | 1035 | .root_pkg = root_pkg, |
| 1003 | .bin_file_dir_path = null, | 1036 | .bin_file_dir_path = null, |
| ... | @@ -1008,6 +1041,7 @@ pub fn buildOutputType( | ... | @@ -1008,6 +1041,7 @@ pub fn buildOutputType( |
| 1008 | .optimize_mode = build_mode, | 1041 | .optimize_mode = build_mode, |
| 1009 | .keep_source_files_loaded = zir_out_path != null, | 1042 | .keep_source_files_loaded = zir_out_path != null, |
| 1010 | .clang_argv = clang_argv.items, | 1043 | .clang_argv = clang_argv.items, |
| 1044 | .lld_argv = lld_argv.items, | ||
| 1011 | .lib_dirs = lib_dirs.items, | 1045 | .lib_dirs = lib_dirs.items, |
| 1012 | .rpath_list = rpath_list.items, | 1046 | .rpath_list = rpath_list.items, |
| 1013 | .c_source_files = c_source_files.items, | 1047 | .c_source_files = c_source_files.items, |
| ... | @@ -1028,17 +1062,19 @@ pub fn buildOutputType( | ... | @@ -1028,17 +1062,19 @@ pub fn buildOutputType( |
| 1028 | .version_script = version_script, | 1062 | .version_script = version_script, |
| 1029 | .disable_c_depfile = disable_c_depfile, | 1063 | .disable_c_depfile = disable_c_depfile, |
| 1030 | .override_soname = override_soname, | 1064 | .override_soname = override_soname, |
| 1031 | .linker_optimization = linker_optimization, | ||
| 1032 | .linker_gc_sections = linker_gc_sections, | 1065 | .linker_gc_sections = linker_gc_sections, |
| 1033 | .linker_allow_shlib_undefined = linker_allow_shlib_undefined, | 1066 | .linker_allow_shlib_undefined = linker_allow_shlib_undefined, |
| 1034 | .linker_bind_global_refs_locally = linker_bind_global_refs_locally, | 1067 | .linker_bind_global_refs_locally = linker_bind_global_refs_locally, |
| 1035 | .linker_z_nodelete = linker_z_nodelete, | 1068 | .linker_z_nodelete = linker_z_nodelete, |
| 1036 | .linker_z_defs = linker_z_defs, | 1069 | .linker_z_defs = linker_z_defs, |
| 1070 | .link_eh_frame_hdr = link_eh_frame_hdr, | ||
| 1037 | .stack_size_override = stack_size_override, | 1071 | .stack_size_override = stack_size_override, |
| 1038 | .strip = strip, | 1072 | .strip = strip, |
| 1039 | .self_exe_path = self_exe_path, | 1073 | .self_exe_path = self_exe_path, |
| 1040 | .rand = &default_prng.random, | 1074 | .rand = &default_prng.random, |
| 1041 | .clang_passthrough_mode = arg_mode != .build, | 1075 | .clang_passthrough_mode = arg_mode != .build, |
| 1076 | .version = version, | ||
| 1077 | .libc_installation = if (libc_installation) |*lci| lci else null, | ||
| 1042 | }) catch |err| { | 1078 | }) catch |err| { |
| 1043 | fatal("unable to create module: {}", .{@errorName(err)}); | 1079 | fatal("unable to create module: {}", .{@errorName(err)}); |
| 1044 | }; | 1080 | }; |
| ... | @@ -1116,16 +1152,64 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo | ... | @@ -1116,16 +1152,64 @@ fn updateModule(gpa: *Allocator, module: *Module, zir_out_path: ?[]const u8) !vo |
| 1116 | } | 1152 | } |
| 1117 | } | 1153 | } |
| 1118 | 1154 | ||
| 1119 | const repl_help = | 1155 | pub const usage_libc = |
| 1120 | \\Commands: | 1156 | \\Usage: zig libc |
| 1121 | \\ update Detect changes to source files and update output files. | 1157 | \\ |
| 1122 | \\ help Print this text | 1158 | \\ Detect the native libc installation and print the resulting |
| 1123 | \\ exit Quit this repl | 1159 | \\ paths to stdout. You can save this into a file and then edit |
| 1160 | \\ the paths to create a cross compilation libc kit. Then you | ||
| 1161 | \\ can pass `--libc [file]` for Zig to use it. | ||
| 1162 | \\ | ||
| 1163 | \\Usage: zig libc [paths_file] | ||
| 1164 | \\ | ||
| 1165 | \\ Parse a libc installation text file and validate it. | ||
| 1124 | \\ | 1166 | \\ |
| 1125 | ; | 1167 | ; |
| 1126 | 1168 | ||
| 1169 | pub fn cmdLibC(gpa: *Allocator, args: []const []const u8) !void { | ||
| 1170 | var input_file: ?[]const u8 = null; | ||
| 1171 | { | ||
| 1172 | var i: usize = 0; | ||
| 1173 | while (i < args.len) : (i += 1) { | ||
| 1174 | const arg = args[i]; | ||
| 1175 | if (mem.startsWith(u8, arg, "-")) { | ||
| 1176 | if (mem.eql(u8, arg, "--help")) { | ||
| 1177 | const stdout = io.getStdOut().writer(); | ||
| 1178 | try stdout.writeAll(usage_libc); | ||
| 1179 | process.exit(0); | ||
| 1180 | } else { | ||
| 1181 | fatal("unrecognized parameter: '{}'", .{arg}); | ||
| 1182 | } | ||
| 1183 | } else if (input_file != null) { | ||
| 1184 | fatal("unexpected extra parameter: '{}'", .{arg}); | ||
| 1185 | } else { | ||
| 1186 | input_file = arg; | ||
| 1187 | } | ||
| 1188 | } | ||
| 1189 | } | ||
| 1190 | if (input_file) |libc_file| { | ||
| 1191 | const stderr = std.io.getStdErr().writer(); | ||
| 1192 | var libc = LibCInstallation.parse(gpa, libc_file, stderr) catch |err| { | ||
| 1193 | fatal("unable to parse libc file: {}", .{@errorName(err)}); | ||
| 1194 | }; | ||
| 1195 | defer libc.deinit(gpa); | ||
| 1196 | } else { | ||
| 1197 | var libc = LibCInstallation.findNative(.{ | ||
| 1198 | .allocator = gpa, | ||
| 1199 | .verbose = true, | ||
| 1200 | }) catch |err| { | ||
| 1201 | fatal("unable to detect native libc: {}", .{@errorName(err)}); | ||
| 1202 | }; | ||
| 1203 | defer libc.deinit(gpa); | ||
| 1204 | |||
| 1205 | var bos = io.bufferedOutStream(io.getStdOut().writer()); | ||
| 1206 | try libc.render(bos.writer()); | ||
| 1207 | try bos.flush(); | ||
| 1208 | } | ||
| 1209 | } | ||
| 1210 | |||
| 1127 | pub const usage_fmt = | 1211 | pub const usage_fmt = |
| 1128 | \\usage: zig fmt [file]... | 1212 | \\Usage: zig fmt [file]... |
| 1129 | \\ | 1213 | \\ |
| 1130 | \\ Formats the input files and modifies them in-place. | 1214 | \\ Formats the input files and modifies them in-place. |
| 1131 | \\ Arguments can be files or directories, which are searched | 1215 | \\ Arguments can be files or directories, which are searched |
src-self-hosted/target.zig+25| ... | @@ -109,3 +109,28 @@ pub fn canBuildLibC(target: std.Target) bool { | ... | @@ -109,3 +109,28 @@ pub fn canBuildLibC(target: std.Target) bool { |
| 109 | } | 109 | } |
| 110 | return false; | 110 | return false; |
| 111 | } | 111 | } |
| 112 | |||
| 113 | pub fn cannotDynamicLink(target: std.Target) bool { | ||
| 114 | return switch (target.os.tag) { | ||
| 115 | .freestanding, .other => true, | ||
| 116 | else => false, | ||
| 117 | }; | ||
| 118 | } | ||
| 119 | |||
| 120 | pub fn osRequiresLibC(target: std.Target) bool { | ||
| 121 | // On Darwin, we always link libSystem which contains libc. | ||
| 122 | // Similarly on FreeBSD and NetBSD we always link system libc | ||
| 123 | // since this is the stable syscall interface. | ||
| 124 | return switch (target.os.tag) { | ||
| 125 | .freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true, | ||
| 126 | else => false, | ||
| 127 | }; | ||
| 128 | } | ||
| 129 | |||
| 130 | pub fn requiresPIE(target: std.Target) bool { | ||
| 131 | return target.isAndroid(); | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn libc_needs_crti_crtn(target: std.Target) bool { | ||
| 135 | return !(target.cpu.arch.isRISCV() or target.isAndroid()); | ||
| 136 | } |
src-self-hosted/test.zig+1| ... | @@ -472,6 +472,7 @@ pub const TestContext = struct { | ... | @@ -472,6 +472,7 @@ pub const TestContext = struct { |
| 472 | .root_pkg = root_pkg, | 472 | .root_pkg = root_pkg, |
| 473 | .keep_source_files_loaded = true, | 473 | .keep_source_files_loaded = true, |
| 474 | .object_format = ofmt, | 474 | .object_format = ofmt, |
| 475 | .is_native_os = case.target.isNativeOs(), | ||
| 475 | }); | 476 | }); |
| 476 | defer module.destroy(); | 477 | defer module.destroy(); |
| 477 | 478 |