-
Notifications
You must be signed in to change notification settings - Fork 925
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Instead of storing an increasing version number in relevant packages (compiler.Version, interp.Version, cgo.Version, ...), read the build ID from the currently running executable. This has several benefits: * All changes relevant to the compiled packages are caught. * No need to bump the version for each change to these packages. This avoids merge conflicts. * During development, `go install` is enough. No need to run `tinygo clean` all the time. Of course, the drawback is that it might be updated a bit more often than necessary but I think the overall benefit is big. Regular release users shouldn't see any difference. Because the tinygo binary stays the same, the cache works well.
- Loading branch information
Showing
5 changed files
with
103 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package builder | ||
|
||
import ( | ||
"bytes" | ||
"debug/elf" | ||
"debug/macho" | ||
"encoding/binary" | ||
"fmt" | ||
"io" | ||
"os" | ||
"runtime" | ||
) | ||
|
||
// ReadBuildID reads the build ID from the currently running executable. | ||
func ReadBuildID() ([]byte, error) { | ||
executable, err := os.Executable() | ||
if err != nil { | ||
return nil, err | ||
} | ||
f, err := os.Open(executable) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
|
||
switch runtime.GOOS { | ||
case "linux", "freebsd": | ||
// Read the GNU build id section. (Not sure about FreeBSD though...) | ||
file, err := elf.NewFile(f) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, section := range file.Sections { | ||
if section.Type != elf.SHT_NOTE || section.Name != ".note.gnu.build-id" { | ||
continue | ||
} | ||
buf := make([]byte, section.Size) | ||
n, err := section.ReadAt(buf, 0) | ||
if uint64(n) != section.Size || err != nil { | ||
return nil, fmt.Errorf("could not read build id: %w", err) | ||
} | ||
return buf, nil | ||
} | ||
case "darwin": | ||
// Read the LC_UUID load command, which contains the equivalent of a | ||
// build ID. | ||
file, err := macho.NewFile(f) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, load := range file.Loads { | ||
// Unfortunately, the debug/macho package doesn't support the | ||
// LC_UUID command directly. So we have to read it from | ||
// macho.LoadBytes. | ||
load, ok := load.(macho.LoadBytes) | ||
if !ok { | ||
continue | ||
} | ||
raw := load.Raw() | ||
command := binary.LittleEndian.Uint32(raw) | ||
if command != 0x1b { | ||
// Looking for the LC_UUID load command. | ||
// LC_UUID is defined here as 0x1b: | ||
// https://opensource.apple.com/source/xnu/xnu-4570.71.2/EXTERNAL_HEADERS/mach-o/loader.h.auto.html | ||
continue | ||
} | ||
return raw[4:], nil | ||
} | ||
default: | ||
// On other platforms (such as Windows) there isn't such a convenient | ||
// build ID. Luckily, Go does have an equivalent of the build ID, which | ||
// is stored as a special symbol named go.buildid. You can read it | ||
// using `go tool buildid`, but the code below extracts it directly | ||
// from the binary. | ||
// Unfortunately, because of stripping with the -w flag, no symbol | ||
// table might be available. Therefore, we have to scan the binary | ||
// directly. Luckily the build ID is always at the start of the file. | ||
// For details, see: | ||
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go | ||
fileStart := make([]byte, 4096) | ||
_, err := io.ReadFull(f, fileStart) | ||
index := bytes.Index(fileStart, []byte("\xff Go build ID: \"")) | ||
if index < 0 || index > len(fileStart)-103 { | ||
return nil, fmt.Errorf("could not find build id in %s", err) | ||
} | ||
buf := fileStart[index : index+103] | ||
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) { | ||
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil | ||
} | ||
} | ||
return nil, fmt.Errorf("could not find build ID in %s", executable) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters