musl.go raw
1 package builder
2
3 import (
4 "bytes"
5 "fmt"
6 "os"
7 "path/filepath"
8 "regexp"
9 "strings"
10
11 "moxie/compileopts"
12 "moxie/goenv"
13 )
14
15 // Create the alltypes.h file from the appropriate alltypes.h.in files.
16 func buildMuslAllTypes(arch, muslDir, outputBitsDir string) error {
17 // Create the file alltypes.h.
18 f, err := os.Create(filepath.Join(outputBitsDir, "alltypes.h"))
19 if err != nil {
20 return err
21 }
22 infiles := []string{
23 filepath.Join(muslDir, "arch", arch, "bits", "alltypes.h.in"),
24 filepath.Join(muslDir, "include", "alltypes.h.in"),
25 }
26 for _, infile := range infiles {
27 data, err := os.ReadFile(infile)
28 if err != nil {
29 return err
30 }
31 lines := strings.Split(string(data), "\n")
32 for _, line := range lines {
33 if strings.HasPrefix(line, "TYPEDEF ") {
34 matches := regexp.MustCompile(`TYPEDEF (.*) ([^ ]*);`).FindStringSubmatch(line)
35 value := matches[1]
36 name := matches[2]
37 line = fmt.Sprintf("#if defined(__NEED_%s) && !defined(__DEFINED_%s)\ntypedef %s %s;\n#define __DEFINED_%s\n#endif\n", name, name, value, name, name)
38 }
39 if strings.HasPrefix(line, "STRUCT ") {
40 matches := regexp.MustCompile(`STRUCT * ([^ ]*) (.*);`).FindStringSubmatch(line)
41 name := matches[1]
42 value := matches[2]
43 line = fmt.Sprintf("#if defined(__NEED_struct_%s) && !defined(__DEFINED_struct_%s)\nstruct %s %s;\n#define __DEFINED_struct_%s\n#endif\n", name, name, name, value, name)
44 }
45 _, err := f.WriteString(line + "\n")
46 if err != nil {
47 return err
48 }
49 }
50 }
51 return f.Close()
52 }
53
54 var libMusl = Library{
55 name: "musl",
56 makeHeaders: func(target, includeDir string) error {
57 bits := filepath.Join(includeDir, "bits")
58 err := os.Mkdir(bits, 0777)
59 if err != nil {
60 return err
61 }
62
63 arch := compileopts.MuslArchitecture(target)
64 muslDir := filepath.Join(goenv.Get("MOXIEROOT"), "lib", "musl")
65
66 err = buildMuslAllTypes(arch, muslDir, bits)
67 if err != nil {
68 return err
69 }
70
71 // Create the file syscall.h.
72 f, err := os.Create(filepath.Join(bits, "syscall.h"))
73 if err != nil {
74 return err
75 }
76 data, err := os.ReadFile(filepath.Join(muslDir, "arch", arch, "bits", "syscall.h.in"))
77 if err != nil {
78 return err
79 }
80 _, err = f.Write(bytes.ReplaceAll(data, []byte("__NR_"), []byte("SYS_")))
81 if err != nil {
82 return err
83 }
84 f.Close()
85
86 return nil
87 },
88 cflags: func(target, headerPath string) []string {
89 arch := compileopts.MuslArchitecture(target)
90 muslDir := filepath.Join(goenv.Get("MOXIEROOT"), "lib/musl")
91 cflags := []string{
92 "-std=c99", // same as in musl
93 "-D_XOPEN_SOURCE=700", // same as in musl
94 // Musl triggers some warnings and we don't want to show any
95 // warnings while compiling (only errors or silence), so disable
96 // specific warnings that are triggered in musl.
97 "-Werror",
98 "-Wno-logical-op-parentheses",
99 "-Wno-bitwise-op-parentheses",
100 "-Wno-shift-op-parentheses",
101 "-Wno-ignored-attributes",
102 "-Wno-string-plus-int",
103 "-Wno-ignored-pragmas",
104 "-Wno-tautological-constant-out-of-range-compare",
105 "-Wno-deprecated-non-prototype",
106 "-Wno-format",
107 "-Wno-parentheses",
108 "-Qunused-arguments",
109 // Select include dirs. Don't include standard library includes
110 // (that would introduce host dependencies and other complications),
111 // but do include all the include directories expected by musl.
112 "-nostdlibinc",
113 "-I" + muslDir + "/arch/" + arch,
114 "-I" + muslDir + "/arch/generic",
115 "-I" + muslDir + "/src/include",
116 "-I" + muslDir + "/src/internal",
117 "-I" + headerPath,
118 "-I" + muslDir + "/include",
119 "-fno-stack-protector",
120 }
121 return cflags
122 },
123 sourceDir: func() string { return filepath.Join(goenv.Get("MOXIEROOT"), "lib/musl/src") },
124 librarySources: func(target string, _ bool) ([]string, error) {
125 arch := compileopts.MuslArchitecture(target)
126 globs := []string{
127 "conf/*.c",
128 "ctype/*.c",
129 "env/*.c",
130 "errno/*.c",
131 "exit/*.c",
132 "fcntl/*.c",
133 "internal/defsysinfo.c",
134 "internal/intscan.c",
135 "internal/libc.c",
136 "internal/shgetc.c",
137 "internal/syscall_ret.c",
138 "internal/vdso.c",
139 "legacy/*.c",
140 "locale/*.c",
141 "linux/*.c",
142 "locale/*.c",
143 "malloc/*.c",
144 "malloc/mallocng/*.c",
145 "mman/*.c",
146 "math/*.c",
147 "misc/*.c",
148 "multibyte/*.c",
149 "sched/*.c",
150 "signal/" + arch + "/*.s",
151 "signal/*.c",
152 "stdio/*.c",
153 "stdlib/*.c",
154 "string/*.c",
155 "thread/" + arch + "/*.s",
156 "thread/*.c",
157 "time/*.c",
158 "unistd/*.c",
159 "process/*.c",
160 }
161
162 if arch == "arm" {
163 // These files need to be added to the start for some reason.
164 globs = append([]string{"thread/arm/*.c"}, globs...)
165 }
166
167 if arch != "aarch64" && arch != "mips" {
168 //aarch64 and mips have no architecture specific code, either they
169 // are not supported or don't need any?
170 globs = append([]string{"process/" + arch + "/*.s"}, globs...)
171 }
172
173 var sources []string
174 seenSources := map[string]struct{}{}
175 basepath := goenv.Get("MOXIEROOT") + "/lib/musl/src/"
176 for _, pattern := range globs {
177 matches, err := filepath.Glob(basepath + pattern)
178 if err != nil {
179 // From the documentation:
180 // > Glob ignores file system errors such as I/O errors reading
181 // > directories. The only possible returned error is
182 // > ErrBadPattern, when pattern is malformed.
183 // So the only possible error is when the (statically defined)
184 // pattern is wrong. In other words, a programming bug.
185 return nil, fmt.Errorf("musl: could not glob source dirs: %w", err)
186 }
187 if len(matches) == 0 {
188 return nil, fmt.Errorf("musl: did not find any files for pattern %#v", pattern)
189 }
190 for _, match := range matches {
191 relpath, err := filepath.Rel(basepath, match)
192 if err != nil {
193 // Not sure if this is even possible.
194 return nil, err
195 }
196 // Make sure architecture specific files override generic files.
197 id := strings.ReplaceAll(relpath, "/"+arch+"/", "/")
198 if _, ok := seenSources[id]; ok {
199 // Already seen this file, skipping this (generic) file.
200 continue
201 }
202 seenSources[id] = struct{}{}
203 sources = append(sources, relpath)
204 }
205 }
206 return sources, nil
207 },
208 crt1Source: "../crt/crt1.c", // lib/musl/crt/crt1.c
209 }
210