builder: handle concurrent library header rename

When a library is built concurrently by multiple TinyGo processes, they may sometimes both build the headers.
In that case a directory rename may fail due to conflict.
This change detects and handles the conflict similar to how GOROOT construction does.
Этот коммит содержится в:
Nia Waldvogel 2021-12-15 09:39:55 -05:00 коммит произвёл Ayke
родитель e6fbad13c6
коммит d5c0083085

Просмотреть файл

@ -4,6 +4,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
@ -92,7 +93,23 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
} }
err = os.Rename(temporaryHeaderPath, headerPath) err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil { if err != nil {
return nil, err switch {
case os.IsExist(err):
// Another invocation of TinyGo also seems to have already created the headers.
case runtime.GOOS == "windows" && os.IsPermission(err):
// On Windows, a rename with a destination directory that already
// exists does not result in an IsExist error, but rather in an
// access denied error. To be sure, check for this case by checking
// whether the target directory exists.
if _, err := os.Stat(headerPath); err == nil {
break
}
fallthrough
default:
return nil, err
}
} }
} }
} }