@@ -157,16 +157,29 @@ var aeabiBuiltins = []string{
157157
158158func builtinFiles (target string ) []string {
159159 builtins := append ([]string {}, genericBuiltins ... ) // copy genericBuiltins
160- if target [: 3 ] == "arm" {
160+ if strings . HasPrefix ( target , "arm" ) {
161161 builtins = append (builtins , aeabiBuiltins ... )
162162 }
163163 return builtins
164164}
165165
166+ // builtinsDir returns the directory where the sources for compiler-rt are kept.
167+ func builtinsDir () string {
168+ return filepath .Join (sourceDir (), "lib" , "compiler-rt" , "lib" , "builtins" )
169+ }
170+
166171// Get the builtins archive, possibly generating it as needed.
167172func loadBuiltins (target string ) (path string , err error ) {
173+ // Try to load a precompiled compiler-rt library.
174+ precompiledPath := filepath .Join (sourceDir (), "pkg" , target , "compiler-rt.a" )
175+ if _ , err := os .Stat (precompiledPath ); err == nil {
176+ // Found a precompiled compiler-rt for this OS/architecture. Return the
177+ // path directly.
178+ return precompiledPath , nil
179+ }
180+
168181 outfile := "librt-" + target + ".a"
169- builtinsDir := filepath . Join ( sourceDir (), "lib" , "compiler-rt" , "lib" , "builtins" )
182+ builtinsDir := builtinsDir ( )
170183
171184 builtins := builtinFiles (target )
172185 srcs := make ([]string , len (builtins ))
@@ -178,9 +191,33 @@ func loadBuiltins(target string) (path string, err error) {
178191 return path , err
179192 }
180193
181- dir , err := ioutil .TempDir ("" , "tinygo-builtins" )
194+ var cachepath string
195+ err = compileBuiltins (target , func (path string ) error {
196+ path , err := cacheStore (path , outfile , commands ["clang" ], srcs )
197+ cachepath = path
198+ return err
199+ })
200+ return cachepath , err
201+ }
202+
203+ // compileBuiltins compiles builtins from compiler-rt into a static library.
204+ // When it succeeds, it will call the callback with the resulting path. The path
205+ // will be removed after callback returns. If callback returns an error, this is
206+ // passed through to the return value of this function.
207+ func compileBuiltins (target string , callback func (path string ) error ) error {
208+ builtinsDir := builtinsDir ()
209+
210+ builtins := builtinFiles (target )
211+ srcs := make ([]string , len (builtins ))
212+ for i , name := range builtins {
213+ srcs [i ] = filepath .Join (builtinsDir , name )
214+ }
215+
216+ dirPrefix := "tinygo-builtins"
217+ remapDir := filepath .Join (os .TempDir (), dirPrefix )
218+ dir , err := ioutil .TempDir (os .TempDir (), dirPrefix )
182219 if err != nil {
183- return "" , err
220+ return err
184221 }
185222 defer os .RemoveAll (dir )
186223
@@ -195,13 +232,16 @@ func loadBuiltins(target string) (path string, err error) {
195232 objpath := filepath .Join (dir , objname + ".o" )
196233 objs = append (objs , objpath )
197234 srcpath := filepath .Join (builtinsDir , name )
198- cmd := exec .Command (commands ["clang" ], "-c" , "-Oz" , "-g" , "-Werror" , "-Wall" , "-std=c11" , "-fshort-enums" , "-nostdlibinc" , "-ffunction-sections" , "-fdata-sections" , "--target=" + target , "-o" , objpath , srcpath )
235+ // Note: -fdebug-prefix-map is necessary to make the output archive
236+ // reproducible. Otherwise the temporary directory is stored in the
237+ // archive itself, which varies each run.
238+ cmd := exec .Command (commands ["clang" ], "-c" , "-Oz" , "-g" , "-Werror" , "-Wall" , "-std=c11" , "-fshort-enums" , "-nostdlibinc" , "-ffunction-sections" , "-fdata-sections" , "--target=" + target , "-fdebug-prefix-map=" + dir + "=" + remapDir , "-o" , objpath , srcpath )
199239 cmd .Stdout = os .Stdout
200240 cmd .Stderr = os .Stderr
201241 cmd .Dir = dir
202242 err = cmd .Run ()
203243 if err != nil {
204- return "" , & commandError {"failed to build" , srcpath , err }
244+ return & commandError {"failed to build" , srcpath , err }
205245 }
206246 }
207247
@@ -213,8 +253,10 @@ func loadBuiltins(target string) (path string, err error) {
213253 cmd .Dir = dir
214254 err = cmd .Run ()
215255 if err != nil {
216- return "" , & commandError {"failed to make static library" , arpath , err }
256+ return & commandError {"failed to make static library" , arpath , err }
217257 }
218258
219- return cacheStore (arpath , outfile , commands ["clang" ], srcs )
259+ // Give the caller the resulting file. The callback must copy the file,
260+ // because after it returns the temporary directory will be removed.
261+ return callback (arpath )
220262}
0 commit comments