From d5c0083085f7104b3f0d41290bb2ab4ccc2e5cac Mon Sep 17 00:00:00 2001 From: Nia Waldvogel Date: Wed, 15 Dec 2021 09:39:55 -0500 Subject: [PATCH] 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. --- builder/library.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/builder/library.go b/builder/library.go index 73079785..efcc8b75 100644 --- a/builder/library.go +++ b/builder/library.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "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) 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 + } } } }