authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-23 20:48:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-23 20:48:47-07:00
logb08fd0e8fca5ff9ac5531437f5749e74dc009a14
treee2fcc2a3a28e1ce90631542745d779c92b9356c0
parent64deb46859a11588fb97e8464ec9dae53124b96b

stage2: building musl libc from source


6 files changed, 426 insertions(+), 76 deletions(-)

BRANCH_TODO+4-2
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1 * musl1 * repair @cImport
2 * tests passing with -Dskip-non-native2 * tests passing with -Dskip-non-native
3 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]3 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
4 * repair @cImport
5 * make sure zig cc works4 * make sure zig cc works
6 - using it as a preprocessor (-E)5 - using it as a preprocessor (-E)
7 - try building some software6 - try building some software
...@@ -20,6 +19,7 @@...@@ -20,6 +19,7 @@
20 * WASM LLD linking19 * WASM LLD linking
21 * skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)20 * skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)
22 (maybe make it an explicit option and have main.zig disable it)21 (maybe make it an explicit option and have main.zig disable it)
22 - make sure that `zig cc -o hello hello.c -target native-native-musl` and `zig build-exe hello.zig -lc -target native-native-musl` will share the same libc build.
23 * audit the CLI options for stage223 * audit the CLI options for stage2
24 * audit the base cache hash24 * audit the base cache hash
25 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.25 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
...@@ -58,3 +58,5 @@...@@ -58,3 +58,5 @@
58 * rename std.builtin.Mode to std.builtin.OptimizeMode58 * rename std.builtin.Mode to std.builtin.OptimizeMode
59 * implement `zig run` and `zig test` when combined with `--watch`59 * implement `zig run` and `zig test` when combined with `--watch`
60 * close the --pkg-begin --pkg-end Package directory handles60 * close the --pkg-begin --pkg-end Package directory handles
61 * make std.Progress support multithreaded
62 * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime
lib/std/zig/system.zig+6
...@@ -393,6 +393,12 @@ pub const NativeTargetInfo = struct {...@@ -393,6 +393,12 @@ pub const NativeTargetInfo = struct {
393 if (!native_target_has_ld or have_all_info or os_is_non_native) {393 if (!native_target_has_ld or have_all_info or os_is_non_native) {
394 return defaultAbiAndDynamicLinker(cpu, os, cross_target);394 return defaultAbiAndDynamicLinker(cpu, os, cross_target);
395 }395 }
396 if (cross_target.abi) |abi| {
397 if (abi.isMusl()) {
398 // musl implies static linking.
399 return defaultAbiAndDynamicLinker(cpu, os, cross_target);
400 }
401 }
396 // The current target's ABI cannot be relied on for this. For example, we may build the zig402 // The current target's ABI cannot be relied on for this. For example, we may build the zig
397 // compiler for target riscv64-linux-musl and provide a tarball for users to download.403 // compiler for target riscv64-linux-musl and provide a tarball for users to download.
398 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined404 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
src/Compilation.zig+106-4
...@@ -15,6 +15,7 @@ const liveness = @import("liveness.zig");...@@ -15,6 +15,7 @@ const liveness = @import("liveness.zig");
15const build_options = @import("build_options");15const build_options = @import("build_options");
16const LibCInstallation = @import("libc_installation.zig").LibCInstallation;16const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
17const glibc = @import("glibc.zig");17const glibc = @import("glibc.zig");
18const musl = @import("musl.zig");
18const libunwind = @import("libunwind.zig");19const libunwind = @import("libunwind.zig");
19const libcxx = @import("libcxx.zig");20const libcxx = @import("libcxx.zig");
20const fatal = @import("main.zig").fatal;21const fatal = @import("main.zig").fatal;
...@@ -140,6 +141,8 @@ const Job = union(enum) {...@@ -140,6 +141,8 @@ const Job = union(enum) {
140 glibc_crt_file: glibc.CRTFile,141 glibc_crt_file: glibc.CRTFile,
141 /// all of the glibc shared objects142 /// all of the glibc shared objects
142 glibc_shared_objects,143 glibc_shared_objects,
144 /// one of the glibc static objects
145 musl_crt_file: musl.CRTFile,
143 /// libunwind.a, usually needed when linking libc146 /// libunwind.a, usually needed when linking libc
144 libunwind: void,147 libunwind: void,
145 libcxx: void,148 libcxx: void,
...@@ -778,6 +781,18 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -778,6 +781,18 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
778 if (comp.wantBuildGLibCFromSource()) {781 if (comp.wantBuildGLibCFromSource()) {
779 try comp.addBuildingGLibCJobs();782 try comp.addBuildingGLibCJobs();
780 }783 }
784 if (comp.wantBuildMuslFromSource()) {
785 try comp.work_queue.write(&[_]Job{
786 .{ .musl_crt_file = .crti_o },
787 .{ .musl_crt_file = .crtn_o },
788 .{ .musl_crt_file = .crt1_o },
789 .{ .musl_crt_file = .scrt1_o },
790 .{ .musl_crt_file = .libc_a },
791 });
792 }
793 if (comp.wantBuildMinGWW64FromSource()) {
794 @panic("TODO");
795 }
781 if (comp.wantBuildLibUnwindFromSource()) {796 if (comp.wantBuildLibUnwindFromSource()) {
782 try comp.work_queue.writeItem(.{ .libunwind = {} });797 try comp.work_queue.writeItem(.{ .libunwind = {} });
783 }798 }
...@@ -822,6 +837,7 @@ pub fn destroy(self: *Compilation) void {...@@ -822,6 +837,7 @@ pub fn destroy(self: *Compilation) void {
822 {837 {
823 var it = self.crt_files.iterator();838 var it = self.crt_files.iterator();
824 while (it.next()) |entry| {839 while (it.next()) |entry| {
840 gpa.free(entry.key);
825 entry.value.deinit(gpa);841 entry.value.deinit(gpa);
826 }842 }
827 self.crt_files.deinit(gpa);843 self.crt_files.deinit(gpa);
...@@ -1128,6 +1144,12 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {...@@ -1128,6 +1144,12 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
1128 fatal("unable to build glibc shared objects: {}", .{@errorName(err)});1144 fatal("unable to build glibc shared objects: {}", .{@errorName(err)});
1129 };1145 };
1130 },1146 },
1147 .musl_crt_file => |crt_file| {
1148 musl.buildCRTFile(self, crt_file) catch |err| {
1149 // TODO Expose this as a normal compile error rather than crashing here.
1150 fatal("unable to build musl CRT file: {}", .{@errorName(err)});
1151 };
1152 },
1131 .libunwind => {1153 .libunwind => {
1132 libunwind.buildStaticLib(self) catch |err| {1154 libunwind.buildStaticLib(self) catch |err| {
1133 // TODO Expose this as a normal compile error rather than crashing here.1155 // TODO Expose this as a normal compile error rather than crashing here.
...@@ -1846,7 +1868,10 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const...@@ -1846,7 +1868,10 @@ fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const
1846}1868}
18471869
1848pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 {1870pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 {
1849 if (comp.wantBuildGLibCFromSource()) {1871 if (comp.wantBuildGLibCFromSource() or
1872 comp.wantBuildMuslFromSource() or
1873 comp.wantBuildMinGWW64FromSource())
1874 {
1850 return comp.crt_files.get(basename).?.full_object_path;1875 return comp.crt_files.get(basename).?.full_object_path;
1851 }1876 }
1852 const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;1877 const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;
...@@ -1865,15 +1890,26 @@ fn addBuildingGLibCJobs(comp: *Compilation) !void {...@@ -1865,15 +1890,26 @@ fn addBuildingGLibCJobs(comp: *Compilation) !void {
1865 });1890 });
1866}1891}
18671892
1868fn wantBuildGLibCFromSource(comp: *Compilation) bool {1893fn wantBuildLibCFromSource(comp: Compilation) bool {
1869 const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) {1894 const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) {
1870 .Obj => false,1895 .Obj => false,
1871 .Lib => comp.bin_file.options.link_mode == .Dynamic,1896 .Lib => comp.bin_file.options.link_mode == .Dynamic,
1872 .Exe => true,1897 .Exe => true,
1873 };1898 };
1874 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and1899 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
1875 comp.bin_file.options.libc_installation == null and1900 comp.bin_file.options.libc_installation == null;
1876 comp.bin_file.options.target.isGnuLibC();1901}
1902
1903fn wantBuildGLibCFromSource(comp: Compilation) bool {
1904 return comp.wantBuildLibCFromSource() and comp.getTarget().isGnuLibC();
1905}
1906
1907fn wantBuildMuslFromSource(comp: Compilation) bool {
1908 return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl();
1909}
1910
1911fn wantBuildMinGWW64FromSource(comp: Compilation) bool {
1912 return comp.wantBuildLibCFromSource() and comp.getTarget().isMinGW();
1877}1913}
18781914
1879fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {1915fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
...@@ -2362,3 +2398,69 @@ fn createStage1Pkg(...@@ -2362,3 +2398,69 @@ fn createStage1Pkg(
2362 };2398 };
2363 return child_pkg;2399 return child_pkg;
2364}2400}
2401
2402pub fn build_crt_file(
2403 comp: *Compilation,
2404 root_name: []const u8,
2405 output_mode: std.builtin.OutputMode,
2406 c_source_files: []const Compilation.CSourceFile,
2407) !void {
2408 const tracy = trace(@src());
2409 defer tracy.end();
2410
2411 const target = comp.getTarget();
2412 const basename = try std.zig.binNameAlloc(comp.gpa, root_name, target, output_mode, null, null);
2413 errdefer comp.gpa.free(basename);
2414
2415 // TODO: This is extracted into a local variable to work around a stage1 miscompilation.
2416 const emit_bin = Compilation.EmitLoc{
2417 .directory = null, // Put it in the cache directory.
2418 .basename = basename,
2419 };
2420 const sub_compilation = try Compilation.create(comp.gpa, .{
2421 .local_cache_directory = comp.global_cache_directory,
2422 .global_cache_directory = comp.global_cache_directory,
2423 .zig_lib_directory = comp.zig_lib_directory,
2424 .target = target,
2425 .root_name = root_name,
2426 .root_pkg = null,
2427 .output_mode = output_mode,
2428 .rand = comp.rand,
2429 .libc_installation = comp.bin_file.options.libc_installation,
2430 .emit_bin = emit_bin,
2431 .optimize_mode = comp.bin_file.options.optimize_mode,
2432 .want_sanitize_c = false,
2433 .want_stack_check = false,
2434 .want_valgrind = false,
2435 .want_pic = comp.bin_file.options.pic,
2436 .emit_h = null,
2437 .strip = comp.bin_file.options.strip,
2438 .is_native_os = comp.bin_file.options.is_native_os,
2439 .self_exe_path = comp.self_exe_path,
2440 .c_source_files = c_source_files,
2441 .verbose_cc = comp.verbose_cc,
2442 .verbose_link = comp.bin_file.options.verbose_link,
2443 .verbose_tokenize = comp.verbose_tokenize,
2444 .verbose_ast = comp.verbose_ast,
2445 .verbose_ir = comp.verbose_ir,
2446 .verbose_llvm_ir = comp.verbose_llvm_ir,
2447 .verbose_cimport = comp.verbose_cimport,
2448 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
2449 .clang_passthrough_mode = comp.clang_passthrough_mode,
2450 .is_compiler_rt_or_libc = true,
2451 });
2452 defer sub_compilation.destroy();
2453
2454 try sub_compilation.updateSubCompilation();
2455
2456 try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
2457 const artifact_path = if (sub_compilation.bin_file.options.directory.path) |p|
2458 try std.fs.path.join(comp.gpa, &[_][]const u8{ p, basename })
2459 else
2460 try comp.gpa.dupe(u8, basename);
2461
2462 comp.crt_files.putAssumeCapacityNoClobber(basename, .{
2463 .full_object_path = artifact_path,
2464 .lock = sub_compilation.bin_file.toOwnedLock(),
2465 });
2466}
src/glibc.zig+4-66
...@@ -274,7 +274,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -274,7 +274,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
274 "-g",274 "-g",
275 "-Wa,--noexecstack",275 "-Wa,--noexecstack",
276 });276 });
277 return build_crt_file(comp, "crti.o", .Obj, &[1]Compilation.CSourceFile{277 return comp.build_crt_file("crti", .Obj, &[1]Compilation.CSourceFile{
278 .{278 .{
279 .src_path = try start_asm_path(comp, arena, "crti.S"),279 .src_path = try start_asm_path(comp, arena, "crti.S"),
280 .extra_flags = args.items,280 .extra_flags = args.items,
...@@ -292,7 +292,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -292,7 +292,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
292 "-g",292 "-g",
293 "-Wa,--noexecstack",293 "-Wa,--noexecstack",
294 });294 });
295 return build_crt_file(comp, "crtn.o", .Obj, &[1]Compilation.CSourceFile{295 return comp.build_crt_file("crtn", .Obj, &[1]Compilation.CSourceFile{
296 .{296 .{
297 .src_path = try start_asm_path(comp, arena, "crtn.S"),297 .src_path = try start_asm_path(comp, arena, "crtn.S"),
298 .extra_flags = args.items,298 .extra_flags = args.items,
...@@ -343,7 +343,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -343,7 +343,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
343 .extra_flags = args.items,343 .extra_flags = args.items,
344 };344 };
345 };345 };
346 return build_crt_file(comp, "Scrt1.o", .Obj, &[_]Compilation.CSourceFile{ start_os, abi_note_o });346 return comp.build_crt_file("Scrt1", .Obj, &[_]Compilation.CSourceFile{ start_os, abi_note_o });
347 },347 },
348 .libc_nonshared_a => {348 .libc_nonshared_a => {
349 const deps = [_][]const u8{349 const deps = [_][]const u8{
...@@ -433,7 +433,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -433,7 +433,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
433 .extra_flags = args.items,433 .extra_flags = args.items,
434 };434 };
435 }435 }
436 return build_crt_file(comp, "libc_nonshared.a", .Lib, &c_source_files);436 return comp.build_crt_file("c_nonshared", .Lib, &c_source_files);
437 },437 },
438 }438 }
439}439}
...@@ -676,68 +676,6 @@ fn lib_path(comp: *Compilation, arena: *Allocator, sub_path: []const u8) ![]cons...@@ -676,68 +676,6 @@ fn lib_path(comp: *Compilation, arena: *Allocator, sub_path: []const u8) ![]cons
676 return path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, sub_path });676 return path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, sub_path });
677}677}
678678
679fn build_crt_file(
680 comp: *Compilation,
681 basename: []const u8,
682 output_mode: std.builtin.OutputMode,
683 c_source_files: []const Compilation.CSourceFile,
684) !void {
685 const tracy = trace(@src());
686 defer tracy.end();
687
688 // TODO: This is extracted into a local variable to work around a stage1 miscompilation.
689 const emit_bin = Compilation.EmitLoc{
690 .directory = null, // Put it in the cache directory.
691 .basename = basename,
692 };
693 const sub_compilation = try Compilation.create(comp.gpa, .{
694 .local_cache_directory = comp.global_cache_directory,
695 .global_cache_directory = comp.global_cache_directory,
696 .zig_lib_directory = comp.zig_lib_directory,
697 .target = comp.getTarget(),
698 .root_name = mem.split(basename, ".").next().?,
699 .root_pkg = null,
700 .output_mode = output_mode,
701 .rand = comp.rand,
702 .libc_installation = comp.bin_file.options.libc_installation,
703 .emit_bin = emit_bin,
704 .optimize_mode = comp.bin_file.options.optimize_mode,
705 .want_sanitize_c = false,
706 .want_stack_check = false,
707 .want_valgrind = false,
708 .want_pic = comp.bin_file.options.pic,
709 .emit_h = null,
710 .strip = comp.bin_file.options.strip,
711 .is_native_os = comp.bin_file.options.is_native_os,
712 .self_exe_path = comp.self_exe_path,
713 .c_source_files = c_source_files,
714 .verbose_cc = comp.verbose_cc,
715 .verbose_link = comp.bin_file.options.verbose_link,
716 .verbose_tokenize = comp.verbose_tokenize,
717 .verbose_ast = comp.verbose_ast,
718 .verbose_ir = comp.verbose_ir,
719 .verbose_llvm_ir = comp.verbose_llvm_ir,
720 .verbose_cimport = comp.verbose_cimport,
721 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
722 .clang_passthrough_mode = comp.clang_passthrough_mode,
723 .is_compiler_rt_or_libc = true,
724 });
725 defer sub_compilation.destroy();
726
727 try sub_compilation.updateSubCompilation();
728
729 try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
730 const artifact_path = if (sub_compilation.bin_file.options.directory.path) |p|
731 try path.join(comp.gpa, &[_][]const u8{ p, basename })
732 else
733 try comp.gpa.dupe(u8, basename);
734
735 comp.crt_files.putAssumeCapacityNoClobber(basename, .{
736 .full_object_path = artifact_path,
737 .lock = sub_compilation.bin_file.toOwnedLock(),
738 });
739}
740
741pub const BuiltSharedObjects = struct {679pub const BuiltSharedObjects = struct {
742 lock: Cache.Lock,680 lock: Cache.Lock,
743 dir_path: []u8,681 dir_path: []u8,
src/link/Elf.zig+1-1
...@@ -1548,7 +1548,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1548,7 +1548,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1548 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));1548 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
1549 } else if (target.isMusl()) {1549 } else if (target.isMusl()) {
1550 try argv.append(comp.libunwind_static_lib.?.full_object_path);1550 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1551 try argv.append(comp.libc_static_lib.?.full_object_path);1551 try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
1552 } else if (self.base.options.link_libcpp) {1552 } else if (self.base.options.link_libcpp) {
1553 try argv.append(comp.libunwind_static_lib.?.full_object_path);1553 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1554 } else {1554 } else {
src/musl.zig+305-3
...@@ -1,6 +1,308 @@...@@ -1,6 +1,308 @@
1//! TODO build musl libc from source1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const mem = std.mem;
4const path = std.fs.path;
5const assert = std.debug.assert;
26
3pub const src_files = [_][]const u8{7const target_util = @import("target.zig");
8const Compilation = @import("Compilation.zig");
9const build_options = @import("build_options");
10const trace = @import("tracy.zig").trace;
11const Cache = @import("Cache.zig");
12const Package = @import("Package.zig");
13
14pub const CRTFile = enum {
15 crti_o,
16 crtn_o,
17 crt1_o,
18 scrt1_o,
19 libc_a,
20};
21
22pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
23 if (!build_options.have_llvm) {
24 return error.ZigCompilerNotBuiltWithLLVMExtensions;
25 }
26 const gpa = comp.gpa;
27 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
28 defer arena_allocator.deinit();
29 const arena = &arena_allocator.allocator;
30
31 switch (crt_file) {
32 .crti_o => {
33 var args = std.ArrayList([]const u8).init(arena);
34 try add_cc_args(comp, arena, &args, false);
35 try args.appendSlice(&[_][]const u8{
36 "-Qunused-arguments",
37 });
38 return comp.build_crt_file("crti", .Obj, &[1]Compilation.CSourceFile{
39 .{
40 .src_path = try start_asm_path(comp, arena, "crti.s"),
41 .extra_flags = args.items,
42 },
43 });
44 },
45 .crtn_o => {
46 var args = std.ArrayList([]const u8).init(arena);
47 try add_cc_args(comp, arena, &args, false);
48 try args.appendSlice(&[_][]const u8{
49 "-Qunused-arguments",
50 });
51 return comp.build_crt_file("crtn", .Obj, &[1]Compilation.CSourceFile{
52 .{
53 .src_path = try start_asm_path(comp, arena, "crtn.s"),
54 .extra_flags = args.items,
55 },
56 });
57 },
58 .crt1_o => {
59 var args = std.ArrayList([]const u8).init(arena);
60 try add_cc_args(comp, arena, &args, false);
61 try args.appendSlice(&[_][]const u8{
62 "-fno-stack-protector",
63 "-DCRT",
64 });
65 return comp.build_crt_file("crt1", .Obj, &[1]Compilation.CSourceFile{
66 .{
67 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
68 "libc", "musl", "crt", "crt1.c",
69 }),
70 .extra_flags = args.items,
71 },
72 });
73 },
74 .scrt1_o => {
75 var args = std.ArrayList([]const u8).init(arena);
76 try add_cc_args(comp, arena, &args, false);
77 try args.appendSlice(&[_][]const u8{
78 "-fPIC",
79 "-fno-stack-protector",
80 "-DCRT",
81 });
82 return comp.build_crt_file("Scrt1", .Obj, &[1]Compilation.CSourceFile{
83 .{
84 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
85 "libc", "musl", "crt", "Scrt1.c",
86 }),
87 .extra_flags = args.items,
88 },
89 });
90 },
91 .libc_a => {
92 // When there is a src/<arch>/foo.* then it should substitute for src/foo.*
93 // Even a .s file can substitute for a .c file.
94 const target = comp.getTarget();
95 const arch_name = target_util.archMuslName(target.cpu.arch);
96 var source_table = std.StringArrayHashMap(Ext).init(comp.gpa);
97 defer source_table.deinit();
98
99 try source_table.ensureCapacity(compat_time32_files.len + src_files.len);
100
101 for (src_files) |src_file| {
102 try addSrcFile(arena, &source_table, src_file);
103 }
104
105 const time32_compat_arch_list = [_][]const u8{ "arm", "i386", "mips", "powerpc" };
106 for (time32_compat_arch_list) |time32_compat_arch| {
107 if (mem.eql(u8, arch_name, time32_compat_arch)) {
108 for (compat_time32_files) |compat_time32_file| {
109 try addSrcFile(arena, &source_table, compat_time32_file);
110 }
111 }
112 }
113
114 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(comp.gpa);
115 defer c_source_files.deinit();
116
117 var override_path = std.ArrayList(u8).init(comp.gpa);
118 defer override_path.deinit();
119
120 const s = path.sep_str;
121
122 for (source_table.items()) |entry| {
123 const src_file = entry.key;
124 const ext = entry.value;
125
126 const dirname = path.dirname(src_file).?;
127 const basename = path.basename(src_file);
128 const noextbasename = mem.split(basename, ".").next().?;
129 const before_arch_dir = path.dirname(dirname).?;
130 const dirbasename = path.basename(dirname);
131
132 var is_arch_specific = false;
133 // Architecture-specific implementations are under a <arch>/ folder.
134 if (is_musl_arch_name(dirbasename)) {
135 if (!mem.eql(u8, dirbasename, arch_name))
136 continue; // Not the architecture we're compiling for.
137 is_arch_specific = true;
138 }
139 if (!is_arch_specific) {
140 // Look for an arch specific override.
141 override_path.shrinkRetainingCapacity(0);
142 try override_path.writer().print("{}" ++ s ++ "{}" ++ s ++ "{}.s", .{
143 dirname, arch_name, noextbasename,
144 });
145 if (source_table.contains(override_path.items))
146 continue;
147
148 override_path.shrinkRetainingCapacity(0);
149 try override_path.writer().print("{}" ++ s ++ "{}" ++ s ++ "{}.S", .{
150 dirname, arch_name, noextbasename,
151 });
152 if (source_table.contains(override_path.items))
153 continue;
154
155 override_path.shrinkRetainingCapacity(0);
156 try override_path.writer().print("{}" ++ s ++ "{}" ++ s ++ "{}.c", .{
157 dirname, arch_name, noextbasename,
158 });
159 if (source_table.contains(override_path.items))
160 continue;
161 }
162
163 var args = std.ArrayList([]const u8).init(arena);
164 try add_cc_args(comp, arena, &args, ext == .o3);
165 try args.appendSlice(&[_][]const u8{
166 "-Qunused-arguments",
167 "-w", // disable all warnings
168 });
169 const c_source_file = try c_source_files.addOne();
170 c_source_file.* = .{
171 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", src_file }),
172 .extra_flags = args.items,
173 };
174 }
175 return comp.build_crt_file("c", .Lib, c_source_files.items);
176 },
177 }
178}
179
180fn is_musl_arch_name(name: []const u8) bool {
181 const musl_arch_names = [_][]const u8{
182 "aarch64",
183 "arm",
184 "generic",
185 "i386",
186 "m68k",
187 "microblaze",
188 "mips",
189 "mips64",
190 "mipsn32",
191 "or1k",
192 "powerpc",
193 "powerpc64",
194 "riscv64",
195 "s390x",
196 "sh",
197 "x32",
198 "x86_64",
199 };
200 for (musl_arch_names) |musl_arch_name| {
201 if (mem.eql(u8, musl_arch_name, name)) {
202 return true;
203 }
204 }
205 return false;
206}
207
208const Ext = enum {
209 assembly,
210 normal,
211 o3,
212};
213
214fn addSrcFile(arena: *Allocator, source_table: *std.StringArrayHashMap(Ext), file_path: []const u8) !void {
215 const ext: Ext = ext: {
216 if (mem.endsWith(u8, file_path, ".c")) {
217 if (mem.startsWith(u8, file_path, "musl/src/malloc/") or
218 mem.startsWith(u8, file_path, "musl/src/string/") or
219 mem.startsWith(u8, file_path, "musl/src/internal/"))
220 {
221 break :ext .o3;
222 } else {
223 break :ext .assembly;
224 }
225 } else if (mem.endsWith(u8, file_path, ".s") or mem.endsWith(u8, file_path, ".S")) {
226 break :ext .assembly;
227 } else {
228 unreachable;
229 }
230 };
231 // TODO do this at comptime on the comptime data rather than at runtime
232 // probably best to wait until self-hosted is done and our comptime execution
233 // is faster and uses less memory.
234 const key = if (path.sep != '/') blk: {
235 const mutable_file_path = try arena.dupe(u8, file_path);
236 for (mutable_file_path) |*c| {
237 if (c.* == '/') {
238 c.* == path.sep;
239 }
240 }
241 break :blk mutable_file_path;
242 } else file_path;
243 source_table.putAssumeCapacityNoClobber(key, ext);
244}
245
246fn add_cc_args(
247 comp: *Compilation,
248 arena: *Allocator,
249 args: *std.ArrayList([]const u8),
250 want_O3: bool,
251) error{OutOfMemory}!void {
252 const target = comp.getTarget();
253 const arch_name = target_util.archMuslName(target.cpu.arch);
254 const os_name = @tagName(target.os.tag);
255 const triple = try std.fmt.allocPrint(arena, "{}-{}-musl", .{ arch_name, os_name });
256 const o_arg = if (want_O3) "-O3" else "-Os";
257
258 try args.appendSlice(&[_][]const u8{
259 "-std=c99",
260 "-ffreestanding",
261 // Musl adds these args to builds with gcc but clang does not support them.
262 //"-fexcess-precision=standard",
263 //"-frounding-math",
264 "-Wa,--noexecstack",
265 "-D_XOPEN_SOURCE=700",
266
267 "-I",
268 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "arch", arch_name }),
269
270 "-I",
271 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "arch", "generic" }),
272
273 "-I",
274 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "src", "include" }),
275
276 "-I",
277 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "src", "internal" }),
278
279 "-I",
280 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "include" }),
281
282 "-I",
283 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", triple }),
284
285 "-I",
286 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", "generic-musl" }),
287
288 o_arg,
289
290 "-fomit-frame-pointer",
291 "-fno-unwind-tables",
292 "-fno-asynchronous-unwind-tables",
293 "-ffunction-sections",
294 "-fdata-sections",
295 });
296}
297
298fn start_asm_path(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 {
299 const target = comp.getTarget();
300 return comp.zig_lib_directory.join(arena, &[_][]const u8{
301 "libc", "musl", "crt", target_util.archMuslName(target.cpu.arch), basename,
302 });
303}
304
305const src_files = [_][]const u8{
4 "musl/src/aio/aio.c",306 "musl/src/aio/aio.c",
5 "musl/src/aio/aio_suspend.c",307 "musl/src/aio/aio_suspend.c",
6 "musl/src/aio/lio_listio.c",308 "musl/src/aio/lio_listio.c",
...@@ -1776,7 +2078,7 @@ pub const src_files = [_][]const u8{...@@ -1776,7 +2078,7 @@ pub const src_files = [_][]const u8{
1776 "musl/src/unistd/writev.c",2078 "musl/src/unistd/writev.c",
1777 "musl/src/unistd/x32/lseek.c",2079 "musl/src/unistd/x32/lseek.c",
1778};2080};
1779pub const compat_time32_files = [_][]const u8{2081const compat_time32_files = [_][]const u8{
1780 "musl/compat/time32/__xstat.c",2082 "musl/compat/time32/__xstat.c",
1781 "musl/compat/time32/adjtime32.c",2083 "musl/compat/time32/adjtime32.c",
1782 "musl/compat/time32/adjtimex_time32.c",2084 "musl/compat/time32/adjtimex_time32.c",